Loading [MathJax]/jax/output/HTML-CSS/config.js
OGS
HydroMechanicsLocalAssemblerMatrix-impl.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <limits>
14
27
28namespace ProcessLib
29{
30namespace LIE
31{
32namespace HydroMechanics
33{
34namespace MPL = MaterialPropertyLib;
35
36template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
37 int GlobalDim>
38HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
39 ShapeFunctionPressure, GlobalDim>::
40 HydroMechanicsLocalAssemblerMatrix(
41 MeshLib::Element const& e,
42 std::size_t const n_variables,
43 std::size_t const /*local_matrix_size*/,
44 std::vector<unsigned> const& dofIndex_to_localIndex,
45 NumLib::GenericIntegrationMethod const& integration_method,
46 bool const is_axially_symmetric,
49 e, is_axially_symmetric, integration_method,
50 (n_variables - 1) * ShapeFunctionDisplacement::NPOINTS * GlobalDim +
51 ShapeFunctionPressure::NPOINTS,
52 dofIndex_to_localIndex),
53 _process_data(process_data)
54{
55 unsigned const n_integration_points =
56 integration_method.getNumberOfPoints();
57
58 _ip_data.reserve(n_integration_points);
59 _secondary_data.N.resize(n_integration_points);
60
61 auto const shape_matrices_u =
62 NumLib::initShapeMatrices<ShapeFunctionDisplacement,
64 e, is_axially_symmetric, integration_method);
65
66 auto const shape_matrices_p =
67 NumLib::initShapeMatrices<ShapeFunctionPressure,
68 ShapeMatricesTypePressure, GlobalDim>(
69 e, is_axially_symmetric, integration_method);
70
72 _process_data.solid_materials, _process_data.material_ids, e.getID());
73
75 x_position.setElementID(e.getID());
76 for (unsigned ip = 0; ip < n_integration_points; ip++)
77 {
78 _ip_data.emplace_back(solid_material);
79 auto& ip_data = _ip_data[ip];
80 auto const& sm_u = shape_matrices_u[ip];
81 auto const& sm_p = shape_matrices_p[ip];
82
83 ip_data.integration_weight =
84 sm_u.detJ * sm_u.integralMeasure *
85 integration_method.getWeightedPoint(ip).getWeight();
86 ip_data.darcy_velocity.setZero();
87
88 ip_data.N_u = sm_u.N;
89 ip_data.dNdx_u = sm_u.dNdx;
90 ip_data.H_u.setZero(GlobalDim, displacement_size);
91 for (int i = 0; i < GlobalDim; ++i)
92 {
93 ip_data.H_u
94 .template block<1, displacement_size / GlobalDim>(
95 i, i * displacement_size / GlobalDim)
96 .noalias() = ip_data.N_u;
97 }
98
99 ip_data.N_p = sm_p.N;
100 ip_data.dNdx_p = sm_p.dNdx;
101
102 _secondary_data.N[ip] = sm_u.N;
103
104 ip_data.sigma_eff.setZero(kelvin_vector_size);
105 ip_data.eps.setZero(kelvin_vector_size);
106
107 ip_data.sigma_eff_prev.resize(kelvin_vector_size);
108 ip_data.eps_prev.resize(kelvin_vector_size);
109 ip_data.C.resize(kelvin_vector_size, kelvin_vector_size);
110
111 auto const initial_effective_stress =
112 _process_data.initial_effective_stress(0, x_position);
113 for (unsigned i = 0; i < kelvin_vector_size; i++)
114 {
115 ip_data.sigma_eff[i] = initial_effective_stress[i];
116 ip_data.sigma_eff_prev[i] = initial_effective_stress[i];
117 }
118 }
119}
120
121template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
122 int GlobalDim>
123void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
124 ShapeFunctionPressure, GlobalDim>::
125 assembleWithJacobianConcrete(double const t, double const dt,
126 Eigen::VectorXd const& local_x,
127 Eigen::VectorXd const& local_x_prev,
128 Eigen::VectorXd& local_rhs,
129 Eigen::MatrixXd& local_Jac)
130{
131 auto p = const_cast<Eigen::VectorXd&>(local_x).segment(pressure_index,
132 pressure_size);
133 auto const p_prev = local_x_prev.segment(pressure_index, pressure_size);
134
135 if (_process_data.deactivate_matrix_in_flow)
136 {
137 setPressureOfInactiveNodes(t, p);
138 }
139
140 auto u = local_x.segment(displacement_index, displacement_size);
141 auto u_prev = local_x_prev.segment(displacement_index, displacement_size);
142
143 auto rhs_p = local_rhs.template segment<pressure_size>(pressure_index);
144 auto rhs_u =
145 local_rhs.template segment<displacement_size>(displacement_index);
146
147 auto J_pp = local_Jac.template block<pressure_size, pressure_size>(
148 pressure_index, pressure_index);
149 auto J_pu = local_Jac.template block<pressure_size, displacement_size>(
150 pressure_index, displacement_index);
151 auto J_uu = local_Jac.template block<displacement_size, displacement_size>(
152 displacement_index, displacement_index);
153 auto J_up = local_Jac.template block<displacement_size, pressure_size>(
154 displacement_index, pressure_index);
155
156 assembleBlockMatricesWithJacobian(t, dt, p, p_prev, u, u_prev, rhs_p, rhs_u,
157 J_pp, J_pu, J_uu, J_up);
158}
159
160template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
161 int GlobalDim>
162void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
163 ShapeFunctionPressure, GlobalDim>::
164 assembleBlockMatricesWithJacobian(
165 double const t, double const dt,
166 Eigen::Ref<const Eigen::VectorXd> const& p,
167 Eigen::Ref<const Eigen::VectorXd> const& p_prev,
168 Eigen::Ref<const Eigen::VectorXd> const& u,
169 Eigen::Ref<const Eigen::VectorXd> const& u_prev,
170 Eigen::Ref<Eigen::VectorXd> rhs_p, Eigen::Ref<Eigen::VectorXd> rhs_u,
171 Eigen::Ref<Eigen::MatrixXd> J_pp, Eigen::Ref<Eigen::MatrixXd> J_pu,
172 Eigen::Ref<Eigen::MatrixXd> J_uu, Eigen::Ref<Eigen::MatrixXd> J_up)
173{
174 assert(this->_element.getDimension() == GlobalDim);
175
177 ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size,
178 pressure_size);
179
181 ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size,
182 pressure_size);
183
184 typename ShapeMatricesTypeDisplacement::template MatrixType<
185 displacement_size, pressure_size>
186 Kup = ShapeMatricesTypeDisplacement::template MatrixType<
187 displacement_size, pressure_size>::Zero(displacement_size,
188 pressure_size);
189
190 auto const& gravity_vec = _process_data.specific_body_force;
191
192 MPL::VariableArray variables;
193 MPL::VariableArray variables_prev;
195 x_position.setElementID(_element.getID());
196
197 auto const& medium = _process_data.media_map.getMedium(_element.getID());
198 auto const& liquid_phase = medium->phase("AqueousLiquid");
199 auto const& solid_phase = medium->phase("Solid");
200
201 auto const T_ref =
202 medium->property(MPL::PropertyType::reference_temperature)
203 .template value<double>(variables, x_position, t, dt);
204 variables.temperature = T_ref;
205 variables_prev.temperature = T_ref;
206
207 bool const has_storage_property =
208 medium->hasProperty(MPL::PropertyType::storage);
209
210 auto const B_dil_bar = getDilatationalBBarMatrix();
211
212 unsigned const n_integration_points = _ip_data.size();
213 for (unsigned ip = 0; ip < n_integration_points; ip++)
214 {
215 auto& ip_data = _ip_data[ip];
216 auto const& ip_w = ip_data.integration_weight;
217 auto const& N_u = ip_data.N_u;
218 auto const& dNdx_u = ip_data.dNdx_u;
219 auto const& N_p = ip_data.N_p;
220 auto const& dNdx_p = ip_data.dNdx_p;
221 auto const& H_u = ip_data.H_u;
222
223 variables.liquid_phase_pressure = N_p.dot(p);
224
225 x_position = {
226 std::nullopt, _element.getID(),
228 NumLib::interpolateCoordinates<ShapeFunctionDisplacement,
230 _element, N_u))};
231
232 auto const x_coord = x_position.getCoordinates().value()[0];
233
234 auto const B =
236 GlobalDim, ShapeFunctionDisplacement::NPOINTS, BBarMatrixType,
238 dNdx_u, N_u, B_dil_bar, x_coord, this->_is_axially_symmetric)
239 .eval();
240
241 auto const& eps_prev = ip_data.eps_prev;
242 auto const& sigma_eff_prev = ip_data.sigma_eff_prev;
243 auto& sigma_eff = ip_data.sigma_eff;
244
245 auto& eps = ip_data.eps;
246 auto& state = ip_data.material_state_variables;
247
248 auto const rho_sr =
249 solid_phase.property(MPL::PropertyType::density)
250 .template value<double>(variables, x_position, t, dt);
251 auto const rho_fr =
252 liquid_phase.property(MPL::PropertyType::density)
253 .template value<double>(variables, x_position, t, dt);
254
255 auto const alpha =
256 medium->property(MPL::PropertyType::biot_coefficient)
257 .template value<double>(variables, x_position, t, dt);
258 auto const porosity =
259 medium->property(MPL::PropertyType::porosity)
260 .template value<double>(variables, x_position, t, dt);
261
262 double const rho = rho_sr * (1 - porosity) + porosity * rho_fr;
263 auto const& identity2 =
265
266 eps.noalias() = B * u;
267
268 variables.mechanical_strain
270
271 variables_prev.stress
273 sigma_eff_prev);
274 variables_prev.mechanical_strain
276 eps_prev);
277 variables_prev.temperature = T_ref;
278
279 auto&& solution = _ip_data[ip].solid_material.integrateStress(
280 variables_prev, variables, t, x_position, dt, *state);
281
282 if (!solution)
283 {
284 OGS_FATAL("Computation of local constitutive relation failed.");
285 }
286
288 std::tie(sigma_eff, state, C) = std::move(*solution);
289
290 J_uu.noalias() += B.transpose() * C * B * ip_w;
291
292 rhs_u.noalias() -= B.transpose() * sigma_eff * ip_w;
293 rhs_u.noalias() -= -H_u.transpose() * rho * gravity_vec * ip_w;
294
295 //
296 // pressure equation, pressure part and displacement equation, pressure
297 // part
298 //
299 if (!_process_data.deactivate_matrix_in_flow) // Only for hydraulically
300 // active matrix
301 {
302 Kup.noalias() += B.transpose() * alpha * identity2 * N_p * ip_w;
303
304 variables.density = rho_fr;
305 auto const mu =
306 liquid_phase.property(MPL::PropertyType::viscosity)
307 .template value<double>(variables, x_position, t, dt);
308
309 auto const k_over_mu =
311 medium->property(MPL::PropertyType::permeability)
312 .value(variables, x_position, t, dt)) /
313 mu)
314 .eval();
315
316 double const S =
317 has_storage_property
318 ? medium->property(MPL::PropertyType::storage)
319 .template value<double>(variables, x_position, t, dt)
320 : porosity *
321 (liquid_phase.property(MPL::PropertyType::density)
322 .template dValue<double>(
323 variables,
324 MPL::Variable::liquid_phase_pressure,
325 x_position, t, dt) /
326 rho_fr) +
327 (alpha - porosity) * (1.0 - alpha) /
328 _ip_data[ip].solid_material.getBulkModulus(
329 t, x_position, &C);
330
331 auto q = ip_data.darcy_velocity.head(GlobalDim);
332 q.noalias() = -k_over_mu * (dNdx_p * p + rho_fr * gravity_vec);
333
334 laplace_p.noalias() +=
335 dNdx_p.transpose() * k_over_mu * dNdx_p * ip_w;
336 storage_p.noalias() += N_p.transpose() * S * N_p * ip_w;
337
338 rhs_p.noalias() +=
339 dNdx_p.transpose() * rho_fr * k_over_mu * gravity_vec * ip_w;
340 }
341 }
342
343 // displacement equation, pressure part
344 J_up.noalias() -= Kup;
345
346 // pressure equation, pressure part.
347 J_pp.noalias() += laplace_p + storage_p / dt;
348
349 // pressure equation, displacement part.
350 J_pu.noalias() += Kup.transpose() / dt;
351
352 // pressure equation
353 rhs_p.noalias() -= laplace_p * p + storage_p * (p - p_prev) / dt +
354 Kup.transpose() * (u - u_prev) / dt;
355
356 // displacement equation
357 rhs_u.noalias() -= -Kup * p;
358}
359
360template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
361 int GlobalDim>
363 ShapeFunctionDisplacement, ShapeFunctionPressure,
364 GlobalDim>::postTimestepConcreteWithVector(double const t, double const dt,
365 Eigen::VectorXd const& local_x)
366{
367 auto p = const_cast<Eigen::VectorXd&>(local_x).segment(pressure_index,
368 pressure_size);
369 if (_process_data.deactivate_matrix_in_flow)
370 {
371 setPressureOfInactiveNodes(t, p);
372 }
373 auto u = local_x.segment(displacement_index, displacement_size);
374
375 postTimestepConcreteWithBlockVectors(t, dt, p, u);
376}
377
378template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
379 int GlobalDim>
380void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
381 ShapeFunctionPressure, GlobalDim>::
382 postTimestepConcreteWithBlockVectors(
383 double const t, double const dt,
384 Eigen::Ref<const Eigen::VectorXd> const& p,
385 Eigen::Ref<const Eigen::VectorXd> const& u)
386{
387 MPL::VariableArray variables;
388 MPL::VariableArray variables_prev;
390
391 auto const e_id = _element.getID();
392 x_position.setElementID(e_id);
393
395 KV sigma_avg = KV::Zero();
396 GlobalDimVector velocity_avg;
397 velocity_avg.setZero();
398
399 unsigned const n_integration_points = _ip_data.size();
400
401 auto const& medium = _process_data.media_map.getMedium(_element.getID());
402 auto const& liquid_phase = medium->phase("AqueousLiquid");
403 auto const T_ref =
404 medium->property(MPL::PropertyType::reference_temperature)
405 .template value<double>(variables, x_position, t, dt);
406 variables.temperature = T_ref;
407 variables_prev.temperature = T_ref;
408
409 auto const B_dil_bar = getDilatationalBBarMatrix();
410
411 for (unsigned ip = 0; ip < n_integration_points; ip++)
412 {
413 auto& ip_data = _ip_data[ip];
414
415 auto const& eps_prev = ip_data.eps_prev;
416 auto const& sigma_eff_prev = ip_data.sigma_eff_prev;
417
418 auto& eps = ip_data.eps;
419 auto& sigma_eff = ip_data.sigma_eff;
420 auto& state = ip_data.material_state_variables;
421
422 auto const& N_u = ip_data.N_u;
423 auto const& N_p = ip_data.N_p;
424 auto const& dNdx_u = ip_data.dNdx_u;
425
426 variables.liquid_phase_pressure = N_p.dot(p);
427
428 x_position = {
429 std::nullopt, _element.getID(),
431 NumLib::interpolateCoordinates<ShapeFunctionDisplacement,
433 _element, N_u))};
434
435 auto const x_coord = x_position.getCoordinates().value()[0];
436
437 auto const B =
439 GlobalDim, ShapeFunctionDisplacement::NPOINTS, BBarMatrixType,
441 dNdx_u, N_u, B_dil_bar, x_coord, this->_is_axially_symmetric)
442 .eval();
443
444 eps.noalias() = B * u;
445
446 variables.mechanical_strain
448
449 variables_prev.stress
451 sigma_eff_prev);
452 variables_prev.mechanical_strain
454 eps_prev);
455
456 auto&& solution = _ip_data[ip].solid_material.integrateStress(
457 variables_prev, variables, t, x_position, dt, *state);
458
459 if (!solution)
460 {
461 OGS_FATAL("Computation of local constitutive relation failed.");
462 }
463
465 std::tie(sigma_eff, state, C) = std::move(*solution);
466
467 sigma_avg += ip_data.sigma_eff;
468
469 if (!_process_data.deactivate_matrix_in_flow) // Only for hydraulically
470 // active matrix
471 {
472 auto const rho_fr =
473 liquid_phase.property(MPL::PropertyType::density)
474 .template value<double>(variables, x_position, t, dt);
475 variables.density = rho_fr;
476 auto const mu =
477 liquid_phase.property(MPL::PropertyType::viscosity)
478 .template value<double>(variables, x_position, t, dt);
479
480 auto const k = MPL::formEigenTensor<GlobalDim>(
481 medium->property(MPL::PropertyType::permeability)
482 .value(variables, x_position, t, dt))
483 .eval();
484
485 GlobalDimMatrixType const k_over_mu = k / mu;
486
487 auto const& gravity_vec = _process_data.specific_body_force;
488 auto const& dNdx_p = ip_data.dNdx_p;
489
490 ip_data.darcy_velocity.head(GlobalDim).noalias() =
491 -k_over_mu * (dNdx_p * p + rho_fr * gravity_vec);
492 velocity_avg.noalias() += ip_data.darcy_velocity.head(GlobalDim);
493 }
494 }
495
496 sigma_avg /= n_integration_points;
497 velocity_avg /= n_integration_points;
498
499 Eigen::Map<KV>(
500 &(*_process_data.element_stresses)[e_id * KV::RowsAtCompileTime]) =
502
503 Eigen::Map<GlobalDimVector>(
504 &(*_process_data.element_velocities)[e_id * GlobalDim]) = velocity_avg;
505
507 ShapeFunctionPressure, typename ShapeFunctionDisplacement::MeshElement,
508 GlobalDim>(_element, _is_axially_symmetric, p,
509 *_process_data.mesh_prop_nodal_p);
510}
511
512template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
513 int GlobalDim>
514void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
515 ShapeFunctionPressure, GlobalDim>::
516 setPressureOfInactiveNodes(double const t, Eigen::Ref<Eigen::VectorXd> p)
517{
519 x_position.setElementID(_element.getID());
520 for (unsigned i = 0; i < pressure_size; i++)
521 {
522 // only inactive nodes
523 if (_process_data.p_element_status->isActiveNode(_element.getNode(i)))
524 {
525 continue;
526 }
527 x_position.setNodeID(getNodeIndex(_element, i));
528 auto const p0 = (*_process_data.p0)(t, x_position)[0];
529 p[i] = p0;
530 }
531}
532
533template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
534 int GlobalDim>
535std::vector<double> const& HydroMechanicsLocalAssemblerMatrix<
536 ShapeFunctionDisplacement, ShapeFunctionPressure, GlobalDim>::
537 getIntPtSigma(
538 const double /*t*/,
539 std::vector<GlobalVector*> const& /*x*/,
540 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
541 std::vector<double>& cache) const
542{
544 _ip_data, &IntegrationPointDataType::sigma_eff, cache);
545}
546template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
547 int GlobalDim>
548std::vector<double> const& HydroMechanicsLocalAssemblerMatrix<
549 ShapeFunctionDisplacement, ShapeFunctionPressure, GlobalDim>::
550 getIntPtEpsilon(
551 const double /*t*/,
552 std::vector<GlobalVector*> const& /*x*/,
553 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
554 std::vector<double>& cache) const
555{
557 _ip_data, &IntegrationPointDataType::eps, cache);
558}
559
560template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
561 int GlobalDim>
562std::vector<double> const& HydroMechanicsLocalAssemblerMatrix<
563 ShapeFunctionDisplacement, ShapeFunctionPressure, GlobalDim>::
564 getIntPtDarcyVelocity(
565 const double /*t*/,
566 std::vector<GlobalVector*> const& /*x*/,
567 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
568 std::vector<double>& cache) const
569{
570 unsigned const n_integration_points = _ip_data.size();
571
572 cache.clear();
573 auto cache_matrix = MathLib::createZeroedMatrix<
574 Eigen::Matrix<double, GlobalDim, Eigen::Dynamic, Eigen::RowMajor>>(
575 cache, GlobalDim, n_integration_points);
576
577 for (unsigned ip = 0; ip < n_integration_points; ip++)
578 {
579 cache_matrix.col(ip).noalias() = _ip_data[ip].darcy_velocity;
580 }
581
582 return cache;
583}
584} // namespace HydroMechanics
585} // namespace LIE
586} // namespace ProcessLib
Definition of the ElementStatus class.
#define OGS_FATAL(...)
Definition Error.h:26
constexpr double getWeight() const
std::size_t getID() const
Returns the ID of the element.
Definition Element.h:89
MathLib::WeightedPoint const & getWeightedPoint(unsigned const igp) const
void setNodeID(std::size_t node_id)
void setElementID(std::size_t element_id)
std::optional< MathLib::Point3d > const getCoordinates() const
MatrixType< _kelvin_vector_size, _number_of_dof > BMatrixType
ShapeMatrixPolicyType< ShapeFunctionDisplacement, GlobalDim > ShapeMatricesTypeDisplacement
SecondaryData< typename ShapeMatricesTypeDisplacement::ShapeMatrices::ShapeType > _secondary_data
std::vector< IntegrationPointDataType, Eigen::aligned_allocator< IntegrationPointDataType > > _ip_data
ShapeMatrixPolicyType< ShapeFunctionPressure, GlobalDim > ShapeMatricesTypePressure
typename ShapeMatricesTypePressure::GlobalDimMatrixType GlobalDimMatrixType
auto & selectSolidConstitutiveRelation(SolidMaterialsMap const &constitutive_relations, MeshLib::PropertyVector< int > const *const material_ids, std::size_t const element_id)
Eigen::Matrix< double, GlobalDim, GlobalDim > formEigenTensor(MaterialPropertyLib::PropertyDataType const &values)
Eigen::Matrix< double, 4, 1 > kelvinVectorToSymmetricTensor(Eigen::Matrix< double, 4, 1, Eigen::ColMajor, 4, 1 > const &v)
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), 1, Eigen::ColMajor > KelvinVectorType
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), kelvin_vector_dimensions(DisplacementDim), Eigen::RowMajor > KelvinMatrixType
Eigen::Map< Matrix > createZeroedMatrix(std::vector< double > &data, Eigen::MatrixXd::Index rows, Eigen::MatrixXd::Index cols)
void interpolateToHigherOrderNodes(MeshLib::Element const &element, bool const is_axially_symmetric, Eigen::MatrixBase< EigenMatrixType > const &node_values, MeshLib::PropertyVector< double > &interpolated_values_global_vector)
std::vector< typename ShapeMatricesType::ShapeMatrices, Eigen::aligned_allocator< typename ShapeMatricesType::ShapeMatrices > > initShapeMatrices(MeshLib::Element const &e, bool const is_axially_symmetric, IntegrationMethod const &integration_method)
std::array< double, 3 > interpolateCoordinates(MeshLib::Element const &e, typename ShapeMatricesType::ShapeMatrices::ShapeType const &N)
BMatrixType computeBMatrixPossiblyWithBbar(DNDX_Type const &dNdx, N_Type const &N, std::optional< BBarMatrixType > const &B_dil_bar, const double radius, const bool is_axially_symmetric)
Fills a B matrix, or a B bar matrix if required.
std::vector< double > const & getIntegrationPointKelvinVectorData(IntegrationPointDataVector const &ip_data_vector, MemberType IpData::*const member, std::vector< double > &cache)
MatrixType< ShapeFunction::NPOINTS, ShapeFunction::NPOINTS > NodalMatrixType
std::vector< ShapeMatrixType, Eigen::aligned_allocator< ShapeMatrixType > > N