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 x_position.setIntegrationPoint(ip);
79
80 _ip_data.emplace_back(solid_material);
81 auto& ip_data = _ip_data[ip];
82 auto const& sm_u = shape_matrices_u[ip];
83 auto const& sm_p = shape_matrices_p[ip];
84
85 ip_data.integration_weight =
86 sm_u.detJ * sm_u.integralMeasure *
87 integration_method.getWeightedPoint(ip).getWeight();
88 ip_data.darcy_velocity.setZero();
89
90 ip_data.N_u = sm_u.N;
91 ip_data.dNdx_u = sm_u.dNdx;
92 ip_data.H_u.setZero(GlobalDim, displacement_size);
93 for (int i = 0; i < GlobalDim; ++i)
94 {
95 ip_data.H_u
96 .template block<1, displacement_size / GlobalDim>(
97 i, i * displacement_size / GlobalDim)
98 .noalias() = ip_data.N_u;
99 }
100
101 ip_data.N_p = sm_p.N;
102 ip_data.dNdx_p = sm_p.dNdx;
103
104 _secondary_data.N[ip] = sm_u.N;
105
106 ip_data.sigma_eff.setZero(kelvin_vector_size);
107 ip_data.eps.setZero(kelvin_vector_size);
108
109 ip_data.sigma_eff_prev.resize(kelvin_vector_size);
110 ip_data.eps_prev.resize(kelvin_vector_size);
111 ip_data.C.resize(kelvin_vector_size, kelvin_vector_size);
112
113 auto const initial_effective_stress =
114 _process_data.initial_effective_stress(0, x_position);
115 for (unsigned i = 0; i < kelvin_vector_size; i++)
116 {
117 ip_data.sigma_eff[i] = initial_effective_stress[i];
118 ip_data.sigma_eff_prev[i] = initial_effective_stress[i];
119 }
120 }
121}
122
123template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
124 int GlobalDim>
125void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
126 ShapeFunctionPressure, GlobalDim>::
127 assembleWithJacobianConcrete(double const t, double const dt,
128 Eigen::VectorXd const& local_x,
129 Eigen::VectorXd const& local_x_prev,
130 Eigen::VectorXd& local_rhs,
131 Eigen::MatrixXd& local_Jac)
132{
133 auto p = const_cast<Eigen::VectorXd&>(local_x).segment(pressure_index,
134 pressure_size);
135 auto const p_prev = local_x_prev.segment(pressure_index, pressure_size);
136
137 if (_process_data.deactivate_matrix_in_flow)
138 {
139 setPressureOfInactiveNodes(t, p);
140 }
141
142 auto u = local_x.segment(displacement_index, displacement_size);
143 auto u_prev = local_x_prev.segment(displacement_index, displacement_size);
144
145 auto rhs_p = local_rhs.template segment<pressure_size>(pressure_index);
146 auto rhs_u =
147 local_rhs.template segment<displacement_size>(displacement_index);
148
149 auto J_pp = local_Jac.template block<pressure_size, pressure_size>(
150 pressure_index, pressure_index);
151 auto J_pu = local_Jac.template block<pressure_size, displacement_size>(
152 pressure_index, displacement_index);
153 auto J_uu = local_Jac.template block<displacement_size, displacement_size>(
154 displacement_index, displacement_index);
155 auto J_up = local_Jac.template block<displacement_size, pressure_size>(
156 displacement_index, pressure_index);
157
158 assembleBlockMatricesWithJacobian(t, dt, p, p_prev, u, u_prev, rhs_p, rhs_u,
159 J_pp, J_pu, J_uu, J_up);
160}
161
162template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
163 int GlobalDim>
164void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
165 ShapeFunctionPressure, GlobalDim>::
166 assembleBlockMatricesWithJacobian(
167 double const t, double const dt,
168 Eigen::Ref<const Eigen::VectorXd> const& p,
169 Eigen::Ref<const Eigen::VectorXd> const& p_prev,
170 Eigen::Ref<const Eigen::VectorXd> const& u,
171 Eigen::Ref<const Eigen::VectorXd> const& u_prev,
172 Eigen::Ref<Eigen::VectorXd> rhs_p, Eigen::Ref<Eigen::VectorXd> rhs_u,
173 Eigen::Ref<Eigen::MatrixXd> J_pp, Eigen::Ref<Eigen::MatrixXd> J_pu,
174 Eigen::Ref<Eigen::MatrixXd> J_uu, Eigen::Ref<Eigen::MatrixXd> J_up)
175{
176 assert(this->_element.getDimension() == GlobalDim);
177
179 ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size,
180 pressure_size);
181
183 ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size,
184 pressure_size);
185
186 typename ShapeMatricesTypeDisplacement::template MatrixType<
187 displacement_size, pressure_size>
188 Kup = ShapeMatricesTypeDisplacement::template MatrixType<
189 displacement_size, pressure_size>::Zero(displacement_size,
190 pressure_size);
191
192 auto const& gravity_vec = _process_data.specific_body_force;
193
194 MPL::VariableArray variables;
195 MPL::VariableArray variables_prev;
197 x_position.setElementID(_element.getID());
198
199 auto const& medium = _process_data.media_map.getMedium(_element.getID());
200 auto const& liquid_phase = medium->phase("AqueousLiquid");
201 auto const& solid_phase = medium->phase("Solid");
202
203 auto const T_ref =
204 medium->property(MPL::PropertyType::reference_temperature)
205 .template value<double>(variables, x_position, t, dt);
206 variables.temperature = T_ref;
207 variables_prev.temperature = T_ref;
208
209 bool const has_storage_property =
210 medium->hasProperty(MPL::PropertyType::storage);
211
212 auto const B_dil_bar = getDilatationalBBarMatrix();
213
214 unsigned const n_integration_points = _ip_data.size();
215 for (unsigned ip = 0; ip < n_integration_points; ip++)
216 {
217 x_position.setIntegrationPoint(ip);
218
219 auto& ip_data = _ip_data[ip];
220 auto const& ip_w = ip_data.integration_weight;
221 auto const& N_u = ip_data.N_u;
222 auto const& dNdx_u = ip_data.dNdx_u;
223 auto const& N_p = ip_data.N_p;
224 auto const& dNdx_p = ip_data.dNdx_p;
225 auto const& H_u = ip_data.H_u;
226
227 variables.liquid_phase_pressure = N_p.dot(p);
228
229 auto const x_coord =
230 NumLib::interpolateXCoordinate<ShapeFunctionDisplacement,
232 _element, N_u);
233 auto const B =
235 GlobalDim, ShapeFunctionDisplacement::NPOINTS, BBarMatrixType,
237 dNdx_u, N_u, B_dil_bar, x_coord, this->_is_axially_symmetric)
238 .eval();
239
240 auto const& eps_prev = ip_data.eps_prev;
241 auto const& sigma_eff_prev = ip_data.sigma_eff_prev;
242 auto& sigma_eff = ip_data.sigma_eff;
243
244 auto& eps = ip_data.eps;
245 auto& state = ip_data.material_state_variables;
246
247 auto const rho_sr =
248 solid_phase.property(MPL::PropertyType::density)
249 .template value<double>(variables, x_position, t, dt);
250 auto const rho_fr =
251 liquid_phase.property(MPL::PropertyType::density)
252 .template value<double>(variables, x_position, t, dt);
253
254 auto const alpha =
255 medium->property(MPL::PropertyType::biot_coefficient)
256 .template value<double>(variables, x_position, t, dt);
257 auto const porosity =
258 medium->property(MPL::PropertyType::porosity)
259 .template value<double>(variables, x_position, t, dt);
260
261 double const rho = rho_sr * (1 - porosity) + porosity * rho_fr;
262 auto const& identity2 =
264
265 eps.noalias() = B * u;
266
267 variables.mechanical_strain
269
270 variables_prev.stress
272 sigma_eff_prev);
273 variables_prev.mechanical_strain
275 eps_prev);
276 variables_prev.temperature = T_ref;
277
278 auto&& solution = _ip_data[ip].solid_material.integrateStress(
279 variables_prev, variables, t, x_position, dt, *state);
280
281 if (!solution)
282 {
283 OGS_FATAL("Computation of local constitutive relation failed.");
284 }
285
287 std::tie(sigma_eff, state, C) = std::move(*solution);
288
289 J_uu.noalias() += B.transpose() * C * B * ip_w;
290
291 rhs_u.noalias() -= B.transpose() * sigma_eff * ip_w;
292 rhs_u.noalias() -= -H_u.transpose() * rho * gravity_vec * ip_w;
293
294 //
295 // pressure equation, pressure part and displacement equation, pressure
296 // part
297 //
298 if (!_process_data.deactivate_matrix_in_flow) // Only for hydraulically
299 // active matrix
300 {
301 Kup.noalias() += B.transpose() * alpha * identity2 * N_p * ip_w;
302
303 variables.density = rho_fr;
304 auto const mu =
305 liquid_phase.property(MPL::PropertyType::viscosity)
306 .template value<double>(variables, x_position, t, dt);
307
308 auto const k_over_mu =
310 medium->property(MPL::PropertyType::permeability)
311 .value(variables, x_position, t, dt)) /
312 mu)
313 .eval();
314
315 double const S =
316 has_storage_property
317 ? medium->property(MPL::PropertyType::storage)
318 .template value<double>(variables, x_position, t, dt)
319 : porosity *
320 (liquid_phase.property(MPL::PropertyType::density)
321 .template dValue<double>(
322 variables,
323 MPL::Variable::liquid_phase_pressure,
324 x_position, t, dt) /
325 rho_fr) +
326 (alpha - porosity) * (1.0 - alpha) /
327 _ip_data[ip].solid_material.getBulkModulus(
328 t, x_position, &C);
329
330 auto q = ip_data.darcy_velocity.head(GlobalDim);
331 q.noalias() = -k_over_mu * (dNdx_p * p + rho_fr * gravity_vec);
332
333 laplace_p.noalias() +=
334 dNdx_p.transpose() * k_over_mu * dNdx_p * ip_w;
335 storage_p.noalias() += N_p.transpose() * S * N_p * ip_w;
336
337 rhs_p.noalias() +=
338 dNdx_p.transpose() * rho_fr * k_over_mu * gravity_vec * ip_w;
339 }
340 }
341
342 // displacement equation, pressure part
343 J_up.noalias() -= Kup;
344
345 // pressure equation, pressure part.
346 J_pp.noalias() += laplace_p + storage_p / dt;
347
348 // pressure equation, displacement part.
349 J_pu.noalias() += Kup.transpose() / dt;
350
351 // pressure equation
352 rhs_p.noalias() -= laplace_p * p + storage_p * (p - p_prev) / dt +
353 Kup.transpose() * (u - u_prev) / dt;
354
355 // displacement equation
356 rhs_u.noalias() -= -Kup * p;
357}
358
359template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
360 int GlobalDim>
362 ShapeFunctionDisplacement, ShapeFunctionPressure,
363 GlobalDim>::postTimestepConcreteWithVector(double const t, double const dt,
364 Eigen::VectorXd const& local_x)
365{
366 auto p = const_cast<Eigen::VectorXd&>(local_x).segment(pressure_index,
367 pressure_size);
368 if (_process_data.deactivate_matrix_in_flow)
369 {
370 setPressureOfInactiveNodes(t, p);
371 }
372 auto u = local_x.segment(displacement_index, displacement_size);
373
374 postTimestepConcreteWithBlockVectors(t, dt, p, u);
375}
376
377template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
378 int GlobalDim>
379void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
380 ShapeFunctionPressure, GlobalDim>::
381 postTimestepConcreteWithBlockVectors(
382 double const t, double const dt,
383 Eigen::Ref<const Eigen::VectorXd> const& p,
384 Eigen::Ref<const Eigen::VectorXd> const& u)
385{
386 MPL::VariableArray variables;
387 MPL::VariableArray variables_prev;
389
390 auto const e_id = _element.getID();
391 x_position.setElementID(e_id);
392
394 KV sigma_avg = KV::Zero();
395 GlobalDimVector velocity_avg;
396 velocity_avg.setZero();
397
398 unsigned const n_integration_points = _ip_data.size();
399
400 auto const& medium = _process_data.media_map.getMedium(_element.getID());
401 auto const& liquid_phase = medium->phase("AqueousLiquid");
402 auto const T_ref =
403 medium->property(MPL::PropertyType::reference_temperature)
404 .template value<double>(variables, x_position, t, dt);
405 variables.temperature = T_ref;
406 variables_prev.temperature = T_ref;
407
408 auto const B_dil_bar = getDilatationalBBarMatrix();
409
410 for (unsigned ip = 0; ip < n_integration_points; ip++)
411 {
412 x_position.setIntegrationPoint(ip);
413
414 auto& ip_data = _ip_data[ip];
415
416 auto const& eps_prev = ip_data.eps_prev;
417 auto const& sigma_eff_prev = ip_data.sigma_eff_prev;
418
419 auto& eps = ip_data.eps;
420 auto& sigma_eff = ip_data.sigma_eff;
421 auto& state = ip_data.material_state_variables;
422
423 auto const& N_u = ip_data.N_u;
424 auto const& N_p = ip_data.N_p;
425 auto const& dNdx_u = ip_data.dNdx_u;
426
427 variables.liquid_phase_pressure = N_p.dot(p);
428
429 auto const x_coord =
430 NumLib::interpolateXCoordinate<ShapeFunctionDisplacement,
432 _element, N_u);
433 auto const B =
435 GlobalDim, ShapeFunctionDisplacement::NPOINTS, BBarMatrixType,
437 dNdx_u, N_u, B_dil_bar, x_coord, this->_is_axially_symmetric)
438 .eval();
439
440 eps.noalias() = B * u;
441
442 variables.mechanical_strain
444
445 variables_prev.stress
447 sigma_eff_prev);
448 variables_prev.mechanical_strain
450 eps_prev);
451
452 auto&& solution = _ip_data[ip].solid_material.integrateStress(
453 variables_prev, variables, t, x_position, dt, *state);
454
455 if (!solution)
456 {
457 OGS_FATAL("Computation of local constitutive relation failed.");
458 }
459
461 std::tie(sigma_eff, state, C) = std::move(*solution);
462
463 sigma_avg += ip_data.sigma_eff;
464
465 if (!_process_data.deactivate_matrix_in_flow) // Only for hydraulically
466 // active matrix
467 {
468 auto const rho_fr =
469 liquid_phase.property(MPL::PropertyType::density)
470 .template value<double>(variables, x_position, t, dt);
471 variables.density = rho_fr;
472 auto const mu =
473 liquid_phase.property(MPL::PropertyType::viscosity)
474 .template value<double>(variables, x_position, t, dt);
475
476 auto const k = MPL::formEigenTensor<GlobalDim>(
477 medium->property(MPL::PropertyType::permeability)
478 .value(variables, x_position, t, dt))
479 .eval();
480
481 GlobalDimMatrixType const k_over_mu = k / mu;
482
483 auto const& gravity_vec = _process_data.specific_body_force;
484 auto const& dNdx_p = ip_data.dNdx_p;
485
486 ip_data.darcy_velocity.head(GlobalDim).noalias() =
487 -k_over_mu * (dNdx_p * p + rho_fr * gravity_vec);
488 velocity_avg.noalias() += ip_data.darcy_velocity.head(GlobalDim);
489 }
490 }
491
492 sigma_avg /= n_integration_points;
493 velocity_avg /= n_integration_points;
494
495 Eigen::Map<KV>(
496 &(*_process_data.element_stresses)[e_id * KV::RowsAtCompileTime]) =
498
499 Eigen::Map<GlobalDimVector>(
500 &(*_process_data.element_velocities)[e_id * GlobalDim]) = velocity_avg;
501
503 ShapeFunctionPressure, typename ShapeFunctionDisplacement::MeshElement,
504 GlobalDim>(_element, _is_axially_symmetric, p,
505 *_process_data.mesh_prop_nodal_p);
506}
507
508template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
509 int GlobalDim>
510void HydroMechanicsLocalAssemblerMatrix<ShapeFunctionDisplacement,
511 ShapeFunctionPressure, GlobalDim>::
512 setPressureOfInactiveNodes(double const t, Eigen::Ref<Eigen::VectorXd> p)
513{
515 x_position.setElementID(_element.getID());
516 for (unsigned i = 0; i < pressure_size; i++)
517 {
518 // only inactive nodes
519 if (_process_data.p_element_status->isActiveNode(_element.getNode(i)))
520 {
521 continue;
522 }
523 x_position.setNodeID(getNodeIndex(_element, i));
524 auto const p0 = (*_process_data.p0)(t, x_position)[0];
525 p[i] = p0;
526 }
527}
528
529template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
530 int GlobalDim>
531std::vector<double> const& HydroMechanicsLocalAssemblerMatrix<
532 ShapeFunctionDisplacement, ShapeFunctionPressure, GlobalDim>::
533 getIntPtSigma(
534 const double /*t*/,
535 std::vector<GlobalVector*> const& /*x*/,
536 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
537 std::vector<double>& cache) const
538{
540 _ip_data, &IntegrationPointDataType::sigma_eff, cache);
541}
542template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
543 int GlobalDim>
544std::vector<double> const& HydroMechanicsLocalAssemblerMatrix<
545 ShapeFunctionDisplacement, ShapeFunctionPressure, GlobalDim>::
546 getIntPtEpsilon(
547 const double /*t*/,
548 std::vector<GlobalVector*> const& /*x*/,
549 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
550 std::vector<double>& cache) const
551{
553 _ip_data, &IntegrationPointDataType::eps, cache);
554}
555
556template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
557 int GlobalDim>
558std::vector<double> const& HydroMechanicsLocalAssemblerMatrix<
559 ShapeFunctionDisplacement, ShapeFunctionPressure, GlobalDim>::
560 getIntPtDarcyVelocity(
561 const double /*t*/,
562 std::vector<GlobalVector*> const& /*x*/,
563 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
564 std::vector<double>& cache) const
565{
566 unsigned const n_integration_points = _ip_data.size();
567
568 cache.clear();
569 auto cache_matrix = MathLib::createZeroedMatrix<
570 Eigen::Matrix<double, GlobalDim, Eigen::Dynamic, Eigen::RowMajor>>(
571 cache, GlobalDim, n_integration_points);
572
573 for (unsigned ip = 0; ip < n_integration_points; ip++)
574 {
575 cache_matrix.col(ip).noalias() = _ip_data[ip].darcy_velocity;
576 }
577
578 return cache;
579}
580} // namespace HydroMechanics
581} // namespace LIE
582} // namespace ProcessLib
Definition of the ElementStatus class.
#define OGS_FATAL(...)
Definition Error.h:26
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)
void setIntegrationPoint(unsigned integration_point)
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)
double interpolateXCoordinate(MeshLib::Element const &e, typename ShapeMatricesType::ShapeMatrices::ShapeType const &N)
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)
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