Plugins
Loading...
Searching...
No Matches
ls_volume_impl.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015: G-CSC, Goethe University Frankfurt
3 * Authors: Christian Wehner, Dmitry Logashenko
4 *
5 * This file is part of UG4.
6 *
7 * UG4 is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License version 3 (as published by the
9 * Free Software Foundation) with the following additional attribution
10 * requirements (according to LGPL/GPL v3 §7):
11 *
12 * (1) The following notice must be displayed in the Appropriate Legal Notices
13 * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 *
15 * (2) The following notice must be displayed at a prominent place in the
16 * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 *
18 * (3) The following bibliography is recommended for citation and must be
19 * preserved in all covered files:
20 * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 * parallel geometric multigrid solver on hierarchically distributed grids.
22 * Computing and visualization in science 16, 4 (2013), 151-164"
23 * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 * flexible software system for simulating pde based models on high performance
25 * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU Lesser General Public License for more details.
31 */
32
38#ifdef UG_PARALLEL
40#endif
41
42namespace ug{
43namespace LevelSet{
44
45/*---- Class 'LSVolume': ----*/
46
51template <typename TGridFunc>
53(
54 const char * ss_names
55)
56{
57 m_ssGrp.set_subset_handler (m_spLSF->domain()->subset_handler ());
58 m_ssGrp.add (TokenizeString (ss_names));
59}
60
64template <typename TGridFunc>
66{
67// The full-dim. grid element types for this dimension:
68 typedef typename domain_traits<dim>::DimElemList ElemList;
69
70 const int n_ss = m_spLSF->num_subsets ();
71
72// sum up all the volumes
73 m_volume_plus = m_volume_minus = 0;
74 m_ss_vol_plus.resize (n_ss); m_ss_vol_minus.resize (n_ss);
75 for (int si = 0; si < n_ss; si++) m_ss_vol_plus[si] = m_ss_vol_minus[si] = 0;
76 boost::mpl::for_each<ElemList> (AddVolumes (this));
77
78#ifdef UG_PARALLEL
79 allreduce_volumes ();
80#endif
81}
82
86template <typename TGridFunc>
88(
90 number time
91)
92{
93// The full-dim. grid element types for this dimension:
94 typedef typename domain_traits<dim>::DimElemList ElemList;
95
96 const int n_ss = m_spLSF->num_subsets ();
97
98// sum up all the volumes
99 m_volume_plus = m_volume_minus = 0;
100 m_ss_vol_plus.resize (n_ss); m_ss_vol_minus.resize (n_ss);
101 for (int si = 0; si < n_ss; si++) m_ss_vol_plus[si] = m_ss_vol_minus[si] = 0;
102 boost::mpl::for_each<ElemList> (AddWeightedVolumes (this, spDensity.get (), time));
103
104#ifdef UG_PARALLEL
105 allreduce_volumes ();
106#endif
107}
108
112template <typename TGridFunc>
113template <typename TElem>
115{
116 typedef typename grid_func_type::template traits<TElem>::const_iterator ElemIter;
118
119 static const size_t num_corners = ref_elem_t::numCorners;
120
121 const grid_func_type & lsf = * m_spLSF;
122 const position_accessor_type & aaPos = lsf.domain()->position_accessor ();
123 std::vector<DoFIndex> ind (1);
124 MathVector<dim> corners [num_corners];
125 number lsf_values [num_corners];
126
127 for (int si = 0; si < lsf.num_subsets (); si++)
128 {
129 if (m_ssGrp.subset_handler().valid () && ! m_ssGrp.contains (si))
130 continue; // skip this subset: it is not mentioned in the specified list
131
132 number ss_vol_plus = 0, ss_vol_minus = 0;
133 ElemIter iterEnd = lsf.template end<TElem> (si);
134 for (ElemIter iter = lsf.template begin<TElem> (si); iter != iterEnd; ++iter)
135 {
136 TElem * elem = *iter;
137
138 // get the corner coordinates ans the values of the LSF
139 for (size_t i = 0; i < num_corners; i++)
140 {
141 Vertex * vrt = elem->vertex (i);
142 corners [i] = aaPos [vrt];
143 if (lsf.inner_dof_indices (vrt, 0, ind) != 1)
144 UG_THROW ("LSVolume: Not a scalar grid function for the LSF!");
145 lsf_values [i] = DoFRef (lsf, ind [0]);
146 }
147
148 // compute the volumes
149 number vol_plus, vol_minus;
150 LSElementSize<ref_elem_t, dim>::compute (corners, lsf_values, vol_plus, vol_minus);
151
152 // add them to the total volumes
153 m_volume_plus += vol_plus; m_volume_minus += vol_minus;
154
155 // add them to the subset
156 ss_vol_plus += vol_plus; ss_vol_minus += vol_minus;
157
158 // check the positivity (if requested)
159 if (m_check_positivity && (vol_plus < 0 || vol_minus < 0))
160 {
161 UG_LOG ("Warning in LSVolume: V+ = " << vol_plus << " < 0 or V- = "
162 << vol_minus << " < 0\n");
163 for (size_t i = 0; i < num_corners; i++)
164 {
165 UG_LOG (" - corner[" << i << "] = " << corners[i]
166 << ", grid_data_index = " << elem->vertex(i)->grid_data_index ()
167 << ", lsf = " << lsf_values[i] << '\n');
168 }
169 }
170
171 /*-- For debugging only: --*
172 number test_vol_plus, test_vol_minus;
173 for (size_t i = 0; i < num_corners; i++)
174 lsf_values [i] = - lsf_values [i];
175 LSElementSize<ref_elem_t, dim>::compute (corners, lsf_values, test_vol_minus, test_vol_plus);
176 if (test_vol_minus < 0 || test_vol_plus < 0 || vol_minus < 0 || vol_plus < 0
177 || std::abs (test_vol_minus - vol_minus) / (vol_plus + vol_minus) >= 1e-12
178 || std::abs (test_vol_plus - vol_plus) / (vol_plus + vol_minus) >= 1e-12)
179 {
180 UG_LOG ("---- LSVolume: Inconsistent values of the volumes for elem id " << elem->grid_data_index () << ":\n");
181 UG_LOG ("-- V_(-) = " << vol_minus << " or " << test_vol_minus << ", diff = " << vol_minus - test_vol_minus << "\n");
182 UG_LOG ("-- V_(+) = " << vol_plus << " or " << test_vol_plus << ", diff = " << vol_plus - test_vol_plus << "\n");
183 for (size_t i = 0; i < num_corners; i++)
184 {
185 UG_LOG ("-- co " << i << ": " << corners[i] << ", lsf = " << - lsf_values [i] << "\n");
186 }
187 UG_THROW ("LSVolume: Inaccurate computation of the volumes.");
188 }
189 *--*/
190 }
191 m_ss_vol_plus[si] += ss_vol_plus; m_ss_vol_minus[si] += ss_vol_minus;
192 }
193}
194
198template <typename TGridFunc>
199template <typename TElem>
201(
202 UserData<number, dim> * pDensity,
203 number time
204)
205{
206 typedef typename grid_func_type::template traits<TElem>::const_iterator ElemIter;
208
209 static const size_t num_corners = ref_elem_t::numCorners;
210
211 const grid_func_type & lsf = * m_spLSF;
212 const position_accessor_type & aaPos = lsf.domain()->position_accessor ();
213 std::vector<DoFIndex> ind (1);
214 MathVector<dim> corners [num_corners], midpoint;
215 number lsf_values [num_corners];
216
217 for (int si = 0; si < lsf.num_subsets (); si++)
218 {
219 if (m_ssGrp.subset_handler().valid () && ! m_ssGrp.contains (si))
220 continue; // skip this subset: it is not mentioned in the specified list
221
222 number ss_vol_plus = 0, ss_vol_minus = 0;
223 ElemIter iterEnd = lsf.template end<TElem> (si);
224 for (ElemIter iter = lsf.template begin<TElem> (si); iter != iterEnd; ++iter)
225 {
226 TElem * elem = *iter;
227
228 // get the corner coordinates ans the values of the LSF
229 midpoint = 0;
230 for (size_t i = 0; i < num_corners; i++)
231 {
232 Vertex * vrt = elem->vertex (i);
233 midpoint += (corners [i] = aaPos [vrt]);
234 if (lsf.inner_dof_indices (vrt, 0, ind) != 1)
235 UG_THROW ("LSVolume: Not a scalar grid function for the LSF!");
236 lsf_values [i] = DoFRef (lsf, ind [0]);
237 }
238 midpoint /= num_corners;
239
240 // compute the volumes
241 number vol_plus, vol_minus;
242 LSElementSize<ref_elem_t, dim>::compute (corners, lsf_values, vol_plus, vol_minus);
243
244 // compute the weight
245 number density;
246 (* pDensity) (density, midpoint, time, si);
247 vol_plus *= density; vol_minus *= density;
248
249 // add them to the total volumes
250 m_volume_plus += vol_plus; m_volume_minus += vol_minus;
251
252 // add them to the subset
253 ss_vol_plus += vol_plus; ss_vol_minus += vol_minus;
254
255 // check the positivity (if requested)
256 if (m_check_positivity && (vol_plus < 0 || vol_minus < 0))
257 {
258 UG_LOG ("Warning in LSVolume: V+ = " << vol_plus << " < 0 or V- = "
259 << vol_minus << " < 0\n");
260 for (size_t i = 0; i < num_corners; i++)
261 {
262 UG_LOG (" - corner[" << i << "] = " << corners[i]
263 << ", grid_data_index = " << elem->vertex(i)->grid_data_index ()
264 << ", lsf = " << lsf_values[i] << '\n');
265 }
266 }
267 }
268 m_ss_vol_plus[si] += ss_vol_plus; m_ss_vol_minus[si] += ss_vol_minus;
269 }
270}
271
272#ifdef UG_PARALLEL
276template <typename TGridFunc>
278{
280 m_volume_minus = procComm.allreduce (m_volume_minus, PCL_RO_SUM);
281 m_volume_plus = procComm.allreduce (m_volume_plus, PCL_RO_SUM);
282
283 const int n_ss = m_spLSF->num_subsets ();
284 for (int si = 0; si < n_ss; si++)
285 {
286 m_ss_vol_minus[si] = procComm.allreduce (m_ss_vol_minus[si], PCL_RO_SUM);
287 m_ss_vol_plus[si] = procComm.allreduce (m_ss_vol_plus[si], PCL_RO_SUM);
288 }
289}
290#endif
291
295template <typename TGridFunc>
297(
298 const char * ss_names,
299 number & vol_plus,
300 number & vol_minus
301) const
302{
303 SubsetGroup ss_grp (m_spLSF->domain()->subset_handler ());
304 ss_grp.add (TokenizeString (ss_names));
305
306 vol_plus = vol_minus = 0;
307 for (size_t i = 0; i < ss_grp.size (); i++)
308 {
309 int si = ss_grp [i];
310 vol_plus += m_ss_vol_plus[si];
311 vol_minus += m_ss_vol_minus[si];
312 }
313}
314
318template <typename TGridFunc>
320{
321 ConstSmartPtr<domain_type> spDom = m_spLSF->domain ();
322
323 UG_LOG ("Volumes of the subset:\n" << std::fixed);
324 number vol_plus = 0, vol_minus = 0;
325 for (int si = 0; si < m_spLSF->num_subsets (); si++)
326 {
327 vol_plus += m_ss_vol_plus[si]; vol_minus += m_ss_vol_minus[si];
328 UG_LOG (spDom->subset_handler()->get_subset_name (si) << " (" << si
329 << "): V(+) = " << m_ss_vol_plus[si] << ", V(-) = " << m_ss_vol_minus[si] << "\n");
330 }
331 UG_LOG ("Totally: V(+) = " << vol_plus << ", V(-) = " << vol_minus << "\n");
332}
333
334/*---- Class 'LSElementSize': ----*/
335
339template <int WDim>
341(
342 const MathVector<WDim> * corner,
343 const number * lsf,
344 number & vol_plus,
345 number & vol_minus
346)
347{
348 number vol_0, vol_1;
349 int r;
350
351 if (lsf[0] * lsf[1] > 0)
352 {
353 vol_0 = ElementSize<ref_element_type, dim> (corner);
354 vol_1 = 0;
355 r = 1;
356 }
357 else
358 {
359 number t = lsf[1] / (lsf[1] - lsf[0]);
360 MathVector<dim> pnt[3];
361 pnt[0] = corner[0];
362 VecScaleAdd (pnt[1], t, corner[0], 1 - t, corner[1]);
363 pnt[2] = corner[1];
364 vol_0 = ElementSize<ref_element_type, dim> (pnt);
365 vol_1 = ElementSize<ref_element_type, dim> (pnt + 1);
366 r = 0;
367 }
368
369 if (lsf[0] >= 0)
370 {
371 vol_plus = vol_0; vol_minus = vol_1;
372 }
373 else
374 {
375 vol_minus = vol_0; vol_plus = vol_1; r = - r;
376 }
377 return r;
378}
379
383template <int WDim>
385(
386 const MathVector<WDim> * corner,
387 const number * lsf,
388 number & vol_plus,
389 number & vol_minus
390)
391{
392 number vol = ElementSize<ref_element_type, dim> (corner);
393
394// look for 'positive' and 'negative' corners
395 int i_pos = -1, i_neg = -1;
396 size_t num_neg = 0;
397 for (int i = 0; i < 3; i++)
398 if (lsf[i] < 0)
399 {
400 i_neg = i;
401 num_neg++;
402 }
403 else
404 i_pos = i;
405
406// check if all are positive or all are negative
407 if (num_neg == 0)
408 {
409 vol_plus = vol; vol_minus = 0;
410 return 1;
411 }
412 if (num_neg == 3)
413 {
414 vol_plus = 0; vol_minus = vol;
415 return -1;
416 }
417
418// look for the cut corner
419 int i_0 = (num_neg == 1)? i_neg : i_pos;
420 int i_1 = (i_0 + 1) % 3, i_2 = (i_0 + 2) % 3;
421
422// compose a new triangle
423 number t;
424 MathVector<dim> cut_tri [3];
425 cut_tri [0] = corner [i_0];
426 t = lsf[i_1] / (lsf[i_1] - lsf[i_0]);
427 VecScaleAdd (cut_tri [1], t, corner[i_0], 1 - t, corner[i_1]);
428 t = lsf[i_2] / (lsf[i_2] - lsf[i_0]);
429 VecScaleAdd (cut_tri [2], t, corner[i_0], 1 - t, corner[i_2]);
430
431// get the cut volume
432 number cut_vol = ElementSize<ReferenceTriangle, dim> (cut_tri);
433
434// get the volumes
435 if (i_0 == i_neg) // i_0 is either i_pos or i_neg
436 {
437 vol_minus = cut_vol; vol_plus = vol - cut_vol;
438 }
439 else
440 {
441 vol_plus = cut_vol; vol_minus = vol - cut_vol;
442 }
443 return 0;
444}
445
449template <int WDim>
451(
452 const MathVector<WDim> * corner,
453 const number * lsf,
454 number & vol_plus,
455 number & vol_minus
456)
457{
458 number vol = ElementSize<ref_element_type, dim> (corner);
459
460// look for 'positive' and 'negative' corners
461 int i_pos[2], i_neg[2];
462 i_pos[0] = -1; i_pos[1] = -1;
463 i_neg[0] = -1; i_neg[1] = -1;
464 size_t num_neg = 0;
465 for (int i = 0; i < 4; i++)
466 if (lsf[i] < 0)
467 {
468 if (i_neg[0] < 0) i_neg[0] = i; else i_neg[1] = i;
469 num_neg++;
470 }
471 else
472 {
473 if (i_pos[0] < 0) i_pos[0] = i; else i_pos[1] = i;
474 }
475
476// check if all are positive or all are negative
477 if (num_neg == 0)
478 {
479 vol_plus = vol; vol_minus = 0;
480 return 1;
481 }
482 if (num_neg == 4)
483 {
484 vol_plus = 0; vol_minus = vol;
485 return -1;
486 }
487
488// if only one corner is cut out
489 if (num_neg == 1 || num_neg == 3)
490 {
491 int i_0 = (num_neg == 1)? i_neg[0] : i_pos[0];
492 MathVector<dim> cut_tet [4];
493 for (int i = 0; i < 4; i++)
494 if (i == i_0)
495 cut_tet [i] = corner [i];
496 else
497 {
498 number t = lsf[i] / (lsf[i] - lsf[i_0]);
499 VecScaleAdd (cut_tet [i], t, corner[i_0], 1 - t, corner[i]);
500 }
501 // Note: The orientation of cut_tet should be the same as for the original shape, i.e. correct.
502 number cut_vol = ElementSize<ReferenceTetrahedron, dim> (cut_tet);
503 if (i_0 == i_neg[0]) // i_0 is either i_pos[0] or i_neg[0]
504 {
505 vol_minus = cut_vol; vol_plus = vol - cut_vol;
506 }
507 else
508 {
509 vol_plus = cut_vol; vol_minus = vol - cut_vol;
510 }
511
512 return 0;
513 }
514
515// if two corners at every side: two prisms
516 // We make the triangle containing i_neg[0] to be the botton.
517 // To this end, we order i_pos[0] and i_pos[1] in such a way that
518 // the new prism is properly oriented.
519 int side_idx = tet_rules::FACE_FROM_VRTS [i_neg[0]] [i_pos[0]] [i_pos[1]];
520 const int * side_co = tet_rules::FACE_VRT_INDS [side_idx];
521 int k;
522 for (k = 0; k < 3; k++)
523 if (side_co [k] == i_neg[0]) break;
524 UG_ASSERT (k < 3, "LSElementSize<ReferenceTetrahedron, WDim>::compute: internal error.");
525 i_pos[0] = side_co [(k + 1) % 3];
526 i_pos[1] = side_co [(k + 2) % 3];
527
528 // Now compute the coordinates of the corners of the prism
529 MathVector<dim> neg_prism [6];
530 for (int k = 0; k < 2; k++)
531 {
532 int i_0 = i_neg [k];
533 neg_prism [3 * k] = corner [i_0];
534 for (int l = 0; l < 2; l++)
535 {
536 int i = i_pos [l];
537 number t = lsf[i] / (lsf[i] - lsf[i_0]);
538 VecScaleAdd (neg_prism [3 * k + l + 1], t, corner[i_0], 1 - t, corner[i]);
539 }
540 }
541 vol_minus = ElementSize<ReferencePrism, dim> (neg_prism);
542 vol_plus = vol - vol_minus;
543 return 0;
544}
545
549template <int WDim>
551(
552 const MathVector<WDim> * corner,
553 const number * lsf,
554 number & vol_plus,
555 number & vol_minus
556)
557{
558 number vol = ElementSize<ref_element_type, dim> (corner);
559
560// look for 'positive' and 'negative' corners
561 int i_pos[3], i_neg[3];
562 i_pos[0] = -1; i_pos[1] = -1; i_pos[2] = -1;
563 i_neg[0] = -1; i_neg[1] = -1; i_neg[2] = -1;
564 size_t num_neg = 0;
565 for (int i = 0; i < 6; i++)
566 if (lsf[i] < 0) // note that we consider 0 as a positive value! This is used below!
567 {
568 if (i_neg[0] < 0) i_neg[0] = i;
569 else if (i_neg[1] < 0) i_neg[1] = i;
570 else i_neg[2] = i;
571 num_neg++;
572 }
573 else
574 {
575 if (i_pos[0] < 0) i_pos[0] = i;
576 else if (i_pos[1] < 0) i_pos[1] = i;
577 else i_pos[2] = i;
578 }
579 /*
580 * Note that i_neg[] and i_pos[] are now ordered in ascending order.
581 */
582
583// check if all are positive or all are negative
584 if (num_neg == 0)
585 {
586 vol_plus = vol; vol_minus = 0;
587 return 1;
588 }
589 if (num_neg == 6)
590 {
591 vol_plus = 0; vol_minus = vol;
592 return -1;
593 }
594
595// if only one corner is cut out, i.e. a tetrahedron is cut out
596 if (num_neg == 1 || num_neg == 5)
597 {
598 int i_0 = (num_neg == 1)? i_neg[0] : i_pos[0];
599 int shift = (i_0 < 3)? 0 : 3;
600 MathVector<dim> cut_tet [4];
601 for (int k = 0; k < 3; k++) // loop the corners of the base where i_0 lies
602 {
603 int i = k + shift;
604 if (i == i_0)
605 cut_tet [k] = corner [i];
606 else
607 {
608 number t = lsf[i] / (lsf[i] - lsf[i_0]);
609 VecScaleAdd (cut_tet [k], t, corner[i_0], 1 - t, corner[i]);
610 }
611 }
612 // For the base of the tetrahedron, we used the same orientation
613 // as for the base of the prism. This is OK if that was the bottom
614 // base of the prism. For the top base, we should invert the orientation:
615 if (shift != 0)
616 {
617 cut_tet[3] = cut_tet[2]; // cut_tet[3] is here a temporary variable
618 cut_tet[2] = cut_tet[1];
619 cut_tet[1] = cut_tet[3];
620 }
621 int i_1 = (i_0 + 3) % 6; // connected corner of the opposite base
622 number t_1 = lsf[i_1] / (lsf[i_1] - lsf[i_0]);
623 VecScaleAdd (cut_tet [3], t_1, corner[i_0], 1 - t_1, corner[i_1]);
624 number cut_vol = ElementSize<ReferenceTetrahedron, dim> (cut_tet);
625 if (i_0 == i_neg[0]) // i_0 is either i_pos[0] or i_neg[0]
626 {
627 vol_minus = cut_vol; vol_plus = vol - cut_vol;
628 }
629 else
630 {
631 vol_plus = cut_vol; vol_minus = vol - cut_vol;
632 }
633
634 return 0;
635 }
636
637// if two corners at every side: 2 tetrahedra or a prism cut out
638 if (num_neg == 2 || num_neg == 4)
639 {
640 int i_0, i_1;
641 if (num_neg == 2)
642 {
643 i_0 = i_neg[0]; i_1 = i_neg[1];
644 }
645 else
646 {
647 i_0 = i_pos[0]; i_1 = i_pos[1];
648 }
649 /* Here, i_0 < i_1 (s. the remark above). */
650
651 // Case 1: 2 corners of one base are cut out; this means, a prism is cut out
652 if (i_1 < 3 || i_0 >= 3)
653 {
654 int shift = (i_0 < 3)? 0 : 3;
655 int i_2 = -1; // the 3rd corner of the base
656 for (int k = 0; k < 3; k++)
657 {
658 i_2 = k + shift;
659 if (i_2 != i_0 && i_2 != i_1) break;
660 }
661 int i_0a = (i_0 + 3) % 6; // corner connected to i_0 on the opposite base
662 int i_1a = (i_1 + 3) % 6; // corner connected to i_1 on the opposite base
663
664 MathVector<dim> cut_prism [6];
665 number t;
666
667 // Remark: We construct the prism in such a way that the 0th
668 // side (with corners 0, 1, 4, 3) is planar (to be consistent
669 // with the computation of the volume in geometry_util.h).
670 // This can be achieved by taking this side from the triangular
671 // base of the original prism.
672 // Note however that we should provide the correct orientation
673 // of the prism. Thus we should provide (i_0 + 1) % 3 == i_1
674 // if the bottom base of the original prism is cut, and
675 // i_0a == (i_1a + 1) % 3 for the top base. To this end, we swap
676 // i_0 with i_1 (and i_0a with i_1a respectively) if necessary.
677 if ((i_1 < 3 && (i_0 + 1) % 3 != i_1) || (i_0 >= 3 && i_0a != (i_1a + 1) % 3))
678 {
679 int i;
680 i = i_0; i_0 = i_1; i_1 = i;
681 i = i_0a; i_0a = i_1a; i_1a = i;
682 }
683
684 cut_prism [0] = corner[i_0];
685 t = lsf[i_2] / (lsf[i_2] - lsf[i_0]);
686 VecScaleAdd (cut_prism [1], t, corner[i_0], 1 - t, corner[i_2]);
687 t = lsf[i_0a] / (lsf[i_0a] - lsf[i_0]);
688 VecScaleAdd (cut_prism [2], t, corner[i_0], 1 - t, corner[i_0a]);
689
690 cut_prism [3] = corner[i_1];
691 t = lsf[i_2] / (lsf[i_2] - lsf[i_1]);
692 VecScaleAdd (cut_prism [4], t, corner[i_1], 1 - t, corner[i_2]);
693 t = lsf[i_1a] / (lsf[i_1a] - lsf[i_1]);
694 VecScaleAdd (cut_prism [5], t, corner[i_1], 1 - t, corner[i_1a]);
695
696 number cut_vol = ElementSize<ReferencePrism, dim> (cut_prism);
697 if (num_neg == 2)
698 {
699 vol_minus = cut_vol;
700 vol_plus = vol - cut_vol;
701 }
702 else
703 {
704 vol_plus = cut_vol;
705 vol_minus = vol - cut_vol;
706 }
707
708 return 0;
709 }
710
711 // Case 2: one corner of each base are cut out, and they are connected; a prism is cut out
712 if (i_1 - i_0 == 3)
713 {
714 // We construct a new (cut out) prism and try to keep the 0th
715 // side as planar as possible: see the previous remark. For this,
716 // we take a part of a side of the original prism as a side of
717 // the new one.
718 MathVector<dim> cut_prism [6];
719 cut_prism [0] = corner [i_0];
720 cut_prism [3] = corner [i_1];
721 {
722 int i = (i_0 + 1) % 3; int j = i + 3;
723 number t;
724 t = lsf[i] / (lsf[i] - lsf[i_0]);
725 VecScaleAdd (cut_prism [1], t, corner[i_0], 1 - t, corner[i]);
726 t = lsf[j] / (lsf[j] - lsf[i_1]);
727 VecScaleAdd (cut_prism [4], t, corner[i_1], 1 - t, corner[j]);
728 }
729 {
730 int i = (i_0 + 2) % 3; int j = i + 3;
731 number t;
732 t = lsf[i] / (lsf[i] - lsf[i_0]);
733 VecScaleAdd (cut_prism [2], t, corner[i_0], 1 - t, corner[i]);
734 t = lsf[j] / (lsf[j] - lsf[i_1]);
735 VecScaleAdd (cut_prism [5], t, corner[i_1], 1 - t, corner[j]);
736 }
737 number cut_vol = ElementSize<ReferencePrism, dim> (cut_prism);
738 if (num_neg == 2)
739 {
740 vol_minus = cut_vol;
741 vol_plus = vol - cut_vol;
742 }
743 else
744 {
745 vol_plus = cut_vol;
746 vol_minus = vol - cut_vol;
747 }
748
749 return 0;
750 }
751
752 // Case 3: The corners belong to different bases but are not connected.
753 // We consider two separated tetrahedra. They do not hinder each other.
754 // We call the function recursively.
755 number tmp_lsf [6], tmp_vol;
756 memcpy (tmp_lsf, lsf, 6 * sizeof (number));
757 if (num_neg == 2)
758 {
759 // 2 negative corners
760 number neg_vol;
761
762 tmp_lsf [i_neg[0]] = 1; // correct the first negative corner
763 LSElementSize<ReferencePrism, dim>::compute (corner, tmp_lsf, tmp_vol, neg_vol);
764 vol_minus = neg_vol;
765
766 tmp_lsf [i_neg[0]] = lsf [i_neg[0]];
767 tmp_lsf [i_neg[1]] = 1; // correct the second negative corner
768 LSElementSize<ReferencePrism, dim>::compute (corner, tmp_lsf, tmp_vol, neg_vol);
769 vol_minus += neg_vol;
770
771 vol_plus = vol - vol_minus;
772 return 0;
773 }
774 if (num_neg == 4)
775 {
776 // 2 positive corners
777 number pos_vol;
778
779 tmp_lsf [i_pos[0]] = -1; // correct the first positive corner
780 LSElementSize<ReferencePrism, dim>::compute (corner, tmp_lsf, pos_vol, tmp_vol);
781 vol_plus = pos_vol;
782
783 tmp_lsf [i_pos[0]] = lsf [i_pos[0]];
784 tmp_lsf [i_pos[1]] = -1; // correct the second positive corner
785 LSElementSize<ReferencePrism, dim>::compute (corner, tmp_lsf, pos_vol, tmp_vol);
786 vol_plus += pos_vol;
787
788 vol_minus = vol - vol_plus;
789 return 0;
790 }
791 }
792
793// if three corners at every side: two prisms or "a very complicated case"
794 if ((i_neg[0] == 0 && i_neg[2] == 2) || (i_neg[0] == 3 && i_neg[2] == 5))
795 {
796 // Case 1: 2 prisms: every base has its own sign
797 number cut_vol;
798 MathVector<dim> cut_prism [6];
799 for (int i = 0; i < 3; i++) cut_prism [i] = corner [i];
800 for (int i = 0; i < 3; i++)
801 {
802 int j = i + 3;
803 number t = lsf[j] / (lsf[j] - lsf[i]);
804 VecScaleAdd (cut_prism [j], t, corner [i], 1 - t, corner [j]);
805 }
806 cut_vol = ElementSize<ReferencePrism, dim> (cut_prism);
807
808 if (i_neg[0] == 0)
809 {
810 vol_minus = cut_vol;
811 vol_plus = vol - cut_vol;
812 }
813 else
814 {
815 vol_plus = cut_vol;
816 vol_minus = vol - cut_vol;
817 }
818
819 return 0;
820 }
821
822 // Case 2: The "very complicated case": Two corners of one base and one
823 // of the other one are cut.
824 // Only one of the three sides connecting the bases is shared by
825 // a negative and a positive corner. Denote this side by [A, B], and its
826 // point, where the LSF is 0, by S. (Without loss of generality, we
827 // assume that LSF[A] < 0.) We divide the whole prism into two parts:
828 // a smaller prism and a tetrahedron. The smaller prism is obtained from
829 // the original one by shifting the corner A into S. The tetrahedron is
830 // the difference of these prisms. After that, we call the function
831 // recursively to compute the volumes for the smaller prism. It has
832 // now one negative corner less than the original one (becase 0 is
833 // considered as a positive number here), so that this case is implemented
834 // above.
835 MathVector<dim> part_prism [6];
836 number part_lsf [6];
837 int base_i = -1;
838
839 for (int i = 0; i < 3; i++)
840 {
841 int j = i + 3;
842 part_prism [i] = corner [i]; part_lsf [i] = lsf [i];
843 part_prism [j] = corner [j]; part_lsf [j] = lsf [j];
844 if ((lsf[i] >= 0 && lsf[j] < 0)
845 || (lsf[i] < 0 && lsf[j] >= 0)) // note: 0 is considered as a positive value
846 {
847 base_i = (lsf[i] < 0)? i : j; // the corner to shift
848 part_lsf[base_i] = 0; // we make it to be a positive corner!
849 number t = lsf[j] / (lsf[j] - lsf[i]);
850 VecScaleAdd (part_prism [base_i], t, corner [i], 1 - t, corner [j]);
851 }
852 }
853 UG_ASSERT (base_i >= 0, "LSElementSize<ReferencePrism, dim>::compute: internal error");
854 number part_prism_vol_plus, part_prism_vol_minus;
856 part_prism_vol_plus, part_prism_vol_minus);
857
858 MathVector<dim> part_tet [4];
859 int shift = (base_i < 3)? 0 : 3;
860 for (int k = 0; k < 3; k++)
861 {
862 part_tet [k] = corner [k + shift];
863 part_lsf [k] = lsf [k + shift];
864 }
865 // As before, we must provide the correct orientation of the tetrahedron.
866 // To this end, we change the current orientation, if base_i is on the
867 // top base of the prism. (Cf. the case of one cut corner.)
868 if (shift != 0)
869 {
870 part_tet[3] = part_tet[2]; part_lsf[3] = part_lsf[2];
871 part_tet[2] = part_tet[1]; part_lsf[2] = part_lsf[1];
872 part_tet[1] = part_tet[3]; part_lsf[1] = part_lsf[3];
873 }
874 part_tet [3] = part_prism [base_i];
875 part_lsf [3] = 0;
876 number part_tet_vol_plus, part_tet_vol_minus;
878 part_tet_vol_plus, part_tet_vol_minus);
879
880 vol_plus = part_prism_vol_plus + part_tet_vol_plus;
881 vol_minus = part_prism_vol_minus + part_tet_vol_minus;
882
883 return 0;
884}
885
886} // end namespace LevelSet
887} // end namespace ug
888
889/* End of File */
size_t allreduce(const size_t &t, pcl::ReduceOperation op) const
static int compute(const MathVector< WDim > *corner, const number *lsf, number &vol_plus, number &vol_minus)
computation of the volumes
Definition ls_volume.h:260
void on_subsets(const char *ss_names)
sets the subsets to restrict the computation on
Definition ls_volume_impl.h:53
void allreduce_volumes()
Definition ls_volume_impl.h:277
void compute()
computes the volumes
Definition ls_volume_impl.h:65
void print_details() const
prints the details
Definition ls_volume_impl.h:319
void add_volumes_of_all()
adds contributions of all elements of a given type
Definition ls_volume_impl.h:114
domain_type::position_accessor_type position_accessor_type
type of the position accessor
Definition ls_volume.h:72
TGridFunc grid_func_type
grid function type
Definition ls_volume.h:63
void volume_in_subsets(const char *ss_names, number &vol_plus, number &vol_minus) const
extracts the volumes enclosed in given subsets
Definition ls_volume_impl.h:297
void add(const char *name)
size_t size() const
#define PCL_RO_SUM
vector< string > TokenizeString(const char *str, const char delimiter=',')
#define UG_ASSERT(expr, msg)
#define UG_THROW(msg)
#define UG_LOG(msg)
double number
const int FACE_VRT_INDS[][4]
const int FACE_FROM_VRTS[4][4][4]
const number & DoFRef(const TMatrix &mat, const DoFIndex &iInd, const DoFIndex &jInd)
void VecScaleAdd(double &dest, double alpha1, const double &v1, double alpha2, const double &v2)
helper class for the computation of the volumes
Definition ls_volume.h:168
helper class for the computation of the weighted volumes
Definition ls_volume.h:195