FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
p1.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
9#include <kernel/geometry/conformal_mesh.hpp>
10#include <kernel/shape.hpp>
11#include <kernel/meshopt/base.hpp>
12#include <kernel/meshopt/rumpf_functional.hpp>
13
14#include <kernel/eval_tags.hpp>
15#include <kernel/cubature/dynamic_factory.hpp>
16#include <kernel/cubature/rule.hpp>
17
18namespace FEAT
19{
20 namespace Meshopt
21 {
23
27 template<typename DataType_, int shape_dim_>
28 class RumpfFunctional<DataType_,
29 Trafo::Standard::Mapping<Geometry::ConformalMesh<Shape::Simplex<shape_dim_>, shape_dim_, DataType_>>> :
30 public RumpfFunctionalBase<DataType_>
31 {
32 public:
34 typedef RumpfFunctionalBase<DataType_> BaseClass;
35
37 typedef DataType_ DataType;
39 static constexpr int shape_dim = shape_dim_;
41 static constexpr int world_dim = shape_dim;
43 typedef Shape::Simplex<shape_dim_> ShapeType;
45 typedef Trafo::Standard::Mapping<Geometry::ConformalMesh<ShapeType, world_dim, DataType_>> TrafoType;
47 typedef typename Intern::TrafoFE<TrafoType>::Space TrafoSpace;
48
50 typedef Tiny::Matrix<DataType_, Shape::FaceTraits<ShapeType,0>::count, world_dim> Tx;
52 typedef Tiny::Vector<DataType_, Shape::FaceTraits<ShapeType,0>::count*world_dim> Tgradh;
53
55 typedef Tiny::Matrix<DataType_, shape_dim, world_dim> TgradR;
56
58 typedef typename TrafoType::template Evaluator<ShapeType, DataType>::Type TrafoEvaluator;
60 typedef typename TrafoSpace::template Evaluator<TrafoEvaluator>::Type SpaceEvaluator;
61
66
67 // Data from evaluating the transformation
68 typedef typename TrafoEvaluator::template ConfigTraits<trafo_config>::EvalDataType TrafoEvalData;
69 // Data from evaluating FE spaces
70 typedef typename SpaceEvaluator::template ConfigTraits<space_config>::EvalDataType SpaceEvalData;
71
72
73 private:
75 TgradR grad_R;
77 TgradR inv_grad_R;
79 TgradR cof_grad_R;
80
82 Cubature::DynamicFactory _cubature_factory;
84 Cubature::Rule<ShapeType, DataType, DataType, Tiny::Vector<DataType, world_dim>> _cubature_rule;
85
87 DataType _frobenius_grad_R;
89 DataType _frobenius_cof_grad_R;
91 DataType _det_grad_R;
93 DataType _normalized_ref_cell_vol;
94
96 const int _exponent_det;
97
99 const bool _compute_frobenius;
101 const bool _compute_cof;
103 const bool _compute_det;
105 const bool _compute_inverse;
106
107 public:
111 explicit RumpfFunctional(
112 const DataType fac_frobenius_,
113 const DataType fac_det_,
114 const DataType fac_cof_,
115 const DataType fac_reg_,
116 const int exponent_det_) :
117 BaseClass( fac_frobenius_,
118 fac_det_,
119 fac_det_*(Math::sqrt( Math::sqr(fac_reg_) + DataType(1) )*Math::pow( DataType(1)
120 + Math::sqrt(Math::sqr(fac_reg_) + DataType(1)), DataType(exponent_det_))),
121 fac_cof_,
122 fac_reg_),
123 grad_R(0),
124 inv_grad_R(0),
125 _cubature_factory("auto-degree:0"),
126 _cubature_rule(Cubature::ctor_factory,_cubature_factory),
127 _frobenius_grad_R(0),
128 _frobenius_cof_grad_R(0),
129 _det_grad_R(0),
130 _normalized_ref_cell_vol(1),
131 _exponent_det(exponent_det_),
132 _compute_frobenius( (fac_frobenius_ > DataType(0)) ),
133 _compute_cof( (fac_cof_ > 0) ),
134 _compute_det( (fac_det_ > 0) ),
135 _compute_inverse( _compute_det || _compute_cof)
136 {
137 XASSERTM(exponent_det_ == 1 || exponent_det_ == 2,"exponent_det must be 1 or 2!");
138 XASSERTM(world_dim == 3 || fac_cof_ == DataType(0),
139 "In 2d, the cofactor and frobenius norm term are redundant, so set fac_cof = 0.");
140
141 // vol(Simplex<d>) = d!
142 for(int d(1); d < world_dim; ++d)
143 {
144 _normalized_ref_cell_vol /= DataType(d+1);
145 }
146
147 }
148
154 static String name()
155 {
156 return "RumpfFunctional<"+ShapeType::name()+">";
157 }
158
162 String info() const
163 {
164 const Index pad_width(30);
165 return name() + ":" + BaseClass::info()
166 + String("\nexponent_det").pad_back(pad_width, '.') + String(": ") + stringify(_exponent_det)
167 + String("\ncubature_rule").pad_back(pad_width, '.') + String(": ") + _cubature_rule.get_name();
168 }
169
170 void set_point(const TrafoEvalData& trafo_data, const TgradR& mat_tensor)
171 {
172
173 // We abuse inv_grad_R as temporary storage
174 inv_grad_R = trafo_data.jac_mat*mat_tensor;
175
176 // grad_R = mat_tensor^T * grad(trafo) because we need to differentiate in the scaled coordinate system
177 grad_R.set_transpose(inv_grad_R);
178
179 // compute determinant before the inverse to avoid division by zero
180 // if grad_R is singular
181 if(_compute_det || _compute_inverse)
182 {
183 _det_grad_R = grad_R.det();
184 }
185
186 // Set the inverse matrix needed for everything related to the derivative of det(grad_R)
187 if(_compute_inverse)
188 {
189 if(Math::isnormal(_det_grad_R))
190 inv_grad_R.set_inverse(grad_R);
191 else
192 {
193 // grad_R is singular, so don't compute inverse to avoid division by zero,
194 // format its entries to NaN instead
195 inv_grad_R.format(Math::nan<DataType>());
196 }
197 }
198
199 if(_compute_frobenius)
200 {
201 _frobenius_grad_R = grad_R.norm_frobenius();
202 }
203
204 if(_compute_cof)
205 {
206 cof_grad_R.set_cofactor(grad_R);
207 _frobenius_cof_grad_R = cof_grad_R.norm_frobenius();
208 }
209 }
210
214 DataType compute_frobenius_part()
215 {
216 return Math::sqr(Math::sqr(_frobenius_grad_R) - DataType(TgradR::n))/_normalized_ref_cell_vol;
217 }
218
222 DataType compute_cof_part()
223 {
224 return Math::sqr(Math::sqr(_frobenius_cof_grad_R) - DataType(TgradR::n))/_normalized_ref_cell_vol;
225 }
226
230 DataType compute_det_part()
231 {
232 if(_exponent_det == 1)
233 {
234 return _det_grad_R/_normalized_ref_cell_vol;
235 }
236 else
237 {
238 return Math::sqr(_det_grad_R)/_normalized_ref_cell_vol;
239 }
240 }
241
245 DataType compute_rec_det_part()
246 {
247 DataType fac;
248 if(_det_grad_R <= DataType(0))
249 {
250 fac = DataType(1)/this->_fac_reg;
251 }
252 else
253 {
254 fac = DataType(1)/( _det_grad_R + Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R)) );
255 }
256
257 if(_exponent_det == 1)
258 {
259 return fac/_normalized_ref_cell_vol;
260 }
261 else
262 {
263 return Math::sqr(fac)/_normalized_ref_cell_vol;
264 }
265 }
266
270 void eval_fval_grad(DataType& fval, Tx& grad, const TgradR& mat_tensor,
271 const TrafoEvaluator& trafo_eval, const SpaceEvaluator& space_eval,
272 const Tx& DOXY(x), const DataType& DOXY(h))
273 {
274 TrafoEvalData trafo_data;
275 SpaceEvalData space_data;
276
277 grad.format(DataType(0));
278 fval = DataType(0);
279
280 DataType fval_frobenius(0);
281 DataType fval_cof(0);
282 DataType fval_det(0);
283 DataType fval_rec_det(0);
284
285 for(int k(0); k < _cubature_rule.get_num_points(); ++k)
286 {
287 // Evaluate trafo and FE space
288 trafo_eval(trafo_data, _cubature_rule.get_point(k));
289 space_eval(space_data, trafo_data);
290 // Compute quantities for nonlinear form
291 set_point(trafo_data, mat_tensor);
292
293 DataType weight(_cubature_rule.get_weight(k));
294
295 if(_compute_frobenius)
296 {
297 fval_frobenius += this->_fac_frobenius*weight*compute_frobenius_part();
298 // The factor jac_det cancels out with the chain rule for the derivative of the test function
299 add_grad_frobenius(grad, space_data, mat_tensor, this->_fac_frobenius*weight);
300 }
301
302 if(_compute_cof)
303 {
304 fval_cof += this->_fac_cof*weight*compute_cof_part();
305 // The factor jac_det cancels out with the chain rule for the derivative of the test function
306 add_grad_cof(grad, space_data, mat_tensor, this->_fac_cof*weight);
307 }
308
309 if(_compute_det)
310 {
311 fval_det += this->_fac_det*weight*compute_det_part();
312 add_grad_det(grad, space_data, mat_tensor, this->_fac_det*weight);
313
314 fval_rec_det += this->_fac_rec_det*weight*compute_rec_det_part();
315 add_grad_rec_det(grad, space_data, mat_tensor, this->_fac_rec_det*weight);
316 }
317
318 }
319
320 fval = fval_frobenius + fval_cof + fval_det + fval_rec_det;
321
322 }
323
327 void eval_fval_cellwise(DataType& fval, const TgradR& mat_tensor,
328 const TrafoEvaluator& trafo_eval, const SpaceEvaluator& space_eval,
329 const Tx& DOXY(x), const DataType& DOXY(h),
330 DataType& fval_frobenius, DataType& fval_cof, DataType& fval_det)
331 {
332
333 TrafoEvalData trafo_data;
334 SpaceEvalData space_data;
335
336 fval = DataType(0);
337 fval_frobenius = DataType(0);
338 fval_cof = DataType(0);
339 fval_det = DataType(0);
340
341 TgradR grad_rec_det(0);
342
343 for(int k(0); k < _cubature_rule.get_num_points(); ++k)
344 {
345 // Evaluate trafo and FE space
346 trafo_eval(trafo_data, _cubature_rule.get_point(k));
347 space_eval(space_data, trafo_data);
348
349 // Compute quantities for nonlinear form
350 set_point(trafo_data, mat_tensor);
351 DataType weight(_cubature_rule.get_weight(k));
352
353 if(_compute_frobenius)
354 {
355 fval_frobenius += weight*this->_fac_frobenius*compute_frobenius_part();
356 }
357
358 if(_compute_cof)
359 {
360 fval_cof += weight*this->_fac_cof*compute_cof_part();
361 }
362
363 if(_compute_det)
364 {
365 fval_det += weight*this->_fac_det*compute_det_part();
366 fval_det += weight*this->_fac_rec_det*compute_rec_det_part();
367 }
368
369 }
370
371 fval = fval_frobenius + fval_cof + fval_det;
372 }
373
377 void add_grad_frobenius(Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor, const DataType fac)
378 {
379 DataType my_fac(fac*DataType(4)*(Math::sqr(_frobenius_grad_R) - DataType(TgradR::n)));
380 my_fac /= _normalized_ref_cell_vol;
381
382 for(int i(0); i < SpaceEvalData::max_local_dofs; ++i)
383 {
384 for(int d(0); d < world_dim; ++d)
385 {
386 grad[i] += my_fac*(mat_tensor[d]*space_data.phi[i].ref_grad[d])*grad_R;
387 }
388 }
389 }
390
394 void add_grad_cof(Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor, const DataType fac)
395 {
396 DataType my_fac(fac*DataType(4)*(Math::sqr(_frobenius_cof_grad_R) - DataType(TgradR::n)));
397 my_fac /= _normalized_ref_cell_vol;
398
399 TgradR cof_grad_R_transpose(0);
400 cof_grad_R_transpose.set_transpose(cof_grad_R);
401
402 for(int i(0); i < SpaceEvalData::max_local_dofs; ++i)
403 {
404 auto transformed_phi_ref_grad = space_data.phi[i].ref_grad*mat_tensor;
405
406 for(int d(0); d < world_dim; ++d)
407 {
408 grad[i][d] += my_fac*(
409 Tiny::dot( inv_grad_R[d], transformed_phi_ref_grad)*Math::sqr(_frobenius_cof_grad_R)
410 - Tiny::dot(cof_grad_R[d], cof_grad_R_transpose*(inv_grad_R*transformed_phi_ref_grad)));
411 }
412 }
413 }
414
418 void add_grad_det(Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor, const DataType fac)
419 {
420 DataType my_fac(fac);
421 if(_exponent_det == 1)
422 {
423 my_fac *= _det_grad_R/_normalized_ref_cell_vol;
424 }
425 else
426 {
427 my_fac *= DataType(2)*Math::sqr(_det_grad_R)/_normalized_ref_cell_vol;
428 }
429
430 for(int i(0); i < SpaceEvalData::max_local_dofs; ++i)
431 {
432 for(int d(0); d < world_dim; ++d)
433 {
434 grad[i] += my_fac*inv_grad_R*(mat_tensor[d]*space_data.phi[i].ref_grad[d]);
435 }
436 }
437 }
438
442 void add_grad_rec_det(Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor, const DataType fac)
443 {
444 DataType my_fac(-fac/_normalized_ref_cell_vol);
445 if(_exponent_det == 1)
446 {
447 my_fac *= _det_grad_R / Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R));
448 if(_det_grad_R > DataType(0))
449 {
450 my_fac /= (_det_grad_R + Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R)));
451 }
452 else
453 {
454 my_fac /= this->_fac_reg;
455 }
456 }
457 else
458 {
459 my_fac *= DataType(2)*Math::sqr(_det_grad_R) / (Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R));
460 if(_det_grad_R > DataType(0))
461 {
462 my_fac /= Math::sqr(_det_grad_R + Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R)));
463 }
464 else
465 {
466 my_fac /= Math::sqr(this->_fac_reg);
467 }
468 }
469
470 for(int i(0); i < SpaceEvalData::max_local_dofs; ++i)
471 {
472 for(int d(0); d < world_dim; ++d)
473 {
474 grad[i] += my_fac*inv_grad_R*(mat_tensor[d]*space_data.phi[i].ref_grad[d]);
475 }
476 }
477 }
478
482 void add_grad_h_part(Tx& grad, const TgradR& mat_tensor,
483 const TrafoEvaluator& trafo_eval, const SpaceEvaluator& space_eval,
484 const Tx& DOXY(x), const DataType& h, const Tgradh& grad_h)
485 {
486
487 TrafoEvalData trafo_data;
488 SpaceEvalData space_data;
489
490 DataType frobenius_der_h(0);
491 DataType det_der_h(0);
492 DataType rec_det_der_h(0);
493
494 for(int k(0); k < _cubature_rule.get_num_points(); ++k)
495 {
496 // Evaluate trafo and FE space
497 trafo_eval(trafo_data, _cubature_rule.get_point(k));
498 space_eval(space_data, trafo_data);
499
500 // Compute quantities for nonlinear form
501 set_point(trafo_data, mat_tensor);
502
503 DataType weight(_cubature_rule.get_weight(k));
504
505 // Add outer parts of the chain rule derivatives, which are different in every integration point
506 frobenius_der_h += weight*DataType(4)*(Math::sqr(_frobenius_grad_R) - DataType(world_dim))*
507 Math::sqr(_frobenius_grad_R)/_normalized_ref_cell_vol;
508
509 det_der_h += weight*_det_grad_R/_normalized_ref_cell_vol;
510
511 DataType fac;
512 if(_det_grad_R >= DataType(0))
513 {
514 fac = Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R));
515 }
516 else
517 {
518 fac = this->_fac_reg;
519 }
520 rec_det_der_h += weight*_det_grad_R/(fac*(_det_grad_R + fac))/_normalized_ref_cell_vol;
521
522 }
523
524 // The inner part of the chain rule derivative is constant wrt. to space, so we can just scale at this point
525 frobenius_der_h *= this->_fac_frobenius*DataType(-1)/h;
526 det_der_h *= this->_fac_det*DataType(-2)/h;
527 rec_det_der_h *= this->_fac_rec_det*DataType(2)/h;
528
529 DataType der_h(frobenius_der_h + det_der_h + rec_det_der_h);
530
531 // Add the local contributions to the global gradient
532 for(int i(0); i < Tx::m; ++i)
533 {
534 for(int d(0); d < Tx::n; ++d)
535 {
536 grad(i,d) += der_h*grad_h(i*Tx::n + d);
537 }
538 }
539 } // add_grad_h_part
540
541 }; // class RumpfFunctional
542#ifdef FEAT_EICKT
543 extern template class RumpfFunctional<double,
544 Trafo::Standard::Mapping<Geometry::ConformalMesh<Shape::Simplex<2>, 2, double>>>;
545
546 extern template class RumpfFunctional<double,
547 Trafo::Standard::Mapping<Geometry::ConformalMesh<Shape::Simplex<3>, 3, double>>>;
548#endif // FEAT_EICKT
550 } // namespace Meshopt
551} // namespace FEAT
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
String info() const
Print basic information.
SpaceEvaluator::template ConfigTraits< space_config >::EvalDataType SpaceEvalData
Data from evaluating FE spaces.
void eval_fval_cellwise(DataType &fval, const TgradR &mat_tensor, const TrafoEvaluator &trafo_eval, const SpaceEvaluator &space_eval, const Tx &x, const DataType &h, DataType &fval_frobenius, DataType &fval_cof, DataType &fval_det)
Computes the different contributions to the functional's value on one cell.
TrafoType::template Evaluator< ShapeType, DataType >::Type TrafoEvaluator
Type for evaluating the transformation.
Tiny::Matrix< DataType_, shape_dim, world_dim > TgradR
Type for the gradient of the local reference mapping.
void eval_fval_grad(DataType &fval, Tx &grad, const TgradR &mat_tensor, const TrafoEvaluator &trafo_eval, const SpaceEvaluator &space_eval, const Tx &x, const DataType &h)
Computes the functional's value and gradient on one cell.
DataType_ DataType
Our data type.
static constexpr int world_dim
Our world dimension - only world_dim == shape_dim is supported.
RumpfFunctional(const DataType_ fac_frobenius_, const DataType_ fac_det_, const DataType_ fac_cof_, const DataType_ fac_reg_, const int exponent_det_)
Constructor.
Tiny::Matrix< DataType_, Shape::FaceTraits< ShapeType, 0 >::count, world_dim > Tx
Type for a pack of local vertex coordinates.
static constexpr int shape_dim
Our shape dimension.
static constexpr SpaceTags space_config
For the FE space, we only need the gradients on the reference cell.
Trafo::Standard::Mapping< Geometry::ConformalMesh< ShapeType, world_dim, DataType_ > > TrafoType
The transformation this functional works on.
Tiny::Vector< DataType_, Shape::FaceTraits< ShapeType, 0 >::count *world_dim > Tgradh
Type for the gradient of the local cell sizes.
Shape::Hypercube< shape_dim_ > ShapeType
Shape type of the underlying transformation.
TrafoSpace::template Evaluator< TrafoEvaluator >::Type SpaceEvaluator
Type for evaluating the FE functions.
void add_grad_h_part(Tx &grad, const TgradR &mat_tensor, const TrafoEvaluator &trafo_eval, const SpaceEvaluator &space_eval, const Tx &x, const DataType &h, const Tgradh &grad_h)
Adds the gradient h part to the local gradient.
RumpfFunctionalBase< DataType_ > BaseClass
Our baseclass.
static constexpr TrafoTags trafo_config
We need the Trafo to evaluate the image point, the Jacobian and its determinant.
TrafoEvaluator::template ConfigTraits< trafo_config >::EvalDataType TrafoEvalData
Data from evaluating the transformation.
Intern::TrafoFE< TrafoType >::Space TrafoSpace
The FE space associated with the transformation.
String pad_back(size_type len, char c=' ') const
Pads the back of the string up to a desired length.
Definition: string.hpp:415
static constexpr int n
the column count of the matrix
static constexpr int m
the row count of the matrix
T_ sqrt(T_ x)
Returns the square-root of a value.
Definition: math.hpp:300
bool isnormal(T_ x)
Checks whether a value is normal.
T_ pow(T_ x, T_ y)
Returns x raised to the power of y.
Definition: math.hpp:643
T_ sqr(T_ x)
Returns the square of a value.
Definition: math.hpp:95
CUDA_HOST_DEVICE T_ dot(const T_ &a, const T_ &b)
Computes the dot-product of two scalars.
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
SpaceTags
Space configuration tags enum.
Definition: eval_tags.hpp:97
@ ref_grad
specifies whether the space should supply reference basis function gradients
@ grad
specifies whether the space should supply basis function gradients
std::uint64_t Index
Index data type.
TrafoTags
Trafo configuration tags enum.
Definition: eval_tags.hpp:22
@ img_point
specifies whether the trafo should supply image point coordinates
@ jac_mat
specifies whether the trafo should supply jacobian matrices
@ jac_det
specifies whether the trafo should supply jacobian determinants
static String name()
Returns the name of the class as a String.
Definition: shape.hpp:71