From f7f423c8adae4465977c63a60058bea553bbbbde Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 16 May 2000 09:01:16 +0000 Subject: [PATCH] Templatize on vector types in many functions, to support block vectors and Vectors better. git-svn-id: https://svn.dealii.org/trunk@2861 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/deal.II/include/dofs/dof_accessor.h | 171 +++++++++++---- deal.II/deal.II/include/fe/fe_values.h | 60 ++++-- deal.II/deal.II/source/dofs/dof_accessor.cc | 195 +++++++++++++----- deal.II/deal.II/source/fe/fe_values.cc | 124 ++++++++++- .../deal.II/source/fe/q1_mapping.jacobians.cc | 4 +- 5 files changed, 437 insertions(+), 117 deletions(-) diff --git a/deal.II/deal.II/include/dofs/dof_accessor.h b/deal.II/deal.II/include/dofs/dof_accessor.h index dc68f03a79..574117bab0 100644 --- a/deal.II/deal.II/include/dofs/dof_accessor.h +++ b/deal.II/deal.II/include/dofs/dof_accessor.h @@ -300,12 +300,23 @@ class DoFObjectAccessor : public DoFAccessor, * The vector has to have the * right size before being passed * to this function. This - * function is only callable for active - * cells. - */ - template - void get_dof_values (const Vector &values, - Vector &local_values) const; + * function is only callable for + * active cells. + * + * The input vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template + void get_dof_values (const InputVector &values, + Vector &local_values) const; /** * This function is the counterpart to @@ -329,10 +340,21 @@ class DoFObjectAccessor : public DoFAccessor, * The vector has to have the * right size before being passed * to this function. - */ - template + * + * The output vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template void set_dof_values (const Vector &local_values, - Vector &values) const; + OutputVector &values) const; /** * Pointer to the #i#th line @@ -531,10 +553,21 @@ class DoFObjectAccessor<1, dim> : public DoFAccessor, * has the right size beforehand. This * function is only callable for active * cells. - */ - template - void get_dof_values (const Vector &values, - Vector &local_values) const; + * + * The input vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template + void get_dof_values (const InputVector &values, + Vector &local_values) const; /** * This function is the counterpart to @@ -557,10 +590,21 @@ class DoFObjectAccessor<1, dim> : public DoFAccessor, * * It is assumed that both vectors already * have the right size beforehand. - */ - template + * + * The output vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template void set_dof_values (const Vector &local_values, - Vector &values) const; + OutputVector &values) const; /** * Return the #i#th child as a DoF line @@ -698,10 +742,21 @@ class DoFObjectAccessor<2, dim> : public DoFAccessor, * has the right size beforehand. This * function is only callable for active * cells. - */ - template - void get_dof_values (const Vector &values, - Vector &local_values) const; + * + * The input vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template + void get_dof_values (const InputVector &values, + Vector &local_values) const; /** * This function is the counterpart to @@ -724,10 +779,21 @@ class DoFObjectAccessor<2, dim> : public DoFAccessor, * * It is assumed that both vectors already * have the right size beforehand. - */ - template + * + * The output vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template void set_dof_values (const Vector &local_values, - Vector &values) const; + OutputVector &values) const; /** * Return a pointer to the #i#th line @@ -873,10 +939,21 @@ class DoFObjectAccessor<3, dim> : public DoFAccessor, * has the right size beforehand. This * function is only callable for active * cells. - */ - template - void get_dof_values (const Vector &values, - Vector &local_values) const; + * + * The input vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template + void get_dof_values (const InputVector &values, + Vector &local_values) const; /** * This function is the counterpart to @@ -899,10 +976,21 @@ class DoFObjectAccessor<3, dim> : public DoFAccessor, * * It is assumed that both vectors already * have the right size beforehand. - */ - template + * + * The output vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template void set_dof_values (const Vector &local_values, - Vector &values) const; + OutputVector &values) const; /** * Return a pointer to the #i#th line @@ -1074,9 +1162,9 @@ class DoFCellAccessor : public DoFObjectAccessor * cells by the finite element * objects. */ - template - void get_interpolated_dof_values (const Vector &values, - Vector &interpolated_values) const; + template + void get_interpolated_dof_values (const InputVector &values, + Vector &interpolated_values) const; /** * This, again, is the counterpart to @@ -1139,10 +1227,21 @@ class DoFCellAccessor : public DoFObjectAccessor * presently only provided for * cells by the finite element * objects. - */ - template + * + * The output vector may be either + * a #Vector#, + * #Vector#, or a + * #BlockVector<...,double>#. It + * is in the responsibility of + * the caller to assure that the + * types of the numbers stored in + * input and output vectors are + * compatible and with similar + * accuracy. + */ + template void set_dof_values_by_interpolation (const Vector &local_values, - Vector &values) const; + OutputVector &values) const; /** * Exception diff --git a/deal.II/deal.II/include/fe/fe_values.h b/deal.II/deal.II/include/fe/fe_values.h index 2b000be90c..b3ec0a389b 100644 --- a/deal.II/deal.II/include/fe/fe_values.h +++ b/deal.II/deal.II/include/fe/fe_values.h @@ -303,20 +303,35 @@ class FEValuesBase * * The function assumes that the * #values# object already has the - * right size. + * right size. + * + * The actual data type of the + * input vector may be either a + * #Vector#, + * #Vector#, or + * #BlockVector#. */ - void get_function_values (const Vector &fe_function, - vector &values) const; + template + void get_function_values (const InputVector &fe_function, + vector &values) const; /** - * Access to vector valued finite element functions. + * Access to vector valued finite + * element functions. * * This function does the same as * the other #get_function_values#, * but applied to multi-component * elements. - */ - void get_function_values (const Vector &fe_function, + * + * The actual data type of the + * input vector may be either a + * #Vector#, + * #Vector#, or + * #BlockVector#. + */ + template + void get_function_values (const InputVector &fe_function, vector > &values) const; /** @@ -357,8 +372,15 @@ class FEValuesBase * The function assumes that the * #gradients# object already has the * right size. - */ - void get_function_grads (const Vector &fe_function, + * + * The actual data type of the + * input vector may be either a + * #Vector#, + * #Vector#, or + * #BlockVector#. + */ + template + void get_function_grads (const InputVector &fe_function, vector > &gradients) const; /** @@ -379,8 +401,15 @@ class FEValuesBase * the other #get_function_values#, * but applied to multi-component * elements. - */ - void get_function_grads (const Vector &fe_function, + * + * The actual data type of the + * input vector may be either a + * #Vector#, + * #Vector#, or + * #BlockVector#. + */ + template + void get_function_grads (const InputVector &fe_function, vector > > &gradients) const; /** @@ -426,8 +455,15 @@ class FEValuesBase * The function assumes that the * #second_derivatives# object already has * the right size. - */ - void get_function_2nd_derivatives (const Vector &fe_function, + * + * The actual data type of the + * input vector may be either a + * #Vector#, + * #Vector#, or + * #BlockVector#. + */ + template + void get_function_2nd_derivatives (const InputVector &fe_function, vector > &second_derivatives) const; /** diff --git a/deal.II/deal.II/source/dofs/dof_accessor.cc b/deal.II/deal.II/source/dofs/dof_accessor.cc index 7989c1cc92..c6c9f088ab 100644 --- a/deal.II/deal.II/source/dofs/dof_accessor.cc +++ b/deal.II/deal.II/source/dofs/dof_accessor.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -117,10 +118,10 @@ distribute_local_to_global (const FullMatrix &local_source, template -template +template void -DoFObjectAccessor<1,dim>::get_dof_values (const Vector &values, - Vector &local_values) const +DoFObjectAccessor<1,dim>::get_dof_values (const InputVector &values, + Vector &local_values) const { Assert (dim==1, ExcInternalError()); @@ -147,10 +148,11 @@ DoFObjectAccessor<1,dim>::get_dof_values (const Vector &values, template -template +template void DoFObjectAccessor<1,dim>::set_dof_values (const Vector &local_values, - Vector &values) const { + OutputVector &values) const +{ Assert (dim==1, ExcInternalError()); Assert (dof_handler != 0, DoFAccessor<1>::ExcInvalidObject()); @@ -269,10 +271,10 @@ distribute_local_to_global (const FullMatrix &local_source, template -template +template void -DoFObjectAccessor<2,dim>::get_dof_values (const Vector &values, - Vector &local_values) const +DoFObjectAccessor<2,dim>::get_dof_values (const InputVector &values, + Vector &local_values) const { Assert (dim==2, ExcInternalError()); @@ -303,10 +305,10 @@ DoFObjectAccessor<2,dim>::get_dof_values (const Vector &values, template -template +template void DoFObjectAccessor<2,dim>::set_dof_values (const Vector &local_values, - Vector &values) const + OutputVector &values) const { Assert (dim==2, ExcInternalError()); @@ -432,10 +434,10 @@ distribute_local_to_global (const FullMatrix &local_source, template -template +template void -DoFObjectAccessor<3,dim>::get_dof_values (const Vector &values, - Vector &local_values) const +DoFObjectAccessor<3,dim>::get_dof_values (const InputVector &values, + Vector &local_values) const { Assert (dim==3, ExcInternalError()); @@ -470,10 +472,10 @@ DoFObjectAccessor<3,dim>::get_dof_values (const Vector &values, template -template +template void DoFObjectAccessor<3,dim>::set_dof_values (const Vector &local_values, - Vector &values) const + OutputVector &values) const { Assert (dim==3, ExcInternalError()); @@ -548,10 +550,10 @@ DoFCellAccessor<3>::face (const unsigned int i) const template -template +template void -DoFCellAccessor::get_interpolated_dof_values (const Vector &values, - Vector &interpolated_values) const +DoFCellAccessor::get_interpolated_dof_values (const InputVector &values, + Vector &interpolated_values) const { const unsigned int dofs_per_cell = dof_handler->get_fe().dofs_per_cell; @@ -610,10 +612,10 @@ DoFCellAccessor::get_interpolated_dof_values (const Vector &values, template -template +template void DoFCellAccessor::set_dof_values_by_interpolation (const Vector &local_values, - Vector &values) const + OutputVector &values) const { const unsigned int dofs_per_cell = dof_handler->get_fe().dofs_per_cell; @@ -645,63 +647,109 @@ DoFCellAccessor::set_dof_values_by_interpolation (const Vector &loc }; + +// -------------------------------------------------------------------------- // explicit instantiations // for double template void -DoFObjectAccessor<1,deal_II_dimension>:: -get_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<1,deal_II_dimension>::get_dof_values (const Vector &, + Vector &) const; template void -DoFObjectAccessor<1,deal_II_dimension>:: -set_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<1,deal_II_dimension>::set_dof_values (const Vector &, + Vector &) const; // for float template void -DoFObjectAccessor<1,deal_II_dimension>:: -get_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<1,deal_II_dimension>::get_dof_values (const Vector &, + Vector &) const; + +template +void +DoFObjectAccessor<1,deal_II_dimension>::set_dof_values (const Vector &, + Vector &) const; + + +// for block vector 2 +template +void +DoFObjectAccessor<1,deal_II_dimension>::get_dof_values (const BlockVector<2,double> &, + Vector &) const; + +template +void +DoFObjectAccessor<1,deal_II_dimension>::set_dof_values (const Vector &, + BlockVector<2,double> &) const; + + +// for block vector 3 +template +void +DoFObjectAccessor<1,deal_II_dimension>::get_dof_values (const BlockVector<3,double> &, + Vector &) const; template void -DoFObjectAccessor<1,deal_II_dimension>:: -set_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<1,deal_II_dimension>::set_dof_values (const Vector &, + BlockVector<3,double> &) const; + + + #if deal_II_dimension >= 2 // for double template void -DoFObjectAccessor<2,deal_II_dimension>:: -get_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<2,deal_II_dimension>::get_dof_values (const Vector &, + Vector &) const; template void -DoFObjectAccessor<2,deal_II_dimension>:: -set_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<2,deal_II_dimension>::set_dof_values (const Vector &, + Vector &) const; // for float template void -DoFObjectAccessor<2,deal_II_dimension>:: -get_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<2,deal_II_dimension>::get_dof_values (const Vector &, + Vector &) const; + +template +void +DoFObjectAccessor<2,deal_II_dimension>::set_dof_values (const Vector &, + Vector &) const; + +// for block vector 2 template void -DoFObjectAccessor<2,deal_II_dimension>:: -set_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<2,deal_II_dimension>::get_dof_values (const BlockVector<2,double> &, + Vector &) const; + +template +void +DoFObjectAccessor<2,deal_II_dimension>::set_dof_values (const Vector &, + BlockVector<2,double> &) const; + + +// for block vector 3 +template +void +DoFObjectAccessor<2,deal_II_dimension>::get_dof_values (const BlockVector<3,double> &, + Vector &) const; + +template +void +DoFObjectAccessor<2,deal_II_dimension>::set_dof_values (const Vector &, + BlockVector<3,double> &) const; + #endif @@ -710,32 +758,54 @@ set_dof_values (const Vector &, // for double template void -DoFObjectAccessor<3,deal_II_dimension>:: -get_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<3,deal_II_dimension>::get_dof_values (const Vector &, + Vector &) const; template void -DoFObjectAccessor<3,deal_II_dimension>:: -set_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<3,deal_II_dimension>::set_dof_values (const Vector &, + Vector &) const; // for float template void -DoFObjectAccessor<3,deal_II_dimension>:: -get_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<3,deal_II_dimension>::get_dof_values (const Vector &, + Vector &) const; + +template +void +DoFObjectAccessor<3,deal_II_dimension>::set_dof_values (const Vector &, + Vector &) const; + + +// for block vector 2 +template +void +DoFObjectAccessor<3,deal_II_dimension>::get_dof_values (const BlockVector<2,double> &, + Vector &) const; +template +void +DoFObjectAccessor<3,deal_II_dimension>::set_dof_values (const Vector &, + BlockVector<2,double> &) const; + + +// for block vector 3 +template +void +DoFObjectAccessor<3,deal_II_dimension>::get_dof_values (const BlockVector<3,double> &, + Vector &) const; template void -DoFObjectAccessor<3,deal_II_dimension>:: -set_dof_values (const Vector &, - Vector &) const; +DoFObjectAccessor<3,deal_II_dimension>::set_dof_values (const Vector &, + BlockVector<3,double> &) const; + + #endif + template void DoFCellAccessor:: @@ -762,6 +832,19 @@ set_dof_values_by_interpolation(const Vector &, Vector &) const; +template +void +DoFCellAccessor:: +get_interpolated_dof_values (const BlockVector<2,double> &, + Vector &) const; + +template +void +DoFCellAccessor:: +set_dof_values_by_interpolation(const Vector &, + BlockVector<3,double> &) const; + + #if deal_II_dimension == 1 template class DoFObjectAccessor<1, 1>; #endif diff --git a/deal.II/deal.II/source/fe/fe_values.cc b/deal.II/deal.II/source/fe/fe_values.cc index b0ff1455be..ee631100d3 100644 --- a/deal.II/deal.II/source/fe/fe_values.cc +++ b/deal.II/deal.II/source/fe/fe_values.cc @@ -20,6 +20,7 @@ #include #include #include +#include /*------------------------------- FEValuesBase ---------------------------*/ @@ -55,9 +56,11 @@ FEValuesBase::FEValuesBase (const unsigned int n_q_points, {}; + template double FEValuesBase::shape_value (const unsigned int i, - const unsigned int j) const { + const unsigned int j) const +{ Assert (update_flags & update_values, ExcAccessToUninitializedField()); Assert (selected_dataset::shape_value (const unsigned int i, }; + template -void FEValuesBase::get_function_values (const Vector &fe_function, - vector &values) const +template +void FEValuesBase::get_function_values (const InputVector &fe_function, + vector &values) const { Assert (fe->n_components() == 1, ExcWrongNoOfComponents()); @@ -101,8 +106,10 @@ void FEValuesBase::get_function_values (const Vector &fe_function, }; + template -void FEValuesBase::get_function_values (const Vector &fe_function, +template +void FEValuesBase::get_function_values (const InputVector &fe_function, vector< Vector > &values) const { Assert (n_quadrature_points == values.size(), @@ -134,6 +141,7 @@ void FEValuesBase::get_function_values (const Vector &fe_functi }; + template const Tensor<1,dim> & FEValuesBase::shape_grad (const unsigned int i, @@ -149,8 +157,10 @@ FEValuesBase::shape_grad (const unsigned int i, }; + template -void FEValuesBase::get_function_grads (const Vector &fe_function, +template +void FEValuesBase::get_function_grads (const InputVector &fe_function, vector > &gradients) const { Assert (fe->n_components() == 1, @@ -180,8 +190,11 @@ void FEValuesBase::get_function_grads (const Vector &fe_function, }; }; + + template -void FEValuesBase::get_function_grads (const Vector &fe_function, +template +void FEValuesBase::get_function_grads (const InputVector &fe_function, vector > > &gradients) const { Assert (n_quadrature_points == gradients.size(), @@ -217,10 +230,12 @@ void FEValuesBase::get_function_grads (const Vector &fe_ }; + template const Tensor<2,dim> & FEValuesBase::shape_2nd_derivative (const unsigned int i, - const unsigned int j) const { + const unsigned int j) const +{ Assert (i::shape_2nd_derivative (const unsigned int i, }; + template -void FEValuesBase::get_function_2nd_derivatives (const Vector &fe_function, +template +void FEValuesBase::get_function_2nd_derivatives (const InputVector &fe_function, vector > &second_derivatives) const { Assert (fe->n_components() == 1, @@ -263,6 +280,7 @@ void FEValuesBase::get_function_2nd_derivatives (const Vector &fe }; + template const Point & FEValuesBase::quadrature_point (const unsigned int i) const @@ -274,6 +292,7 @@ FEValuesBase::quadrature_point (const unsigned int i) const }; + template const Point & FEValuesBase::support_point (const unsigned int i) const @@ -285,6 +304,7 @@ FEValuesBase::support_point (const unsigned int i) const }; + template double FEValuesBase::JxW (const unsigned int i) const { @@ -343,8 +363,10 @@ FEValues::FEValues (const FiniteElement &fe, }; + template -void FEValues::reinit (const typename DoFHandler::cell_iterator &cell) { +void FEValues::reinit (const typename DoFHandler::cell_iterator &cell) +{ present_cell = cell; // fill jacobi matrices and real // quadrature points @@ -458,9 +480,11 @@ FEFaceValuesBase::FEFaceValuesBase (const unsigned int n_q_points, {}; + template const Point & -FEFaceValuesBase::normal_vector (const unsigned int i) const { +FEFaceValuesBase::normal_vector (const unsigned int i) const +{ Assert (i::FEFaceValues (const FiniteElement &fe, template void FEFaceValues::reinit (const typename DoFHandler::cell_iterator &cell, - const unsigned int face_no) { + const unsigned int face_no) +{ present_cell = cell; selected_dataset = face_no; // fill jacobi matrices and real @@ -686,6 +711,7 @@ FESubfaceValues::FESubfaceValues (const FiniteElement &fe, }; + template void FESubfaceValues::reinit (const typename DoFHandler::cell_iterator &cell, const unsigned int face_no, @@ -794,3 +820,79 @@ template class FEFaceValuesBase; template class FEFaceValues; template class FESubfaceValues; #endif + + +//----------------------------------------------------------------------------- + +template +void FEValuesBase::get_function_values (const Vector &, + vector &) const; +template +void FEValuesBase::get_function_values (const Vector &, + vector &) const; +template +void FEValuesBase::get_function_values (const BlockVector<2,double> &, + vector &) const; +template +void FEValuesBase::get_function_values (const BlockVector<3,double> &, + vector &) const; + +//----------------------------------------------------------------------------- + +template +void FEValuesBase::get_function_values (const Vector &, + vector > &) const; +template +void FEValuesBase::get_function_values (const Vector &, + vector > &) const; +template +void FEValuesBase::get_function_values (const BlockVector<2,double> &, + vector > &) const; +template +void FEValuesBase::get_function_values (const BlockVector<3,double> &, + vector > &) const; + +//----------------------------------------------------------------------------- + +template +void FEValuesBase::get_function_grads (const Vector &, + vector > &) const; +template +void FEValuesBase::get_function_grads (const Vector &, + vector > &) const; +template +void FEValuesBase::get_function_grads (const BlockVector<2,double> &, + vector > &) const; +template +void FEValuesBase::get_function_grads (const BlockVector<3,double> &, + vector > &) const; + +//----------------------------------------------------------------------------- + +template +void FEValuesBase::get_function_grads (const Vector &, + vector > > &) const; +template +void FEValuesBase::get_function_grads (const Vector &, + vector > > &) const; +template +void FEValuesBase::get_function_grads (const BlockVector<2,double> &, + vector > > &) const; +template +void FEValuesBase::get_function_grads (const BlockVector<3,double> &, + vector > > &) const; + +//----------------------------------------------------------------------------- + +template +void FEValuesBase::get_function_2nd_derivatives (const Vector &, + vector > &) const; +template +void FEValuesBase::get_function_2nd_derivatives (const Vector &, + vector > &) const; +template +void FEValuesBase::get_function_2nd_derivatives (const BlockVector<2,double> &, + vector > &) const; +template +void FEValuesBase::get_function_2nd_derivatives (const BlockVector<3,double> &, + vector > &) const; diff --git a/deal.II/deal.II/source/fe/q1_mapping.jacobians.cc b/deal.II/deal.II/source/fe/q1_mapping.jacobians.cc index acc9dede48..b2a6ac9d18 100644 --- a/deal.II/deal.II/source/fe/q1_mapping.jacobians.cc +++ b/deal.II/deal.II/source/fe/q1_mapping.jacobians.cc @@ -69,8 +69,8 @@ void FEQ1Mapping<1>::compute_jacobian_gradients (const DoFHandler<1>::cell_itera template <> void FEQ1Mapping<2>::compute_jacobian_matrices (const DoFHandler<2>::cell_iterator &cell, - const vector > &unit_points, - vector > &jacobians) + const vector > &unit_points, + vector > &jacobians) { const unsigned int dim = 2; -- 2.39.5