FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
velocity_analyser.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
8#include <kernel/assembly/asm_traits.hpp>
9#include <kernel/lafem/dense_vector.hpp>
10#include <kernel/lafem/dense_vector_blocked.hpp>
11#include <kernel/lafem/power_vector.hpp>
12#include <kernel/util/tiny_algebra.hpp>
13#include <kernel/util/dist.hpp>
14
15namespace FEAT
16{
17 namespace Assembly
18 {
20 namespace Intern
21 {
22 template<typename Vector_>
23 struct MultiGather;
24 } // namespace Intern
26
35 template<typename DataType_, int dim_>
37 {
39 static constexpr int dim = dim_;
40
47 DataType_ norm_h0;
48
55 DataType_ norm_h1;
56
63 DataType_ divergence;
64
71 DataType_ vorticity;
72
79
86
89 norm_h0(DataType_(0)),
90 norm_h1(DataType_(0)),
91 divergence(DataType_(0)),
92 vorticity(DataType_(0)),
93 norm_h0_comp(DataType_(0)),
94 norm_h1_comp(DataType_(0))
95 {
96 }
97
107 void synchronize(const Dist::Comm& comm)
108 {
109 DataType_ verr[2*dim_+4] =
110 {
115 };
116 for(int i(0); i < dim_; ++i)
117 {
118 verr[4+ i] = Math::sqr(norm_h0_comp[i]);
119 verr[4+dim_+i] = Math::sqr(norm_h1_comp[i]);
120 }
121
122 comm.allreduce(verr, verr, std::size_t(2*dim_+4), Dist::op_sum);
123
124 norm_h0 = Math::sqrt(verr[0]);
125 norm_h1 = Math::sqrt(verr[1]);
126 divergence = Math::sqrt(verr[2]);
127 vorticity = Math::sqrt(verr[3]);
128 for(int i(0); i < dim_; ++i)
129 {
130 norm_h0_comp[i] = Math::sqrt(verr[4+ i]);
131 norm_h1_comp[i] = Math::sqrt(verr[4+dim_+i]);
132 }
133 }
134
135
151 String format_string(int precision = 0, std::size_t pad_size = 10u, char pad_char = '.') const
152 {
153 String s;
154 s += String("H0-Norm").pad_back(pad_size, pad_char) + ": " + stringify_fp_sci(norm_h0, precision) + " [";
155 for(int i(0); i < dim_; ++i)
156 (s += " ") += stringify_fp_sci(norm_h0_comp[i], precision);
157 s += " ]\n";
158 s += String("H1-Norm").pad_back(pad_size, pad_char) + ": " + stringify_fp_sci(norm_h1, precision) + " [";
159 for(int i(0); i < dim_; ++i)
160 (s += " ") += stringify_fp_sci(norm_h1_comp[i], precision);
161 s += " ]\n";
162 s += String("Divergence").pad_back(pad_size, pad_char) + ": " + stringify_fp_sci(divergence, precision) + "\n";
163 s += String("Vorticity").pad_back(pad_size, pad_char) + ": " + stringify_fp_sci(vorticity, precision) + "\n";
164 return s;
165 }
166
168 friend std::ostream& operator<<(std::ostream& os, const VelocityInfo& vi)
169 {
170 // print H0-norms
171 os << "H0-Norm...: " << stringify_fp_sci(vi.norm_h0) << " [";
172 for(int i(0); i < dim_; ++i)
173 os << " " << stringify_fp_sci(vi.norm_h0_comp[i]);
174 os << " ]\n";
175
176 // print H1-norms
177 os << "H1-Norm...: " << stringify_fp_sci(vi.norm_h1) << " [";
178 for(int i(0); i < dim_; ++i)
179 os << " " << stringify_fp_sci(vi.norm_h1_comp[i]);
180 os << " ]\n";
181
182 // print divergence and vorticity norms
183 os << "Divergence: " << stringify_fp_sci(vi.divergence) << "\n";
184 os << "Vorticity.: " << stringify_fp_sci(vi.vorticity) << "\n";
185
186 return os;
187 }
188 }; // struct VelocityInfo
189
198 {
199 private:
201 template<typename DT_, int sm_, int sn_>
202 static DT_ calc_vorticity(const Tiny::Matrix<DT_, 2, 2, sm_, sn_>& jac)
203 {
204 // 2D: (dx u2 - dy u1)^2
205 // J_ij = d/d_j f_i ==> (J_01 - J_10)^2
206 return Math::sqr(jac[1][0] - jac[0][1]);
207 }
208
209 template<typename DT_, int sm_, int sn_>
210 static DT_ calc_vorticity(const Tiny::Matrix<DT_, 3, 3, sm_, sn_>& jac)
211 {
212 // 3D: (dy u3 - dz u2)^2 + (dz u1 - dx u3)^2 + (dx u2 - dy u1)
213 return
214 Math::sqr(jac[2][1] - jac[1][2]) + // dy u3 - dz u2 = J_21 - J_12
215 Math::sqr(jac[0][2] - jac[2][0]) + // dz u1 - dx u3 = J_02 - J_20
216 Math::sqr(jac[1][0] - jac[0][1]); // dx u2 - dy u1 = J_10 - J_01
217 }
219
220 public:
236 template<typename DataType_, typename IndexType_, int dim_, typename Space_>
239 const Space_& space, const String& cubature_name)
240 {
241 Cubature::DynamicFactory cubature_factory(cubature_name);
242 return compute(vector, space, cubature_factory);
243 }
244
260 template<typename DataType_, typename IndexType_, int dim_, typename Space_>
263 const Space_& space, const Cubature::DynamicFactory& cubature_factory)
264 {
265 // first of all, verify the dimensions
266 static_assert(Space_::shape_dim == dim_, "invalid velocity field dimension");
267
269 typedef Space_ SpaceType;
270
272
275
277 typedef typename AsmTraits::DataType DataType;
278
279 // create the cubature rule
280 typename AsmTraits::CubatureRuleType cubature_rule(Cubature::ctor_factory, cubature_factory);
281
282 // fetch the trafo
283 const typename AsmTraits::TrafoType& trafo = space.get_trafo();
284
285 // create a trafo evaluator
286 typename AsmTraits::TrafoEvaluator trafo_eval(trafo);
287
288 // create a space evaluator and evaluation data
289 typename AsmTraits::SpaceEvaluator space_eval(space);
290 typedef typename AsmTraits::SpaceEvaluator SpaceEvaluator;
291
292 // create a dof-mapping
293 typename AsmTraits::DofMapping dof_mapping(space);
294
295 // create trafo evaluation data
296 typename AsmTraits::TrafoEvalData trafo_data;
297
298 // create space evaluation data
299 typename AsmTraits::SpaceEvalData space_data;
300
301 // create matrix scatter-axpy
302 Intern::MultiGather<VectorType> multi_gather(vector);
303
304 // initialize result
306
307 // local velocity values
309
310 // vector field values
312
313 // vector field derivatives
315
316 // loop over all cells of the mesh
317 for(typename AsmTraits::CellIterator cell(trafo_eval.begin()); cell != trafo_eval.end(); ++cell)
318 {
319 // initialize dof-mapping
320 dof_mapping.prepare(cell);
321
322 // fetch local basis values
323 basis_val.format();
324 multi_gather.gather(basis_val, dof_mapping);
325
326 // finish dof-mapping
327 dof_mapping.finish();
328
329 // prepare trafo evaluator
330 trafo_eval.prepare(cell);
331
332 // prepare space evaluator
333 space_eval.prepare(trafo_eval);
334
335 // fetch number of local dofs
336 int num_loc_dofs = space_eval.get_num_local_dofs();
337
338 // loop over all quadrature points and integrate
339 for(int k(0); k < cubature_rule.get_num_points(); ++k)
340 {
341 // compute trafo data
342 trafo_eval(trafo_data, cubature_rule.get_point(k));
343
344 // compute basis function data
345 space_eval(space_data, trafo_data);
346
347 // compute basis function values and derivatives
348 val.format();
349 jac.format();
350 for(int i(0); i < num_loc_dofs; ++i)
351 {
352 for(int bi(0); bi < dim_; ++bi)
353 {
354 val[bi] += basis_val[bi][i] * space_data.phi[i].value;
355 // J_ij = d/d_j f_i <==> J = (f_1,...,f_n)^T * (d/d_1, ..., d/d_n)
356 for(int bj(0); bj < dim_; ++bj)
357 {
358 // J_ij = d/d_j f_i
359 jac[bi][bj] += basis_val[bi][i] * space_data.phi[i].grad[bj];
360 }
361 }
362 }
363
364 // compute integration weight
365 DataType omega = trafo_data.jac_det * cubature_rule.get_weight(k);
366
367 // update info
368 for(int i(0); i < dim_; ++i)
369 {
370 // update H0 component norm
371 info.norm_h0_comp[i] += omega * Math::sqr(val[i]);
372
373 // update H1 component norm
374 info.norm_h1_comp[i] += omega * Tiny::dot(jac[i], jac[i]);
375 }
376
377 // update divergence
378 info.divergence += omega * Math::sqr(jac.trace());
379
380 // update vorticity
381 info.vorticity += omega * calc_vorticity(jac);
382
383 // continue with next cubature point
384 }
385
386 // finish evaluators
387 space_eval.finish();
388 trafo_eval.finish();
389
390 // continue with next cell
391 }
392
393 // finally, compute the rest
394 for(int i(0); i < dim_; ++i)
395 {
396 info.norm_h0 += info.norm_h0_comp[i];
397 info.norm_h1 += info.norm_h1_comp[i];
398 info.norm_h0_comp[i] = Math::sqrt(info.norm_h0_comp[i]);
399 info.norm_h1_comp[i] = Math::sqrt(info.norm_h1_comp[i]);
400 }
401
402 // take the roots
403 info.norm_h0 = Math::sqrt(info.norm_h0);
404 info.norm_h1 = Math::sqrt(info.norm_h1);
405 info.divergence = Math::sqrt(info.divergence);
406 info.vorticity = Math::sqrt(info.vorticity);
407
408 // okay
409 return info;
410 }
411
427 template<typename DataType_, typename IndexType_, int dim_, typename Space_>
430 const Space_& space, const String& cubature_name)
431 {
432 Cubature::DynamicFactory cubature_factory(cubature_name);
433 return compute(vector, space, cubature_factory);
434 }
435
451 template<typename DataType_, typename IndexType_, int dim_, typename Space_>
454 const Space_& space, const Cubature::DynamicFactory& cubature_factory)
455 {
456 // first of all, verify the dimensions
457 static_assert(Space_::shape_dim == dim_, "invalid velocity field dimension");
458
459 // validate vector dimensions
460 XASSERTM(vector.size() == space.get_num_dofs(), "invalid vector size");
461
463 typedef Space_ SpaceType;
464
466
469
471 typedef typename AsmTraits::DataType DataType;
472
473 // create the cubature rule
474 typename AsmTraits::CubatureRuleType cubature_rule(Cubature::ctor_factory, cubature_factory);
475
476 // fetch the trafo
477 const typename AsmTraits::TrafoType& trafo = space.get_trafo();
478
479 // create a trafo evaluator
480 typename AsmTraits::TrafoEvaluator trafo_eval(trafo);
481
482 // create a space evaluator and evaluation data
483 typename AsmTraits::SpaceEvaluator space_eval(space);
484 typedef typename AsmTraits::SpaceEvaluator SpaceEvaluator;
485
486 // create a dof-mapping
487 typename AsmTraits::DofMapping dof_mapping(space);
488
489 // create trafo evaluation data
490 typename AsmTraits::TrafoEvalData trafo_data;
491
492 // create space evaluation data
493 typename AsmTraits::SpaceEvalData space_data;
494
495 // create matrix scatter-axpy
496 typename VectorType::GatherAxpy gather(vector);
497
498 // initialize result
500
501 // local velocity values
502 Tiny::Vector<Tiny::Vector<DataType, dim_>, SpaceEvaluator::max_local_dofs> basis_val;
503
504 // vector field value
506
507 // vector field first derivatives as jacobian matrix
509
510 // loop over all cells of the mesh
511 for(typename AsmTraits::CellIterator cell(trafo_eval.begin()); cell != trafo_eval.end(); ++cell)
512 {
513 // initialize dof-mapping
514 dof_mapping.prepare(cell);
515
516 // fetch local basis values
517 basis_val.format();
518 gather(basis_val, dof_mapping);
519
520 // finish dof-mapping
521 dof_mapping.finish();
522
523 // prepare trafo evaluator
524 trafo_eval.prepare(cell);
525
526 // prepare space evaluator
527 space_eval.prepare(trafo_eval);
528
529 // fetch number of local dofs
530 const int num_loc_dofs = space_eval.get_num_local_dofs();
531
532 // loop over all quadrature points and integrate
533 for(int k(0); k < cubature_rule.get_num_points(); ++k)
534 {
535 // compute trafo data
536 trafo_eval(trafo_data, cubature_rule.get_point(k));
537
538 // compute basis function data
539 space_eval(space_data, trafo_data);
540
541 // compute basis function values and derivatives
542 val.format();
543 jac.format();
544 for(int i(0); i < num_loc_dofs; ++i)
545 {
546 val.axpy(space_data.phi[i].value, basis_val[i]);
547 // J_ij = d/d_j f_i <==> J = (f_1,...,f_n)^T * (d/d_1, ..., d/d_n)
548 jac.add_outer_product(basis_val[i], space_data.phi[i].grad);
549 }
550
551 // compute integration weight
552 const DataType omega = trafo_data.jac_det * cubature_rule.get_weight(k);
553
554 // update norms
555 for(int i(0); i < dim_; ++i)
556 {
557 // update H0 component norm
558 info.norm_h0_comp[i] += omega * Math::sqr(val[i]);
559
560 // update H1 component norm
561 info.norm_h1_comp[i] += omega * Tiny::dot(jac[i], jac[i]);
562 }
563
564 // update divergence
565 info.divergence += omega * Math::sqr(jac.trace());
566
567 // update vorticity
568 info.vorticity += omega * calc_vorticity(jac);
569
570 // continue with next cubature point
571 }
572
573 // finish evaluators
574 space_eval.finish();
575 trafo_eval.finish();
576
577 // continue with next cell
578 }
579
580 // finally, compute the rest
581 for(int i(0); i < dim_; ++i)
582 {
583 info.norm_h0 += info.norm_h0_comp[i];
584 info.norm_h1 += info.norm_h1_comp[i];
585 info.norm_h0_comp[i] = Math::sqrt(info.norm_h0_comp[i]);
586 info.norm_h1_comp[i] = Math::sqrt(info.norm_h1_comp[i]);
587 }
588
589 // take the roots
590 info.norm_h0 = Math::sqrt(info.norm_h0);
591 info.norm_h1 = Math::sqrt(info.norm_h1);
592 info.divergence = Math::sqrt(info.divergence);
593 info.vorticity = Math::sqrt(info.vorticity);
594
595 // okay
596 return info;
597 }
598 }; // class VelocityAnalyser
599
601 namespace Intern
602 {
603 template<typename DT_, typename IT_, int dim_>
604 struct MultiGather<LAFEM::PowerVector<LAFEM::DenseVector<DT_, IT_>, dim_> >
605 {
606 typedef MultiGather<LAFEM::PowerVector<LAFEM::DenseVector<DT_, IT_>, dim_-1> > RestClass;
607
608 typename LAFEM::DenseVector<DT_, IT_>::GatherAxpy _first_gather;
609 RestClass _rest_gather;
610
611 MultiGather(const LAFEM::PowerVector<LAFEM::DenseVector<DT_, IT_>, dim_>& vector) :
612 _first_gather(vector.first()), _rest_gather(vector.rest())
613 {
614 }
615
616 template<int m_, int n_, int sm_, int sn_, typename DofMapping_>
617 void gather(
618 Tiny::Matrix<DT_, m_, n_, sm_, sn_>& vals,
619 const DofMapping_& dof_mapping,
620 int offset = 0)
621 {
622 _first_gather(vals[offset], dof_mapping);
623 _rest_gather.gather(vals, dof_mapping, offset+1);
624 }
625 };
626
627 template<typename DT_, typename IT_>
628 struct MultiGather<LAFEM::PowerVector<LAFEM::DenseVector<DT_, IT_>, 1> >
629 {
630 typename LAFEM::DenseVector<DT_, IT_>::GatherAxpy _first_gather;
631
632 MultiGather(const LAFEM::PowerVector<LAFEM::DenseVector<DT_, IT_>, 1>& vector) :
633 _first_gather(vector.first())
634 {
635 }
636
637 template<int m_, int n_, int sm_, int sn_, typename DofMapping_>
638 void gather(
639 Tiny::Matrix<DT_, m_, n_, sm_, sn_>& vals,
640 const DofMapping_& dof_mapping,
641 int offset = 0)
642 {
643 _first_gather(vals[offset], dof_mapping);
644 }
645 };
646 } // namespace Intern
648 } // namespace Assembly
649} // namespace FEAT
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Common single-space assembly traits class template.
Definition: asm_traits.hpp:83
Velocity field analyser class.
static VelocityInfo< DataType_, dim_ > compute(const LAFEM::PowerVector< LAFEM::DenseVector< DataType_, IndexType_ >, dim_ > &vector, const Space_ &space, const String &cubature_name)
Performs the analysis of a velocity field.
static VelocityInfo< DataType_, dim_ > compute(const LAFEM::DenseVectorBlocked< DataType_, IndexType_, dim_ > &vector, const Space_ &space, const Cubature::DynamicFactory &cubature_factory)
Performs the analysis of a velocity field.
static VelocityInfo< DataType_, dim_ > compute(const LAFEM::DenseVectorBlocked< DataType_, IndexType_, dim_ > &vector, const Space_ &space, const String &cubature_name)
Performs the analysis of a velocity field.
static VelocityInfo< DataType_, dim_ > compute(const LAFEM::PowerVector< LAFEM::DenseVector< DataType_, IndexType_ >, dim_ > &vector, const Space_ &space, const Cubature::DynamicFactory &cubature_factory)
Performs the analysis of a velocity field.
Communicator class.
Definition: dist.hpp:1349
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
Definition: dist.cpp:655
Gather-Axpy operation for DenseVector.
Blocked Dense data vector class template.
Index size() const
The number of elements.
Dense data vector class template.
Power-Vector meta class template.
String class implementation.
Definition: string.hpp:46
String pad_back(size_type len, char c=' ') const
Pads the back of the string up to a desired length.
Definition: string.hpp:415
Tiny Matrix class template.
CUDA_HOST_DEVICE Matrix & add_outer_product(const Vector< T_, m_, snx_ > &x, const Vector< T_, n_, sny_ > &y, const DataType alpha=DataType(1))
Adds the outer product of two vectors onto the matrix.
CUDA_HOST_DEVICE DataType trace() const
Returns the trace of the matrix.
CUDA_HOST_DEVICE void format(DataType alpha=DataType(0))
Formats the matrix.
Tiny Vector class template.
CUDA_HOST_DEVICE void format(DataType alpha=DataType(0))
Formats the vector.
CUDA_HOST_DEVICE Vector & axpy(DataType alpha, const Vector< T_, n_, snx_ > &x)
Adds another scaled vector onto this vector.
const Operation op_sum(MPI_SUM)
Operation wrapper for MPI_SUM.
Definition: dist.hpp:271
T_ sqrt(T_ x)
Returns the square-root of a value.
Definition: math.hpp:300
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_fp_sci(DataType_ value, int precision=0, int width=0, bool sign=false)
Prints a floating point value to a string in scientific notation.
Definition: string.hpp:1088
Velocity field information structure.
String format_string(int precision=0, std::size_t pad_size=10u, char pad_char='.') const
Formats the velocity information as a string.
Tiny::Vector< DataType_, dim_ > norm_h0_comp
Velocity field components H0-norm.
DataType_ norm_h0
Velocity field H0-norm.
DataType_ norm_h1
Velocity field H1-semi-norm.
DataType_ vorticity
Velocity field vorticity H0-norm.
friend std::ostream & operator<<(std::ostream &os, const VelocityInfo &vi)
prints the info to an output stream
static constexpr int dim
The dimension of the analysed velocity field.
Tiny::Vector< DataType_, dim_ > norm_h1_comp
Velocity field components H1-semi-norm.
DataType_ divergence
Velocity field divergence H0-norm.
void synchronize(const Dist::Comm &comm)
Synchronizes the velocity information over a communicator.