FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
q1.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::Hypercube<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::Hypercube<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 // If a cell is nonconvex we get det <= 0 at some vertex, so it is advantageous to have a cubature
126 // formula that also contains that vertex
127 _cubature_factory("newton-cotes-closed:"+stringify(4)),
128 //_cubature_factory("auto-degree:"+stringify(5)),
129 _cubature_rule(Cubature::ctor_factory,_cubature_factory),
130 _frobenius_grad_R(0),
131 _frobenius_cof_grad_R(0),
132 _det_grad_R(0),
133 _normalized_ref_cell_vol(1<<world_dim),
134 _exponent_det(exponent_det_),
135 _compute_frobenius( (fac_frobenius_ > DataType(0)) ),
136 _compute_cof( (fac_cof_ > 0) ),
137 _compute_det( (fac_det_ > 0) ),
138 _compute_inverse( _compute_det || _compute_cof)
139 {
140 XASSERTM(exponent_det_ == 1 || exponent_det_ == 2,"exponent_det must be 1 or 2!");
141 XASSERTM(world_dim == 3 || fac_cof_ == DataType(0),
142 "In 2d, the cofactor and frobenius norm term are redundant, so set fac_cof = 0.");
143 }
144
150 static String name()
151 {
152 return "RumpfFunctional<"+ShapeType::name()+">";
153 }
154
158 String info() const
159 {
160 const Index pad_width(30);
161 return name() + ":" + BaseClass::info()
162 + String("\nexponent_det").pad_back(pad_width, '.') + String(": ") + stringify(_exponent_det)
163 + String("\ncubature_rule").pad_back(pad_width, '.') + String(": ") + _cubature_rule.get_name();
164 }
165
166 void set_point(const TrafoEvalData& trafo_data, const TgradR& mat_tensor)
167 {
168
169 // We abuse inv_grad_R as temporary storage
170 inv_grad_R = trafo_data.jac_mat*mat_tensor;
171
172 // grad_R = mat_tensor^T * grad(trafo) because we need to differentiate in the scaled coordinate system
173 grad_R.set_transpose(inv_grad_R);
174
175 // compute determinant before the inverse to avoid division by zero
176 // if grad_R is singular
177 if(_compute_det || _compute_inverse)
178 {
179 _det_grad_R = grad_R.det();
180 }
181
182 // Set the inverse matrix needed for everything related to the derivative of det(grad_R)
183 if(_compute_inverse)
184 {
185 if(Math::isnormal(_det_grad_R))
186 inv_grad_R.set_inverse(grad_R);
187 else
188 {
189 // grad_R is singular, so don't compute inverse to avoid division by zero,
190 // format its entries to NaN instead
191 inv_grad_R.format(Math::nan<DataType>());
192 }
193 }
194
195 if(_compute_frobenius)
196 {
197 _frobenius_grad_R = grad_R.norm_frobenius();
198 }
199
200 if(_compute_cof)
201 {
202 cof_grad_R.set_cofactor(grad_R);
203 _frobenius_cof_grad_R = cof_grad_R.norm_frobenius();
204 }
205 }
206
210 DataType compute_frobenius_part()
211 {
212 return Math::sqr(Math::sqr(_frobenius_grad_R) - DataType(TgradR::n))/_normalized_ref_cell_vol;
213 }
214
218 DataType compute_cof_part()
219 {
220 return Math::sqr(Math::sqr(_frobenius_cof_grad_R) - DataType(TgradR::n))/_normalized_ref_cell_vol;
221 }
222
226 DataType compute_det_part()
227 {
228 if(_exponent_det == 1)
229 {
230 return _det_grad_R/_normalized_ref_cell_vol;
231 }
232 else
233 {
234 return Math::sqr(_det_grad_R)/_normalized_ref_cell_vol;
235 }
236 }
237
241 DataType compute_rec_det_part()
242 {
243 DataType fac;
244 if(_det_grad_R <= DataType(0))
245 {
246 fac = DataType(1)/this->_fac_reg;
247 }
248 else
249 {
250 fac = DataType(1)/( _det_grad_R + Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R)) );
251 }
252
253 if(_exponent_det == 1)
254 {
255 return fac/_normalized_ref_cell_vol;
256 }
257 else
258 {
259 return Math::sqr(fac)/_normalized_ref_cell_vol;
260 }
261 }
262
266 void eval_fval_grad(DataType& fval, Tx& grad, const TgradR& mat_tensor,
267 const TrafoEvaluator& trafo_eval, const SpaceEvaluator& space_eval,
268 const Tx& DOXY(x), const DataType& DOXY(h))
269 {
270 TrafoEvalData trafo_data;
271 SpaceEvalData space_data;
272
273 grad.format(DataType(0));
274 fval = DataType(0);
275
276 DataType fval_frobenius(0);
277 DataType fval_cof(0);
278 DataType fval_det(0);
279 DataType fval_rec_det(0);
280
281 for(int k(0); k < _cubature_rule.get_num_points(); ++k)
282 {
283 // Evaluate trafo and FE space
284 trafo_eval(trafo_data, _cubature_rule.get_point(k));
285 space_eval(space_data, trafo_data);
286 // Compute quantities for nonlinear form
287 set_point(trafo_data, mat_tensor);
288
289 DataType weight(_cubature_rule.get_weight(k));
290
291 if(_compute_frobenius)
292 {
293 fval_frobenius += this->_fac_frobenius*weight*compute_frobenius_part();
294 // The factor jac_det cancels out with the chain rule for the derivative of the test function
295 add_grad_frobenius(grad, space_data, mat_tensor, this->_fac_frobenius*weight);
296 }
297
298 if(_compute_cof)
299 {
300 fval_cof += this->_fac_cof*weight*compute_cof_part();
301 // The factor jac_det cancels out with the chain rule for the derivative of the test function
302 add_grad_cof(grad, space_data, mat_tensor, this->_fac_cof*weight);
303 }
304
305 if(_compute_det)
306 {
307 fval_det += this->_fac_det*weight*compute_det_part();
308 add_grad_det(grad, space_data, mat_tensor, this->_fac_det*weight);
309
310 fval_rec_det += this->_fac_rec_det*weight*compute_rec_det_part();
311 add_grad_rec_det(grad, space_data, mat_tensor, this->_fac_rec_det*weight);
312 }
313
314 }
315
316 fval = fval_frobenius + fval_cof + fval_det + fval_rec_det;
317
318 }
319
323 void eval_fval_cellwise(DataType& fval, const TgradR& mat_tensor,
324 const TrafoEvaluator& trafo_eval, const SpaceEvaluator& space_eval,
325 const Tx& DOXY(x), const DataType& DOXY(h),
326 DataType& fval_frobenius, DataType& fval_cof, DataType& fval_det)
327 {
328
329 TrafoEvalData trafo_data;
330 SpaceEvalData space_data;
331
332 fval = DataType(0);
333 fval_frobenius = DataType(0);
334 fval_cof = DataType(0);
335 fval_det = DataType(0);
336
337 TgradR grad_rec_det(0);
338
339 for(int k(0); k < _cubature_rule.get_num_points(); ++k)
340 {
341 // Evaluate trafo and FE space
342 trafo_eval(trafo_data, _cubature_rule.get_point(k));
343 space_eval(space_data, trafo_data);
344
345 // Compute quantities for nonlinear form
346 set_point(trafo_data, mat_tensor);
347
348 DataType weight(_cubature_rule.get_weight(k));
349
350 if(_compute_frobenius)
351 {
352 fval_frobenius += weight*this->_fac_frobenius*compute_frobenius_part();
353 }
354
355 if(_compute_cof)
356 {
357 fval_cof += weight*this->_fac_cof*compute_cof_part();
358 }
359
360 if(_compute_det)
361 {
362 fval_det += weight*this->_fac_det*compute_det_part();
363 fval_det += weight*this->_fac_rec_det*compute_rec_det_part();
364 }
365
366 }
367
368 fval = fval_frobenius + fval_cof + fval_det;
369
370 }
371
375 void add_grad_frobenius(Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor,
376 const DataType fac)
377 {
378 DataType my_fac(fac*DataType(4)*(Math::sqr(_frobenius_grad_R) - DataType(TgradR::n)));
379 my_fac /= _normalized_ref_cell_vol;
380
381 for(int i(0); i < SpaceEvalData::max_local_dofs; ++i)
382 {
383 for(int d(0); d < world_dim; ++d)
384 {
385 grad[i] += my_fac*(mat_tensor[d]*space_data.phi[i].ref_grad[d])*grad_R;
386 }
387 }
388 }
389
393 void add_grad_cof(Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor, const DataType fac)
394 {
395 DataType my_fac(fac*DataType(4)*(Math::sqr(_frobenius_cof_grad_R) - DataType(TgradR::n)));
396 my_fac /= _normalized_ref_cell_vol;
397
398 TgradR cof_grad_R_transpose(0);
399 cof_grad_R_transpose.set_transpose(cof_grad_R);
400
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(
443 Tx& grad, const SpaceEvalData& space_data, const TgradR& mat_tensor, const DataType fac)
444 {
445 DataType my_fac(-fac/_normalized_ref_cell_vol);
446 if(_exponent_det == 1)
447 {
448 my_fac *= _det_grad_R / Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R));
449 if(_det_grad_R > DataType(0))
450 {
451 my_fac /= (_det_grad_R + Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R)));
452 }
453 else
454 {
455 my_fac /= this->_fac_reg;
456 }
457 }
458 else
459 {
460 my_fac *= DataType(2)*Math::sqr(_det_grad_R) / (Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R));
461 if(_det_grad_R > DataType(0))
462 {
463 my_fac /= Math::sqr(_det_grad_R + Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R)));
464 }
465 else
466 {
467 my_fac /= Math::sqr(this->_fac_reg);
468 }
469 }
470
471 for(int i(0); i < SpaceEvalData::max_local_dofs; ++i)
472 {
473 for(int d(0); d < world_dim; ++d)
474 {
475 grad[i] += my_fac*inv_grad_R*(mat_tensor[d]*space_data.phi[i].ref_grad[d]);
476 }
477 }
478 }
479
483 void add_grad_h_part(Tx& grad, const TgradR& mat_tensor,
484 const TrafoEvaluator& trafo_eval, const SpaceEvaluator& space_eval,
485 const Tx& DOXY(x), const DataType& h, const Tgradh& grad_h)
486 {
487
488 TrafoEvalData trafo_data;
489 SpaceEvalData space_data;
490
491 DataType frobenius_der_h(0);
492 DataType det_der_h(0);
493 DataType rec_det_der_h(0);
494
495 for(int k(0); k < _cubature_rule.get_num_points(); ++k)
496 {
497 // Evaluate trafo and FE space
498 trafo_eval(trafo_data, _cubature_rule.get_point(k));
499 space_eval(space_data, trafo_data);
500
501 // Compute quantities for nonlinear form
502 set_point(trafo_data, mat_tensor);
503
504 DataType weight(_cubature_rule.get_weight(k));
505
506 // Add outer parts of the chain rule derivatives, which are different in every integration point
507 frobenius_der_h += weight*DataType(4)*(Math::sqr(_frobenius_grad_R) - DataType(world_dim))*
508 Math::sqr(_frobenius_grad_R)/_normalized_ref_cell_vol;
509
510 det_der_h += weight*_det_grad_R/_normalized_ref_cell_vol;
511
512 DataType fac;
513 if(_det_grad_R >= DataType(0))
514 {
515 fac = Math::sqrt(Math::sqr(this->_fac_reg) + Math::sqr(_det_grad_R));
516 }
517 else
518 {
519 fac = this->_fac_reg;
520 }
521
522 rec_det_der_h += weight*_det_grad_R/(fac*(_det_grad_R + fac))/_normalized_ref_cell_vol;
523
524 }
525
526 // The inner part of the chain rule derivative is constant wrt. to space, so we can just scale at this
527 // point
528 frobenius_der_h *= this->_fac_frobenius*DataType(-1)/h;
529 det_der_h *= this->_fac_det*DataType(-2)/h;
530 rec_det_der_h *= this->_fac_rec_det*DataType(2)/h;
531
532 DataType der_h(frobenius_der_h + det_der_h + rec_det_der_h);
533
534 // Add the local contributions to the global gradient
535 for(int i(0); i < Tx::m; ++i)
536 {
537 for(int d(0); d < Tx::n; ++d)
538 {
539 grad(i,d) += der_h*grad_h(i*Tx::n + d);
540 }
541 }
542 } // add_grad_h_part
543
544 }; // class RumpfFunctional
545#ifdef FEAT_EICKT
546 extern template class RumpfFunctional<double,
547 Trafo::Standard::Mapping<Geometry::ConformalMesh<Shape::Hypercube<2>, 2, double>>>;
548
549 extern template class RumpfFunctional<double,
550 Trafo::Standard::Mapping<Geometry::ConformalMesh<Shape::Hypercube<3>, 3, double>>>;
551#endif // FEAT_EICKT
553 } // namespace Meshopt
554} // 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