LCOV - code coverage report
Current view: top level - src/mesh - mesh_function.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 271 337 80.4 %
Date: 2026-06-03 20:22:46 Functions: 41 50 82.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14