LCOV - code coverage report
Current view: top level - src/mesh - mesh_function.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 251 331 75.8 %
Date: 2025-08-19 19:27:09 Functions: 37 51 72.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : // Local Includes
      21             : #include "libmesh/mesh_function.h"
      22             : #include "libmesh/dense_vector.h"
      23             : #include "libmesh/equation_systems.h"
      24             : #include "libmesh/numeric_vector.h"
      25             : #include "libmesh/dof_map.h"
      26             : #include "libmesh/point_locator_tree.h"
      27             : #include "libmesh/fe_base.h"
      28             : #include "libmesh/fe_interface.h"
      29             : #include "libmesh/fe_compute_data.h"
      30             : #include "libmesh/mesh_base.h"
      31             : #include "libmesh/point.h"
      32             : #include "libmesh/elem.h"
      33             : #include "libmesh/int_range.h"
      34             : #include "libmesh/fe_map.h"
      35             : 
      36             : namespace libMesh
      37             : {
      38             : 
      39             : 
      40             : //------------------------------------------------------------------
      41             : // MeshFunction methods
      42         564 : MeshFunction::MeshFunction (const EquationSystems & eqn_systems,
      43             :                             const NumericVector<Number> & vec,
      44             :                             const DofMap & dof_map,
      45             :                             std::vector<unsigned int> vars,
      46         564 :                             const FunctionBase<Number> * master) :
      47             :   FunctionBase<Number> (master),
      48             :   ParallelObject       (eqn_systems),
      49         532 :   _eqn_systems         (eqn_systems),
      50         532 :   _vector              (vec),
      51         532 :   _dof_map             (dof_map),
      52          16 :   _system_vars         (std::move(vars)),
      53         580 :   _out_of_mesh_mode    (false)
      54             : {
      55         564 : }
      56             : 
      57             : 
      58             : 
      59         213 : MeshFunction::MeshFunction (const EquationSystems & eqn_systems,
      60             :                             const NumericVector<Number> & vec,
      61             :                             const DofMap & dof_map,
      62             :                             const unsigned int var,
      63         213 :                             const FunctionBase<Number> * master) :
      64             :   FunctionBase<Number> (master),
      65             :   ParallelObject       (eqn_systems),
      66         201 :   _eqn_systems         (eqn_systems),
      67         201 :   _vector              (vec),
      68         201 :   _dof_map             (dof_map),
      69         402 :   _system_vars         (1,var),
      70         213 :   _out_of_mesh_mode    (false)
      71             : {
      72         213 : }
      73             : 
      74         598 : MeshFunction::MeshFunction (const MeshFunction & mf):
      75         598 :   FunctionBase<Number> (mf._master),
      76         598 :   ParallelObject       (mf._eqn_systems),
      77         572 :   _eqn_systems         (mf._eqn_systems),
      78         598 :   _vector              (mf._vector),
      79         598 :   _dof_map             (mf._dof_map),
      80         598 :   _system_vars         (mf._system_vars),
      81         598 :   _out_of_mesh_mode    (mf._out_of_mesh_mode)
      82             : {
      83             :   // Initialize the mf and set the point locator if the
      84             :   // input mf had done so.
      85         598 :   if(mf.initialized())
      86             :   {
      87         527 :     this->MeshFunction::init();
      88             : 
      89         527 :     if(mf.get_point_locator().initialized())
      90         527 :       this->set_point_locator_tolerance(mf.get_point_locator().get_close_to_point_tol());
      91             : 
      92             :   }
      93             : 
      94         598 :   if (mf._subdomain_ids)
      95             :     _subdomain_ids =
      96             :       std::make_unique<std::set<subdomain_id_type>>
      97           0 :         (*mf._subdomain_ids);
      98         598 : }
      99             : 
     100        1959 : MeshFunction::~MeshFunction () = default;
     101             : 
     102             : 
     103             : 
     104        1304 : void MeshFunction::init ()
     105             : {
     106             :   // are indices of the desired variable(s) provided?
     107          46 :   libmesh_assert_greater (this->_system_vars.size(), 0);
     108             : 
     109             :   // Don't do twice...
     110        1304 :   if (this->_initialized)
     111             :     {
     112           0 :       libmesh_assert(_point_locator);
     113           0 :       return;
     114             :     }
     115             : 
     116             :   // The Mesh owns the "master" PointLocator, while handing us a
     117             :   // PointLocator "proxy" that forwards all requests to the master.
     118        1304 :   const MeshBase & mesh = this->_eqn_systems.get_mesh();
     119        2516 :   _point_locator = mesh.sub_point_locator();
     120             : 
     121             :   // ready for use
     122        1304 :   this->_initialized = true;
     123             : }
     124             : 
     125             : 
     126             : 
     127             : #ifdef LIBMESH_ENABLE_DEPRECATED
     128           0 : void MeshFunction::init (const Trees::BuildType /*point_locator_build_type*/)
     129             : {
     130             :   libmesh_deprecated();
     131             : 
     132             :   // Call the init() taking no args instead. Note: this is backwards
     133             :   // compatible because the argument was not used for anything
     134             :   // previously anyway.
     135           0 :   this->init();
     136           0 : }
     137             : #endif // LIBMESH_ENABLE_DEPRECATED
     138             : 
     139             : 
     140             : 
     141             : void
     142           0 : MeshFunction::clear ()
     143             : {
     144             :   // only delete the point locator when we are the master
     145           0 :   if (_point_locator && !_master)
     146           0 :     _point_locator.reset();
     147             : 
     148           0 :   this->_initialized = false;
     149           0 : }
     150             : 
     151             : 
     152             : 
     153         598 : std::unique_ptr<FunctionBase<Number>> MeshFunction::clone () const
     154             : {
     155         598 :   return std::make_unique<MeshFunction>(*this);
     156             : }
     157             : 
     158             : 
     159             : 
     160           0 : Number MeshFunction::operator() (const Point & p,
     161             :                                  const Real time)
     162             : {
     163           0 :   libmesh_assert (this->initialized());
     164             : 
     165           0 :   DenseVector<Number> buf (1);
     166           0 :   this->operator() (p, time, buf);
     167           0 :   return buf(0);
     168             : }
     169             : 
     170         213 : std::map<const Elem *, Number> MeshFunction::discontinuous_value (const Point & p,
     171             :                                                                   const Real time)
     172             : {
     173           6 :   libmesh_assert (this->initialized());
     174             : 
     175          12 :   std::map<const Elem *, DenseVector<Number>> buffer;
     176         213 :   this->discontinuous_value (p, time, buffer);
     177           6 :   std::map<const Elem *, Number> return_value;
     178         497 :   for (const auto & [elem, vec] : buffer)
     179         284 :     return_value[elem] = vec(0);
     180             :   // NOTE: If no suitable element is found, then the map return_value is empty. This
     181             :   // puts burden on the user of this function but I don't really see a better way.
     182         219 :   return return_value;
     183             : }
     184             : 
     185           0 : Gradient MeshFunction::gradient (const Point & p,
     186             :                                  const Real time)
     187             : {
     188           0 :   libmesh_assert (this->initialized());
     189             : 
     190           0 :   std::vector<Gradient> buf (1);
     191           0 :   this->gradient(p, time, buf);
     192           0 :   return buf[0];
     193             : }
     194             : 
     195         213 : std::map<const Elem *, Gradient> MeshFunction::discontinuous_gradient (const Point & p,
     196             :                                                                        const Real time)
     197             : {
     198           6 :   libmesh_assert (this->initialized());
     199             : 
     200          12 :   std::map<const Elem *, std::vector<Gradient>> buffer;
     201         213 :   this->discontinuous_gradient (p, time, buffer);
     202           6 :   std::map<const Elem *, Gradient> return_value;
     203         497 :   for (const auto & [elem, vec] : buffer)
     204         284 :     return_value[elem] = vec[0];
     205             :   // NOTE: If no suitable element is found, then the map return_value is empty. This
     206             :   // puts burden on the user of this function but I don't really see a better way.
     207         219 :   return return_value;
     208             : }
     209             : 
     210             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     211           0 : Tensor MeshFunction::hessian (const Point & p,
     212             :                               const Real time)
     213             : {
     214           0 :   libmesh_assert (this->initialized());
     215             : 
     216           0 :   std::vector<Tensor> buf (1);
     217           0 :   this->hessian(p, time, buf);
     218           0 :   return buf[0];
     219             : }
     220             : #endif
     221             : 
     222      243382 : void MeshFunction::operator() (const Point & p,
     223             :                                const Real time,
     224             :                                DenseVector<Number> & output)
     225             : {
     226      243382 :   this->operator() (p, time, output, this->_subdomain_ids.get());
     227      243382 : }
     228             : 
     229     1374254 : void MeshFunction::operator() (const Point & p,
     230             :                                const Real,
     231             :                                DenseVector<Number> & output,
     232             :                                const std::set<subdomain_id_type> * subdomain_ids)
     233             : {
     234      113417 :   libmesh_assert (this->initialized());
     235             : 
     236     1374254 :   const Elem * element = this->find_element(p,subdomain_ids);
     237             : 
     238     1374254 :   if (!element)
     239             :     {
     240             :       // We'd better be in out_of_mesh_mode if we couldn't find an
     241             :       // element in the mesh
     242          80 :       libmesh_assert (_out_of_mesh_mode);
     243          80 :       output = _out_of_mesh_value;
     244             :     }
     245             :   else
     246             :     {
     247             :       {
     248     1373294 :         const unsigned int dim = element->dim();
     249             : 
     250             : 
     251             :         // Get local coordinates to feed these into compute_data().
     252             :         // Note that the fe_type can safely be used from the 0-variable,
     253             :         // since the inverse mapping is the same for all FEFamilies
     254     1146620 :         const Point mapped_point (FEMap::inverse_map (dim, element,
     255      226674 :                                                       p));
     256             : 
     257             :         // resize the output vector to the number of output values
     258             :         // that the user told us, this include multiple entries for
     259             :         // the spatial components of vector variable
     260      113337 :         unsigned int output_size = 0;
     261     2746868 :         for (auto index : index_range(this->_system_vars))
     262             :           {
     263     1373574 :             const unsigned int var = _system_vars[index];
     264             : 
     265     1373574 :             if (var == libMesh::invalid_uint)
     266             :               {
     267           0 :                 libmesh_assert (_out_of_mesh_mode &&
     268             :                                 index < _out_of_mesh_value.size());
     269           0 :                 output(index) = _out_of_mesh_value(index);
     270           0 :                 continue;
     271             :               }
     272             : 
     273     1373574 :             const FEType & fe_type = this->_dof_map.variable_type(var);
     274             : 
     275             :             // Adding entries for each scalar variable and spatial components of
     276             :             // vector variables
     277     1373574 :             switch (fe_type.family)
     278             :               {
     279         280 :               case HIERARCHIC_VEC:
     280             :               case L2_HIERARCHIC_VEC:
     281             :               case LAGRANGE_VEC:
     282             :               case L2_LAGRANGE_VEC:
     283             :               case MONOMIAL_VEC:
     284             :               case NEDELEC_ONE:
     285             :               case RAVIART_THOMAS:
     286             :               case L2_RAVIART_THOMAS:
     287             :                 {
     288         280 :                   output_size = output_size + dim;
     289         280 :                   break;
     290             :                 }
     291     1373294 :               default:
     292             :                 {
     293     1373294 :                   output_size++;
     294     1373294 :                   break;
     295             :                 }
     296             :               }
     297             : 
     298             :           }
     299     1259957 :         output.resize(output_size);
     300             : 
     301             :         // Adding a counter to keep the output indexing correct for mix scalar-vector output sets
     302      113337 :         unsigned int vec_count = 0;
     303             : 
     304             :         // loop over all vars
     305     2746868 :         for (auto index : index_range(this->_system_vars))
     306             :           {
     307             :             // the data for this variable
     308     1373574 :             const unsigned int var = _system_vars[index];
     309             : 
     310     1373574 :             if (var == libMesh::invalid_uint)
     311             :               {
     312           0 :                 libmesh_assert (_out_of_mesh_mode &&
     313             :                                 index < _out_of_mesh_value.size());
     314           0 :                 output(index) = _out_of_mesh_value(index);
     315           0 :                 continue;
     316             :               }
     317             : 
     318     1373574 :             const FEType & fe_type = this->_dof_map.variable_type(var);
     319             : 
     320             :             // The method between vector and scalar variable are different:
     321             :             // For scalar variables, we use the previous established method of using FEInterface::compute_data
     322             :             // For vector variables, we call the phi() data directly to build the variable solution
     323     1373574 :             switch (fe_type.family)
     324             :               {
     325         280 :               case HIERARCHIC_VEC:
     326             :               case L2_HIERARCHIC_VEC:
     327             :               case LAGRANGE_VEC:
     328             :               case L2_LAGRANGE_VEC:
     329             :               case MONOMIAL_VEC:
     330             :               case NEDELEC_ONE:
     331             :               case RAVIART_THOMAS:
     332             :               case L2_RAVIART_THOMAS:
     333             :                 {
     334             :                   // Calling the physical mesh point needed for the shape function
     335         296 :                   FEComputeData data (this->_eqn_systems, mapped_point);
     336         280 :                   const Point & pt = data.p;
     337             : 
     338             :                   // where the solution values for the var-th variable are stored
     339          16 :                   std::vector<dof_id_type> dof_indices;
     340         280 :                   this->_dof_map.dof_indices (element, dof_indices, var);
     341             : 
     342             :                   // Calling the properly-transformed shape function using get_phi()
     343         288 :                   std::unique_ptr<FEVectorBase> vec_fe = FEVectorBase::build(dim, fe_type);
     344         288 :                   std::vector<Point> vec_pt = {pt};
     345           8 :                   const std::vector<std::vector<RealGradient>> & vec_phi = vec_fe->get_phi();
     346         280 :                   vec_fe->reinit(element, &vec_pt);
     347             : 
     348             :                   // interpolate the solution
     349             :                   {
     350         840 :                     for (unsigned int d = 0; d < dim; d++)
     351             :                     {
     352          16 :                       Number value = 0.;
     353             : 
     354        3360 :                       for (auto i : index_range(dof_indices))
     355        2880 :                         value += this->_vector(dof_indices[i]) * (vec_phi[i][0](d));
     356             : 
     357         576 :                       output(index+vec_count*(dim-1)+d) = value;
     358             :                     }
     359             :                   }
     360             : 
     361         280 :                   vec_count++;
     362           8 :                   break;
     363         528 :                 }
     364     1373294 :               default:
     365             :                 {
     366             :                   // Build an FEComputeData that contains both input and output data
     367             :                   // for the specific compute_data method.
     368             : 
     369     1599968 :                   FEComputeData data (this->_eqn_systems, mapped_point);
     370             : 
     371     1373294 :                   FEInterface::compute_data (dim, fe_type, element, data);
     372             : 
     373             :                   // where the solution values for the var-th variable are stored
     374      226674 :                   std::vector<dof_id_type> dof_indices;
     375     1373294 :                   this->_dof_map.dof_indices (element, dof_indices, var);
     376             : 
     377             :                   // interpolate the solution
     378             :                   {
     379      113337 :                     Number value = 0.;
     380             : 
     381    15257006 :                     for (auto i : index_range(dof_indices))
     382    15018896 :                       value += this->_vector(dof_indices[i]) * data.shape[i];
     383             : 
     384     1486631 :                     output(index+vec_count*(dim-1)) = value;
     385             :                   }
     386      113337 :                   break;
     387     1146620 :                 }
     388             :               }
     389             : 
     390             :             // next variable
     391             :           }
     392             :       }
     393             :     }
     394     1374254 : }
     395             : 
     396         213 : void MeshFunction::discontinuous_value (const Point & p,
     397             :                                         const Real time,
     398             :                                         std::map<const Elem *, DenseVector<Number>> & output)
     399             : {
     400         213 :   this->discontinuous_value (p, time, output, this->_subdomain_ids.get());
     401         213 : }
     402             : 
     403             : 
     404             : 
     405         213 : void MeshFunction::discontinuous_value (const Point & p,
     406             :                                         const Real,
     407             :                                         std::map<const Elem *, DenseVector<Number>> & output,
     408             :                                         const std::set<subdomain_id_type> * subdomain_ids)
     409             : {
     410           6 :   libmesh_assert (this->initialized());
     411             : 
     412             :   // clear the output map
     413           6 :   output.clear();
     414             : 
     415             :   // get the candidate elements
     416         219 :   std::set<const Elem *> candidate_element = this->find_elements(p,subdomain_ids);
     417             : 
     418             :   // loop through all candidates, if the set is empty this function will return an
     419             :   // empty map
     420         497 :   for (const auto & element : candidate_element)
     421             :     {
     422         284 :       const unsigned int dim = element->dim();
     423             : 
     424             :       // define a temporary vector to store all values
     425         292 :       DenseVector<Number> temp_output (cast_int<unsigned int>(this->_system_vars.size()));
     426             : 
     427             :       // Get local coordinates to feed these into compute_data().
     428             :       // Note that the fe_type can safely be used from the 0-variable,
     429             :       // since the inverse mapping is the same for all FEFamilies
     430         284 :       const Point mapped_point (FEMap::inverse_map (dim, element, p));
     431             : 
     432             :       // loop over all vars
     433         568 :       for (auto index : index_range(this->_system_vars))
     434             :         {
     435             :           // the data for this variable
     436         284 :           const unsigned int var = _system_vars[index];
     437             : 
     438         284 :           if (var == libMesh::invalid_uint)
     439             :             {
     440           0 :               libmesh_assert (_out_of_mesh_mode &&
     441             :                               index < _out_of_mesh_value.size());
     442           0 :               temp_output(index) = _out_of_mesh_value(index);
     443           0 :               continue;
     444             :             }
     445             : 
     446         284 :           const FEType & fe_type = this->_dof_map.variable_type(var);
     447             : 
     448             :           // Build an FEComputeData that contains both input and output data
     449             :           // for the specific compute_data method.
     450             :           {
     451         300 :             FEComputeData data (this->_eqn_systems, mapped_point);
     452             : 
     453         284 :             FEInterface::compute_data (dim, fe_type, element, data);
     454             : 
     455             :             // where the solution values for the var-th variable are stored
     456           8 :             std::vector<dof_id_type> dof_indices;
     457         284 :             this->_dof_map.dof_indices (element, dof_indices, var);
     458             : 
     459             :             // interpolate the solution
     460             :             {
     461           8 :               Number value = 0.;
     462             : 
     463         568 :               for (auto i : index_range(dof_indices))
     464         292 :                 value += this->_vector(dof_indices[i]) * data.shape[i];
     465             : 
     466         284 :               temp_output(index) = value;
     467             :             }
     468             : 
     469         268 :           }
     470             : 
     471             :           // next variable
     472             :         }
     473             : 
     474             :       // Insert temp_output into output
     475         284 :       output[element] = temp_output;
     476             :     }
     477         213 : }
     478             : 
     479             : 
     480             : 
     481           0 : void MeshFunction::gradient (const Point & p,
     482             :                              const Real time,
     483             :                              std::vector<Gradient> & output)
     484             : {
     485           0 :   this->gradient(p, time, output, this->_subdomain_ids.get());
     486           0 : }
     487             : 
     488             : 
     489             : 
     490     1127520 : void MeshFunction::gradient (const Point & p,
     491             :                              const Real,
     492             :                              std::vector<Gradient> & output,
     493             :                              const std::set<subdomain_id_type> * subdomain_ids)
     494             : {
     495       93960 :   libmesh_assert (this->initialized());
     496             : 
     497     1127520 :   const Elem * element = this->find_element(p,subdomain_ids);
     498             : 
     499     1127520 :   if (!element)
     500           0 :     output.resize(0);
     501             :   else
     502     1127520 :     this->_gradient_on_elem(p, element, output);
     503     1127520 : }
     504             : 
     505             : 
     506         213 : void MeshFunction::discontinuous_gradient (const Point & p,
     507             :                                            const Real time,
     508             :                                            std::map<const Elem *, std::vector<Gradient>> & output)
     509             : {
     510         213 :   this->discontinuous_gradient (p, time, output, this->_subdomain_ids.get());
     511         213 : }
     512             : 
     513             : 
     514             : 
     515         213 : void MeshFunction::discontinuous_gradient (const Point & p,
     516             :                                            const Real,
     517             :                                            std::map<const Elem *, std::vector<Gradient>> & output,
     518             :                                            const std::set<subdomain_id_type> * subdomain_ids)
     519             : {
     520           6 :   libmesh_assert (this->initialized());
     521             : 
     522             :   // clear the output map
     523           6 :   output.clear();
     524             : 
     525             :   // get the candidate elements
     526         219 :   std::set<const Elem *> candidate_element = this->find_elements(p,subdomain_ids);
     527             : 
     528             :   // loop through all candidates, if the set is empty this function will return an
     529             :   // empty map
     530         497 :   for (const auto & element : candidate_element)
     531             :     {
     532             :       // define a temporary vector to store all values
     533         300 :       std::vector<Gradient> temp_output (cast_int<unsigned int>(this->_system_vars.size()));
     534             : 
     535         284 :       this->_gradient_on_elem(p, element, temp_output);
     536             : 
     537             :       // Insert temp_output into output
     538         276 :       output.emplace(element, std::move(temp_output));
     539             :     }
     540         213 : }
     541             : 
     542             : 
     543             : 
     544     1127804 : void MeshFunction::_gradient_on_elem (const Point & p,
     545             :                                       const Elem * element,
     546             :                                       std::vector<Gradient> & output)
     547             : {
     548       93968 :   libmesh_assert(element);
     549             : 
     550             :   // resize the output vector to the number of output values
     551             :   // that the user told us
     552     1221772 :   output.resize (this->_system_vars.size());
     553             : 
     554     1127804 :   const unsigned int dim = element->dim();
     555             : 
     556             :   // Get local coordinates to feed these into compute_data().
     557             :   // Note that the fe_type can safely be used from the 0-variable,
     558             :   // since the inverse mapping is the same for all FEFamilies
     559      939868 :   const Point mapped_point (FEMap::inverse_map (dim, element,
     560      187936 :                                                 p));
     561             : 
     562     1221772 :   std::vector<Point> point_list (1, mapped_point);
     563             : 
     564             :   // loop over all vars
     565     2255608 :   for (auto index : index_range(this->_system_vars))
     566             :     {
     567             :       // the data for this variable
     568     1127804 :       const unsigned int var = _system_vars[index];
     569             : 
     570     1127804 :       if (var == libMesh::invalid_uint)
     571             :         {
     572           0 :           libmesh_assert (_out_of_mesh_mode &&
     573             :                           index < _out_of_mesh_value.size());
     574           0 :           output[index] = Gradient(_out_of_mesh_value(index));
     575           0 :           continue;
     576             :         }
     577             : 
     578     1127804 :       const FEType & fe_type = this->_dof_map.variable_type(var);
     579             : 
     580             :       // where the solution values for the var-th variable are stored
     581       93968 :       std::vector<dof_id_type> dof_indices;
     582     1127804 :       this->_dof_map.dof_indices (element, dof_indices, var);
     583             : 
     584             :       // interpolate the solution
     585       93968 :       Gradient grad(0.);
     586             : 
     587             :       // for performance-reasons, we use different algorithms now.
     588             :       // TODO: Check that both give the same result for finite elements.
     589             :       // Otherwive it is wrong...
     590      281900 :       if (!element->infinite())
     591             :         {
     592     1221772 :           std::unique_ptr<FEBase> point_fe (FEBase::build(dim, fe_type));
     593       93968 :           const std::vector<std::vector<RealGradient>> & dphi = point_fe->get_dphi();
     594     1127804 :           point_fe->reinit(element, &point_list);
     595             : 
     596    10149100 :           for (auto i : index_range(dof_indices))
     597     9773008 :             grad.add_scaled(dphi[i][0], this->_vector(dof_indices[i]));
     598             : 
     599      939868 :         }
     600             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     601             :       else
     602             :         {
     603             :           // Build an FEComputeData that contains both input and output data
     604             :           // for the specific compute_data method.
     605             :           //
     606             :           // TODO: enable this for a vector of points as well...
     607           0 :           FEComputeData data (this->_eqn_systems, mapped_point);
     608           0 :           data.enable_derivative();
     609           0 :           FEInterface::compute_data (dim, fe_type, element, data);
     610             : 
     611             :           // grad [x] = data.dshape[i](v) * dv/dx  * dof_index [i]
     612             :           // sum over all indices
     613           0 :           for (auto i : index_range(dof_indices))
     614             :             {
     615             :               // local coordinates
     616           0 :               for (std::size_t v=0; v<dim; v++)
     617           0 :                 for (std::size_t xyz=0; xyz<LIBMESH_DIM; xyz++)
     618             :                   {
     619             :                     // FIXME: this needs better syntax: It is matrix-vector multiplication.
     620           0 :                     grad(xyz) += data.local_transform[v][xyz]
     621           0 :                       * data.dshape[i](v)
     622           0 :                       * this->_vector(dof_indices[i]);
     623             :                   }
     624             :             }
     625           0 :         }
     626             : #endif
     627     1221772 :       output[index] = grad;
     628             :     }
     629     1127804 : }
     630             : 
     631             : 
     632             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     633           0 : void MeshFunction::hessian (const Point & p,
     634             :                             const Real time,
     635             :                             std::vector<Tensor> & output)
     636             : {
     637           0 :   this->hessian(p, time, output, this->_subdomain_ids.get());
     638           0 : }
     639             : 
     640             : 
     641             : 
     642     1127520 : void MeshFunction::hessian (const Point & p,
     643             :                             const Real,
     644             :                             std::vector<Tensor> & output,
     645             :                             const std::set<subdomain_id_type> * subdomain_ids)
     646             : {
     647       93960 :   libmesh_assert (this->initialized());
     648             : 
     649     1127520 :   const Elem * element = this->find_element(p,subdomain_ids);
     650             : 
     651     1127520 :   if (!element)
     652             :     {
     653           0 :       output.resize(0);
     654             :     }
     655             :   else
     656             :     {
     657      281880 :       if(element->infinite())
     658             :         libmesh_warning("Warning: Requested the Hessian of an Infinite element."
     659             :                         << "Second derivatives for Infinite elements"
     660             :                         << " are not yet implemented!"
     661             :                         << std::endl);
     662             : 
     663             :       // resize the output vector to the number of output values
     664             :       // that the user told us
     665     1221480 :       output.resize (this->_system_vars.size());
     666             : 
     667             : 
     668             :       {
     669     1127520 :         const unsigned int dim = element->dim();
     670             : 
     671             : 
     672             :         // Get local coordinates to feed these into compute_data().
     673             :         // Note that the fe_type can safely be used from the 0-variable,
     674             :         // since the inverse mapping is the same for all FEFamilies
     675      939600 :         const Point mapped_point (FEMap::inverse_map (dim, element,
     676      187920 :                                                       p));
     677             : 
     678     1221480 :         std::vector<Point> point_list (1, mapped_point);
     679             : 
     680             :         // loop over all vars
     681     2255040 :         for (auto index : index_range(this->_system_vars))
     682             :           {
     683             :             // the data for this variable
     684     1127520 :             const unsigned int var = _system_vars[index];
     685             : 
     686     1127520 :             if (var == libMesh::invalid_uint)
     687             :               {
     688           0 :                 libmesh_assert (_out_of_mesh_mode &&
     689             :                                 index < _out_of_mesh_value.size());
     690           0 :                 output[index] = Tensor(_out_of_mesh_value(index));
     691           0 :                 continue;
     692             :               }
     693     1127520 :             const FEType & fe_type = this->_dof_map.variable_type(var);
     694             : 
     695     1221480 :             std::unique_ptr<FEBase> point_fe (FEBase::build(dim, fe_type));
     696             :             const std::vector<std::vector<RealTensor>> & d2phi =
     697       93960 :               point_fe->get_d2phi();
     698     1127520 :             point_fe->reinit(element, &point_list);
     699             : 
     700             :             // where the solution values for the var-th variable are stored
     701      187920 :             std::vector<dof_id_type> dof_indices;
     702     1127520 :             this->_dof_map.dof_indices (element, dof_indices, var);
     703             : 
     704             :             // interpolate the solution
     705       93960 :             Tensor hess;
     706             : 
     707    10147680 :             for (auto i : index_range(dof_indices))
     708     9771840 :               hess.add_scaled(d2phi[i][0], this->_vector(dof_indices[i]));
     709             : 
     710     1221480 :             output[index] = hess;
     711      939600 :           }
     712             :       }
     713             :     }
     714     1127520 : }
     715             : #endif
     716             : 
     717     3629294 : const Elem * MeshFunction::find_element(const Point & p,
     718             :                                         const std::set<subdomain_id_type> * subdomain_ids) const
     719             : {
     720             :   // Ensure that in the case of a master mesh function, the
     721             :   // out-of-mesh mode is enabled either for both or for none.  This is
     722             :   // important because the out-of-mesh mode is also communicated to
     723             :   // the point locator.  Since this is time consuming, enable it only
     724             :   // in debug mode.
     725             : #ifdef DEBUG
     726      301337 :   if (this->_master != nullptr)
     727             :     {
     728             :       const MeshFunction * master =
     729           0 :         cast_ptr<const MeshFunction *>(this->_master);
     730           0 :       libmesh_error_msg_if(_out_of_mesh_mode!=master->_out_of_mesh_mode,
     731             :                            "ERROR: If you use out-of-mesh-mode in connection with master mesh "
     732             :                            "functions, you must enable out-of-mesh mode for both the master and the slave mesh function.");
     733             :     }
     734             : #endif
     735             : 
     736             :   // locate the point in the other mesh
     737     3629294 :   const Elem * element = (*_point_locator)(p, subdomain_ids);
     738             : 
     739             :   // Make sure that the element found is evaluable
     740     3629294 :   return this->check_found_elem(element, p);
     741             : }
     742             : 
     743         426 : std::set<const Elem *> MeshFunction::find_elements(const Point & p,
     744             :                                                    const std::set<subdomain_id_type> * subdomain_ids) const
     745             : {
     746             :   // Ensure that in the case of a master mesh function, the
     747             :   // out-of-mesh mode is enabled either for both or for none.  This is
     748             :   // important because the out-of-mesh mode is also communicated to
     749             :   // the point locator.  Since this is time consuming, enable it only
     750             :   // in debug mode.
     751             : #ifdef DEBUG
     752          12 :   if (this->_master != nullptr)
     753             :     {
     754             :       const MeshFunction * master =
     755           0 :         cast_ptr<const MeshFunction *>(this->_master);
     756           0 :       libmesh_error_msg_if(_out_of_mesh_mode!=master->_out_of_mesh_mode,
     757             :                            "ERROR: If you use out-of-mesh-mode in connection with master mesh "
     758             :                            "functions, you must enable out-of-mesh mode for both the master and the slave mesh function.");
     759             :     }
     760             : #endif
     761             : 
     762             :   // locate the point in the other mesh
     763          24 :   std::set<const Elem *> candidate_elements;
     764          12 :   std::set<const Elem *> final_candidate_elements;
     765         426 :   (*_point_locator)(p, candidate_elements, subdomain_ids);
     766             : 
     767             :   // For each candidate Elem, if it is evaluable, add it to the set of
     768             :   // final candidate Elems.
     769         994 :   for (const auto & element : candidate_elements)
     770         568 :     final_candidate_elements.insert(this->check_found_elem(element, p));
     771             : 
     772         438 :   return final_candidate_elements;
     773             : }
     774             : 
     775             : const Elem *
     776     3629862 : MeshFunction::check_found_elem(const Elem * element, const Point & p) const
     777             : {
     778             :   // If the PointLocator did not find an Element containing Point p,
     779             :   // OR if the PointLocator found a local element containting Point p,
     780             :   // we can simply return it.
     781     3629862 :   if (!element || (element->processor_id() == this->processor_id()))
     782      292871 :     return element;
     783             : 
     784             :   // Otherwise, the PointLocator returned a valid but non-local
     785             :   // element.  Therefore, we have to do some further checks:
     786             :   //
     787             :   // 1.) If we have a SERIAL _vector, then we can just return the
     788             :   //     non-local element, because all the DOFs are available.
     789     1903020 :   if (_vector.type() == SERIAL)
     790        8358 :     return element;
     791             : 
     792             :   // 2.) If we have a GHOSTED _vector, then we can return a non-local
     793             :   //     Element provided that all of its DOFs are ghosted on this
     794             :   //     processor. That should be faster than the other option, which
     795             :   //     is to search through all the Elem's point_neighbors() for a
     796             :   //     suitable local Elem.
     797        1826 :   if (_vector.type() == GHOSTED && _dof_map.is_evaluable(*element))
     798         111 :     return element;
     799             : 
     800             :   // 3.) If we have a PARALLEL vector, then we search the non-local
     801             :   //     Elem's point neighbors for a local one to return instead. If
     802             :   //     we don't eventually find one, we just return nullptr.
     803          13 :   std::set<const Elem *> point_neighbors;
     804         204 :   element->find_point_neighbors(p, point_neighbors);
     805          13 :   element = nullptr;
     806         686 :   for (const auto & elem : point_neighbors)
     807         723 :     if (elem->processor_id() == this->processor_id())
     808             :       {
     809          13 :         element = elem;
     810          13 :         break;
     811             :       }
     812             : 
     813          13 :   return element;
     814             : }
     815             : 
     816        1054 : const PointLocatorBase & MeshFunction::get_point_locator () const
     817             : {
     818          48 :   libmesh_assert (this->initialized());
     819        1054 :   return *_point_locator;
     820             : }
     821             : 
     822           0 : PointLocatorBase & MeshFunction::get_point_locator ()
     823             : {
     824           0 :   libmesh_assert (this->initialized());
     825           0 :   return *_point_locator;
     826             : }
     827             : 
     828          71 : void MeshFunction::enable_out_of_mesh_mode(const DenseVector<Number> & value)
     829             : {
     830           2 :   libmesh_assert (this->initialized());
     831          71 :   _point_locator->enable_out_of_mesh_mode();
     832          71 :   _out_of_mesh_mode = true;
     833           2 :   _out_of_mesh_value = value;
     834          71 : }
     835             : 
     836           0 : void MeshFunction::enable_out_of_mesh_mode(const Number & value)
     837             : {
     838           0 :   DenseVector<Number> v(1);
     839           0 :   v(0) = value;
     840           0 :   this->enable_out_of_mesh_mode(v);
     841           0 : }
     842             : 
     843           0 : void MeshFunction::disable_out_of_mesh_mode()
     844             : {
     845           0 :   libmesh_assert (this->initialized());
     846           0 :   _point_locator->disable_out_of_mesh_mode();
     847           0 :   _out_of_mesh_mode = false;
     848           0 : }
     849             : 
     850         598 : void MeshFunction::set_point_locator_tolerance(Real tol)
     851             : {
     852         598 :   _point_locator->set_close_to_point_tol(tol);
     853         598 :   _point_locator->set_contains_point_tol(tol);
     854         598 : }
     855             : 
     856           0 : void MeshFunction::unset_point_locator_tolerance()
     857             : {
     858           0 :   _point_locator->unset_close_to_point_tol();
     859           0 : }
     860             : 
     861          71 : void MeshFunction::set_subdomain_ids(const std::set<subdomain_id_type> * subdomain_ids)
     862             : {
     863          71 :   if (subdomain_ids)
     864         140 :     _subdomain_ids = std::make_unique<std::set<subdomain_id_type>>(*subdomain_ids);
     865             :   else
     866           0 :     _subdomain_ids.reset();
     867          71 : }
     868             : 
     869             : } // namespace libMesh

Generated by: LCOV version 1.14