Plugins
Loading...
Searching...
No Matches
hrfblsm_discr_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
33/*
34 * High-resolution flux-based level set method: Implementation
35 */
36
37// ug4 headers
42#ifdef UG_PARALLEL
44#endif
45
46namespace ug{
47namespace LevelSet{
48
49// Define for the classic ghost fluid method
50#define LS_CLASSIC_GHOST_FLUID
51
58template<typename TGridFunction>
60(
61 size_t noc,
62 number lsf []
63)
64{
65 int pos = 0, neg = 0;
66 for (size_t co = 0; co < noc; co++)
67 {
68 if (lsf [co] >= - lsf_threshold () && lsf [co] <= lsf_threshold ())
69 return 0; // we consider such elements as intersected; this is important for computation of the gradients
70 if (lsf [co] < 0) neg = 1;
71 else pos = 1;
72 }
73 return pos - neg;
74}
75
79template<typename TGridFunction>
81(
83 ABool& aCoIE,
84 t_aaCoIE& aaCoIE
85)
86{
87// set the default value (false everywhere)
88 SetAttachmentValues (aaCoIE, grid.vertices_begin (), grid.vertices_end (), false);
89
90// if no LSF then nothing to do
91 if (! m_spLSF.valid ()) return;
92
93 LocalIndices locInd;
94 LocalVector locLSF;
95
96// loop the vertices
97 ElemIterator iterEnd = m_spLSF->template end<ElemType> ();
98 for (ElemIterator iter = m_spLSF->template begin<ElemType> (); iter != iterEnd; ++iter)
99 {
100 // local values of the LSF
101 number lsf [maxNumCo];
102 ElemType* elem = *iter;
103 size_t noc = elem->num_vertices ();
104 m_spLSF->indices (elem, locInd);
105 locLSF.resize (locInd);
106 GetLocalVector (locLSF, *m_spLSF);
107 for (size_t i = 0; i < noc; i++)
108 lsf[i] = locLSF (0, i);
109 // check the sign of the lsf
110 if (lsf_sign (noc, lsf) == 0)
111 for (size_t i = 0; i < elem->num_vertices (); i++)
112 aaCoIE[elem->vertex (i)] = true;
113 }
114
115# ifdef UG_PARALLEL
116 AttachmentAllReduce<Vertex> (grid, aCoIE, PCL_RO_LOR);
117# endif
118}
119
123template<typename TGridFunction>
125(
126 const CplUserData<number,dim> * if_val_data,
127 int si,
128 DimFV1Geometry<dim> & geo,
129 number sol [],
130 number lsf [],
131 size_t base,
132 number ext []
133)
134{
135 const MathVector<dim>* co_coord = geo.corners ();
136
137 for (size_t co = 0; co < geo.num_scv (); co++)
138 if (lsf [co] * lsf [base] > 0)
139 ext[co] = sol[co]; /* take the original value */
140 else /* extrapolate */
141 {
142 number interface_val;
143 if (if_val_data == NULL)
144 interface_val = 0;
145 else
146 {
147 const MathVector<dim>* co_local = geo.scv_local_ips ();
148 MathVector<dim> if_pnt_coord, if_pnt_local;
149 number s = lsf[co] / (lsf[co] - lsf[base]);
150 VecScaleAdd (if_pnt_coord, s, co_coord[base], 1 - s, co_coord[co]);
151 VecScaleAdd (if_pnt_local, s, co_local[base], 1 - s, co_local[co]);
152 (* if_val_data) (&interface_val, &if_pnt_coord, m_time, si,
153 geo.elem (), co_coord, &if_pnt_local, 1, NULL);
154 }
155
156 number t = lsf[co] / lsf[base];
157 ext[co] = sol[base] * t + interface_val * (1 - t);
158 }
159}
160
164template<typename TGridFunction>
166(
167 bool redOrder,
168 const MathVector<dim>& ip,
169// Data at the upwind corner
170 const MathVector<dim>& x_up,
171 number u_up,
172 const MathVector<dim>& grad_up,
173 const MathVector<dim>& vel_up,
174// Data at the downwind corner
175 const MathVector<dim>& x_down,
176 number u_down,
177 const MathVector<dim>& grad_down,
178 const MathVector<dim>& vel_down,
179// Computed update
180 number& corr_up,
181 number& corr_down,
182 number& src_up,
183 number& src_down
184)
185{
186 if (! m_firstOrder) // the High-Resolution Flux-Based Level-Set method
187 {
188 // due to the convection:
189 // conv_corr = u_{ip}^{n+0.5}, where u_{ip}^{n+0.5} is interpolated along the characteristic
190 MathVector<dim> distVec;
191 VecSubtract (distVec, ip, x_up);
192 corr_up = u_up - 0.5 * m_dt * (grad_up * vel_up);
193 if (! redOrder)
194 corr_up += grad_up * distVec;
195 corr_down = corr_up;
196
197 // due to the divergence:
198 if (! m_divFree)
199 {
200 // div_corr_up = u_{co_up}^{n+0.5}, where u_{co_up}^{n+0.5} is interpolated along the characteristic
201 corr_up -= u_up - 0.5 * m_dt * (grad_up * vel_up);
202
203 // div_corr_down = u_{co_down}^{n+0.5}, where u_{co_up}^{n+0.5} is interpolated along the characteristic
204 corr_down -= u_down - 0.5 * m_dt * (grad_down * vel_down);
205 }
206 }
207 else // the classic (first-order) upwind method
208 {
209 // due to the convection
210 corr_down = corr_up = u_up;
211
212 // due to the divergence
213 if (! m_divFree)
214 {
215 corr_up -= u_up;
216 corr_down -= u_down;
217 }
218 }
219
220 if (! m_antiderivSrc) // the usual discretization
221 src_up = src_down = 0; // we do not assemble the source factors here
222 else
223 { // approximate the mesh size
224 MathVector<dim> hVec;
225 VecSubtract (hVec, x_down, x_up);
226 src_up = 0;
227 src_down = vel_down * hVec;
228 }
229}
230
234template<typename TGridFunction>
236(
237 bool redOrder,
238 const MathVector<dim>& bip,
239// Data at the upwind corner
240 const MathVector<dim>& x,
241 number u,
242 const MathVector<dim>& grad,
243 const MathVector<dim>& vel,
244// Computed update
245 number& corr
246)
247{
248 if (! m_firstOrder) // the High-Resolution Flux-Based Level-Set method
249 {
250 // due to the convection:
251 // conv_corr = u_{bip}^{n+0.5}, where u_{bip}^{n+0.5} is interpolated along the characteristic
252 MathVector<dim> distVec;
253 VecSubtract (distVec, bip, x);
254 corr = u - 0.5 * m_dt * (grad * vel);
255 if (! redOrder)
256 corr += grad * distVec;
257
258 // due to the divergence
259 if (! m_divFree)
260 // div_corr = u_{co}^{n+0.5}, where u_{co}^{n+0.5} is interpolated along the characteristic
261 corr -= u - 0.5 * m_dt * (grad * vel);
262 }
263 else // the classic (first-order) upwind method
264 {
265 // due to the convection
266 corr = u;
267
268 // due to the divergence
269 if (! m_divFree)
270 corr -= u;
271 }
272}
273
278template<typename TGridFunction>
280(
281 ElemType* elem,
282 MathVector<dim> co_coord[],
284 LocalVector& u,
285 MathVector<dim> grad[],
286 MathVector<dim> co_vel[],
287 int lsf_sign
288)
289{
290 size_t noc = geo.num_scv ();
291
292 const int si = 0; //TODO this should be corrected
293
294// Compute the corner velocity
295 if (lsf_sign == 0 && m_imVelocity.valid ()) // we consider an arbitrary vel. field only if there is no LSF
296 {
297 (*m_imVelocity) (co_vel, geo.scv_global_ips (), m_time, si,
298 elem, co_coord, geo.scv_local_ips (), noc, &u);
299 if (m_gamma != 1)
300 for (size_t i = 0; i < noc; i++)
301 co_vel[i] *= m_gamma;
302 }
303 else if (lsf_sign == 0 && m_imNormalVel.valid ()) // normal velocity (only if there is no LSF)
304 {
305 number normal_vel [maxNumCo];
306
307 (*m_imNormalVel) (normal_vel, geo.scv_global_ips (), m_time, si,
308 elem, co_coord, geo.scv_local_ips (), noc, &u);
309
310 for (size_t i = 0; i < noc; i++)
311 {
312 number vnorm = VecLength (grad[i]);
313 if (vnorm > 1e-15) //TODO: Eliminate the explicit constant
314 {
315 if (lsf_sign < 0)
316 vnorm = - vnorm;
317 VecScale (co_vel[i], grad[i], m_gamma * normal_vel[i] / vnorm);
318 }
319 else
320 co_vel[i] = 0;
321 }
322 }
323 else if (m_delta != 0) // constantly scaled normalized gradient as the velocity
324 for (size_t i = 0; i < noc; i++)
325 {
326 number vnorm = VecLength (grad[i]);
327 if (vnorm > 1e-15) //TODO: Eliminate the explicit constant
328 {
329 if (lsf_sign < 0)
330 vnorm = - vnorm;
331 VecScale (co_vel[i], grad[i], m_delta / vnorm);
332 }
333 else
334 co_vel[i] = 0;
335 }
336 else
337 for (size_t i = 0; i < noc; i++) co_vel[i] = 0;
338}
339
346template<typename TGridFunction>
348(
349 ElemType* elem,
351 domain_type& domain,
352 LocalVector& uOld,
353 t_aaGrad& aaGradient,
354 t_aaGrad& aaVelGrad,
355 t_aaVol& aaVolume,
356 int sign,
357 t_aaUpd& aaUpdate,
358 t_aaUpd* aaSrc
359)
360{
361// get position accessor
362 const position_accessor_type& aaPos = domain.position_accessor ();
363
364// get vertices and extract corner coordinates
365 MathVector<dim> coCoord[maxNumCo];
366 Vertex* vVrt[maxNumCo];
367 for (size_t i = 0; i < elem->num_vertices (); ++i)
368 {
369 vVrt[i] = elem->vertex (i);
370 coCoord[i] = aaPos[vVrt[i]];
371 }
372
373// update fv geometry
374 geo.update (elem, coCoord, domain.subset_handler().get ());
375 size_t noc = geo.num_scv ();
376
377// fill node values and gradients
378 number uValue[maxNumCo];
379 MathVector<dim> grad[maxNumCo];
380 MathVector<dim> vel_grad[maxNumCo];
381 for (size_t i=0; i < noc; i++)
382 {
383 uValue[i] = uOld (0, i);
384 grad[i] = aaGradient[vVrt[i]];
385 vel_grad[i] = aaVelGrad[vVrt[i]];
386 }
387
388// get corner velocity and source
389 MathVector<dim> coVelocity[maxNumCo];
390 get_nodal_vel (elem, coCoord, geo, uOld, vel_grad, coVelocity, sign);
391
392// outflow boundary
393 bool outBndCo[maxNumCo];
394 for (size_t i = 0; i < noc; i++) outBndCo[i] = false;
395 for (size_t k = 0; k < m_neumann_sg.size (); k++)
396 {
397 int si = m_neumann_sg [k];
398 for (size_t i = 0; i < geo.num_bf (si); i++)
399 {
400 // get current BF
401 const typename DimFV1Geometry<dim>::BF& bf = geo.bf (si, i);
402 const size_t nodeID = bf.node_id ();
403
404 // mark the corner
405 outBndCo[nodeID] = true;
406
407 // compute values at the bip
408 MathVector<dim> bipVelocity;
409 bipVelocity = 0;
410 for (size_t co = 0; co < noc; co++)
411 VecScaleAppend (bipVelocity, bf.shape (co), coVelocity[co]);
412 number bipNormalVel = bipVelocity * bf.normal ();
413
414 // assemble the fluxes
415 number corr;
416 bnd_sol_update (true, bf.global_ip (), coCoord[nodeID], uValue[nodeID],
417 grad[nodeID], coVelocity[nodeID], corr);
418 aaUpdate[ vVrt[nodeID] ] -= bipNormalVel * corr / aaVolume[ vVrt[nodeID] ];
419
420 // the local Courant-number
421 if (m_spCourant.valid ())
422 {
423 number localCFL = m_dt * bipNormalVel / aaVolume[ vVrt[nodeID] ];
424 const LocalIndices& ind = uOld.get_indices ();
425 const size_t index = ind.index (0, nodeID), comp = ind.comp (0, nodeID);
426 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
427 if (m_divFree)
428 { // we consider the outflow faces
429 if (bipNormalVel > 0)
430 CFL_entry += localCFL;
431 }
432 else
433 { // actually, CFL should NOT be regarded here...
434 CFL_entry += std::fabs (localCFL);
435 }
436 }
437 }
438 }
439
440// fluxes through the inner scvfaces
441 for (size_t ip = 0; ip < geo.num_scvf (); ++ip)
442 {
443 // get current SCVF
444 const typename DimFV1Geometry<dim>::SCVF& scvf = geo.scvf (ip);
445 size_t from = scvf.from ();
446 size_t to = scvf.to ();
447 const MathVector<dim>& ipCoord = scvf.global_ip ();
448
449 // compute the ip velocity from the corner velocity by the linear interpolation
450 MathVector<dim> ipVelocity;
451 ipVelocity = 0;
452 for (size_t co = 0; co < noc; co++)
453 VecScaleAppend (ipVelocity, scvf.shape (co), coVelocity[co]);
454
455 // normal ip-velocity
456 number ipNormalVel = ipVelocity * scvf.normal ();
457
458 // upwinding
459 size_t up_co, down_co;
460 if (ipNormalVel > 0)
461 {
462 up_co = from; down_co = to;
463 }
464 else
465 {
466 up_co = to; down_co = from; ipNormalVel = - ipNormalVel;
467 }
468
469 // assemble the fluxes
470 number corr_up, corr_down;
471 number src_up, src_down;
472 sol_update (outBndCo[up_co], // reduce the order at the outflow boundary
473 ipCoord, coCoord[up_co], uValue[up_co], grad[up_co], coVelocity[up_co],
474 coCoord[down_co], uValue[down_co], grad[down_co], coVelocity[down_co],
475 corr_up, corr_down, src_up, src_down);
476
477 aaUpdate[ vVrt[up_co] ] -= ipNormalVel * corr_up / aaVolume[ vVrt[up_co] ];
478 aaUpdate[ vVrt[down_co] ] += ipNormalVel * corr_down / aaVolume[ vVrt[down_co] ];
479
480 if (aaSrc != NULL)
481 {
482 (*aaSrc)[ vVrt[up_co] ] -= ipNormalVel * src_up / aaVolume[ vVrt[up_co] ];
483 (*aaSrc)[ vVrt[down_co] ] += ipNormalVel * src_down / aaVolume[ vVrt[down_co] ];
484 }
485
486 // the local Courant-number
487 if (m_spCourant.valid ())
488 {
489 const LocalIndices& ind = uOld.get_indices ();
490 size_t index, comp;
491
492 if (m_divFree)
493 { // consider the outflow faces:
494 number localCFL = m_dt * ipNormalVel / aaVolume[ vVrt[up_co] ];
495 index = ind.index (0, up_co); comp = ind.comp (0, up_co);
496 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
497 CFL_entry += localCFL;
498 }
499 else
500 { // consider inflow faces
501 number localCFL = m_dt * ipNormalVel / aaVolume[ vVrt[down_co] ];
502 index = ind.index (0, down_co); comp = ind.comp (0, down_co);
503 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
504 CFL_entry += localCFL;
505 }
506 }
507 }
508}
509
513template<typename TGridFunction>
515(
517 const typename DimFV1Geometry<dim>::SCVF& scvf,
518 number u[],
519 MathVector<dim> grad[],
520 number lsf[],
521//---- Data computed for the from-corner
522 MathVector<dim>& from_co_vel,
523 number& from_flux,
524//---- Data computed for the to-corner
525 MathVector<dim>& to_co_vel,
526 number& to_flux
527)
528{
529 number ext_u [maxNumCo];
530 MathVector<dim> grad_ip;
531 number norm, delta;
532 size_t co, noc = geo.num_scv ();
533
534// From-corner
535 co = scvf.from ();
536 delta = (lsf[co] >= 0)? 1 : -1;
537 extrapolate_by_lsf (NULL, 0, geo, u, lsf, co, ext_u);
538 grad_ip = 0.0;
539 for (size_t sh = 0; sh < noc; sh++)
540 VecScaleAppend (grad_ip, ext_u[sh], scvf.global_grad (sh));
541 norm = VecLength (grad_ip);
542 if (norm > 1e-15) //TODO: Eliminate the explicit constant
543 from_flux = delta * (grad_ip * scvf.normal ()) / norm;
544 else
545 from_flux = 0;
546 norm = VecLength (grad[co]);
547 if (norm > 1e-15) //TODO: Eliminate the explicit constant
548 VecScale (from_co_vel, grad[co], delta / norm);
549 else
550 from_co_vel = 0;
551
552// To-corner
553 co = scvf.to ();
554 delta = (lsf[co] >= 0)? 1 : -1;
555 extrapolate_by_lsf (NULL, 0, geo, u, lsf, co, ext_u);
556 grad_ip = 0.0;
557 for (size_t sh = 0; sh < noc; sh++)
558 VecScaleAppend (grad_ip, ext_u[sh], scvf.global_grad (sh));
559 norm = VecLength (grad_ip);
560 if (norm > 1e-15) //TODO: Eliminate the explicit constant
561 to_flux = delta * (grad_ip * scvf.normal ()) / norm;
562 else
563 to_flux = 0;
564 norm = VecLength (grad[co]);
565 if (norm > 1e-15) //TODO: Eliminate the explicit constant
566 VecScale (to_co_vel, grad[co], delta / norm);
567 else
568 to_co_vel = 0;
569}
570
574template<typename TGridFunction>
576(
578 const typename DimFV1Geometry<dim>::BF& bf,
579 number u[],
580 MathVector<dim> grad[],
581 number lsf[],
582 MathVector<dim>& co_vel,
583 number& flux
584)
585{
586 number ext_u [maxNumCo];
587 MathVector<dim> grad_ip;
588 number norm, delta;
589 size_t co, noc = geo.num_scv ();
590
591 co = bf.node_id ();
592 delta = (lsf[co] >= 0)? 1 : -1;
593 extrapolate_by_lsf (NULL, 0, geo, u, lsf, co, ext_u);
594 grad_ip = 0.0;
595 for (size_t sh = 0; sh < noc; sh++)
596 VecScaleAppend (grad_ip, ext_u[sh], bf.global_grad (sh));
597 norm = VecLength (grad_ip);
598 if (norm > 1e-15) //TODO: Eliminate the explicit constant
599 flux = delta * (grad_ip * bf.normal ()) / norm;
600 else
601 flux = 0;
602 norm = VecLength (grad[co]);
603 if (norm > 1e-15) //TODO: Eliminate the explicit constant
604 VecScale (co_vel, grad[co], delta / norm);
605 else
606 co_vel = 0;
607}
608
617template<typename TGridFunction>
619(
620 ElemType* elem,
622 domain_type& domain,
623 LocalVector& uOld,
624 LocalVector& locLSF,
625 LocalVector& locVelPot,
626 t_aaGrad& aaGradient,
627 t_aaGrad& aaVelGrad,
628 t_aaVol& aaVolume,
629 t_aaUpd& aaUpdate,
630 t_aaUpd* aaSrc,
631 CplUserData<number,dim> * if_val_data,
632 int si
633)
634{
635// get position accessor
636 const position_accessor_type& aaPos = domain.position_accessor ();
637
638// get the LSF and compute its sign
639 number lsf[maxNumCo];
640 GetLocalVector (locLSF, *m_spLSF);
641 for (size_t i = 0; i < elem->num_vertices (); i++)
642 lsf[i] = locLSF (0, i);
643 int sign = lsf_sign (elem->num_vertices (), lsf);
644 if (sign != 0)
645 return sign;
646
647// get vertices and extract corner coordinates
648 MathVector<dim> coCoord[maxNumCo];
649 Vertex* vVrt[maxNumCo];
650 for (size_t i = 0; i < elem->num_vertices (); i++)
651 {
652 vVrt[i] = elem->vertex (i);
653 coCoord[i] = aaPos[vVrt[i]];
654 }
655
656// update fv geometry
657 geo.update (elem, coCoord, domain.subset_handler().get ());
658 size_t noc = geo.num_scv ();
659
660// fill nodal values and gradients
661 number uValue[maxNumCo];
662 number vel_pot[maxNumCo];
663 MathVector<dim> grad[maxNumCo];
664 MathVector<dim> vel_grad[maxNumCo];
665 GetLocalVector (locVelPot, *m_spVelPot);
666 for (size_t i = 0; i < noc; i++)
667 {
668 uValue[i] = uOld (0, i);
669 vel_pot[i] = locVelPot (0, i);
670 grad[i] = aaGradient[vVrt[i]];
671 vel_grad[i] = aaVelGrad[vVrt[i]];
672 }
673
674// outflow boundary
675 for (size_t k = 0; k < m_neumann_sg.size (); k++)
676 {
677 int si = m_neumann_sg [k];
678 for(size_t i = 0; i < geo.num_bf (si); i++)
679 {
680 // get the BF
681 const typename DimFV1Geometry<dim>::BF& bf = geo.bf (si, i);
682 const size_t nodeID = bf.node_id ();
683
684 // get the velocity
685 MathVector<dim> co_vel;
686 number flux;
687 get_bf_vel_on_if (geo, bf, vel_pot, vel_grad, lsf, co_vel, flux);
688
689 // assemble the fluxes
690 if (m_divFree) // otherwise we do not consider any flux for the first order approx.
691 aaUpdate[ vVrt[nodeID] ] -= flux * uValue[nodeID] / aaVolume[ vVrt[nodeID] ]; // first order approximation
692
693 // the local Courant-number
694 if (m_spCourant.valid ())
695 {
696 if (m_divFree) // otherwise there are no contribution
697 {
698 if (flux > 0) // we consider only outflow faces
699 {
700 number localCFL = m_dt * flux / aaVolume[ vVrt[nodeID] ];
701 const LocalIndices& ind = uOld.get_indices ();
702 const size_t index = ind.index (0, nodeID), comp = ind.comp (0, nodeID);
703 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
704 CFL_entry += localCFL;
705 }
706 }
707 }
708 }
709 }
710
711# ifndef LS_CLASSIC_GHOST_FLUID
712
713// fluxes through the inner scv faces
714 for (size_t ip = 0; ip < geo.num_scvf (); ip++)
715 {
716 number corr, src, t;
717
718 // get current SCVF
719 const typename DimFV1Geometry<dim>::SCVF& scvf = geo.scvf (ip);
720 const MathVector<dim>& ipCoord = scvf.global_ip ();
721 size_t from = scvf.from ();
722 size_t to = scvf.to ();
723
724 // compute the velocities
725 MathVector<dim> from_co_vel, to_co_vel;
726 number from_flux, to_flux;
727 get_scvf_vel_on_if (geo, scvf, vel_pot, vel_grad, lsf,
728 from_co_vel, from_flux, to_co_vel, to_flux);
729
730 // assemble the flux for the from-corner
731 sol_update (false, ipCoord, coCoord[from], uValue[from], grad[from], from_co_vel,
732 coCoord[to], uValue[to], grad[to], to_co_vel, corr, t, src, t);
733 aaUpdate[ vVrt[from] ] -= from_flux * corr / aaVolume[ vVrt[from] ];
734 if (aaSrc != NULL)
735 (*aaSrc) [ vVrt[from] ] -= from_flux * src / aaVolume[ vVrt[from] ];
736
737 // assemble the flux for the to-corner
738 sol_update (false, ipCoord, coCoord[to], uValue[to], grad[to], to_co_vel,
739 coCoord[from], uValue[from], grad[from], from_co_vel, corr, t, src, t);
740 aaUpdate[ vVrt[to] ] += to_flux * corr / aaVolume[ vVrt[to] ];
741 if (aaSrc != NULL)
742 (*aaSrc) [ vVrt[to] ] += to_flux * src / aaVolume[ vVrt[to] ];
743
744 // the local Courant-number
745 if (m_spCourant.valid ())
746 {
747 const LocalIndices& ind = uOld.get_indices ();
748 size_t index, comp;
749
750 if (m_divFree)
751 { // consider the outflow faces:
752 number localCFL = m_dt * std::abs (from_flux) / aaVolume[ vVrt[from] ];
753 index = ind.index (0, from); comp = ind.comp (0, from);
754 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
755 CFL_entry += localCFL;
756 }
757 else
758 { // consider inflow faces
759 number localCFL = m_dt * std::abs (to_flux) / aaVolume[ vVrt[to] ];
760 index = ind.index (0, to); comp = ind.comp (0, to);
761 number& CFL_entry_2 = BlockRef ((* m_spCourant) [index], comp);
762 CFL_entry += localCFL;
763 }
764 }
765 }
766
767# else // LS_CLASSIC_GHOST_FLUID
768
769// loop the base corner for the extrapolation
770 for (size_t base_co = 0; base_co < noc; base_co++)
771 {
772 // extrapolate the solution
773 number extValue [maxNumCo];
774 extrapolate_by_lsf (if_val_data, si, geo, uValue, lsf, base_co, extValue);
775
776 // fluxes through the inner scvfaces
777 for (size_t ip = 0; ip < geo.num_scvf (); ++ip)
778 {
779 // get current SCVF
780 const typename DimFV1Geometry<dim>::SCVF& scvf = geo.scvf (ip);
781 size_t from = scvf.from ();
782 size_t to = scvf.to ();
783 if (from != base_co && to != base_co)
784 continue; // not the current case
785
786 const MathVector<dim>& ipCoord = scvf.global_ip ();
787
788 // compute the velocities
789 MathVector<dim> from_co_vel, to_co_vel;
790 number from_ipNormalVel, to_ipNormalVel;
791 get_scvf_vel_on_if (geo, scvf, vel_pot, vel_grad, lsf,
792 from_co_vel, from_ipNormalVel, to_co_vel, to_ipNormalVel);
793
794 // normal ip-velocity (depending on the corner we assemble):
795 number ipNormalVel = (base_co == from)? from_ipNormalVel : to_ipNormalVel;
796
797 // upwinding
798 size_t up_co, down_co;
799 MathVector<dim> up_co_vel, down_co_vel;
800 if (ipNormalVel > 0)
801 {
802 up_co = from; down_co = to;
803 up_co_vel = from_co_vel; down_co_vel = to_co_vel;
804 }
805 else
806 {
807 up_co = to; down_co = from; ipNormalVel = - ipNormalVel;
808 up_co_vel = to_co_vel; down_co_vel = from_co_vel;
809 }
810
811 // assemble the fluxes
812 number corr_up, corr_down;
813 number src_up, src_down;
814 sol_update (false,
815 ipCoord, coCoord[up_co], extValue[up_co], grad[up_co], up_co_vel,
816 coCoord[down_co], extValue[down_co], grad[down_co], down_co_vel,
817 corr_up, corr_down, src_up, src_down);
818 if (base_co == up_co)
819 {
820 aaUpdate[ vVrt[base_co] ] -= ipNormalVel * corr_up / aaVolume[ vVrt[up_co] ];
821 if (aaSrc != NULL)
822 (*aaSrc) [ vVrt[base_co] ] -= ipNormalVel * src_up / aaVolume[ vVrt[up_co] ];
823 }
824 else
825 {
826 aaUpdate[ vVrt[base_co] ] += ipNormalVel * corr_down / aaVolume[ vVrt[down_co] ];
827 if (aaSrc != NULL)
828 (*aaSrc) [ vVrt[base_co] ] += ipNormalVel * src_down / aaVolume[ vVrt[down_co] ];
829 }
830
831 // the local Courant-number
832 if (m_spCourant.valid ())
833 {
834 const LocalIndices& ind = uOld.get_indices ();
835 size_t index, comp;
836
837 if (m_divFree)
838 { // consider the outflow faces:
839 number localCFL = m_dt * ipNormalVel / aaVolume[ vVrt[from] ];
840 index = ind.index (0, from); comp = ind.comp (0, from);
841 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
842 CFL_entry += localCFL;
843 }
844 else
845 { // consider inflow faces
846 number localCFL = m_dt * ipNormalVel / aaVolume[ vVrt[to] ];
847 index = ind.index (0, to); comp = ind.comp (0, to);
848 number& CFL_entry = BlockRef ((* m_spCourant) [index], comp);
849 CFL_entry += localCFL;
850 }
851 }
852 }
853 }
854
855# endif
856
857 return 0;
858}
859
863template<typename TGridFunction>
865(
866 TGridFunction& u,
868 ANumber& aVolume,
869 t_aaVol& aaVolume
870)
871{
872// get domain
873 domain_type& domain = *u.domain().get ();
874
875// get grid of domain
876 grid_type& grid = *domain.grid ();
877
878// initialize attachment value
879 SetAttachmentValues (aaVolume, grid.vertices_begin (), grid.vertices_end (), 0);
880
881// local values
882 MathVector<dim> coCoord[maxNumCo];
883 Vertex* vVrt[maxNumCo];
884
885// sum up all contributions of the sub control volumes to one vertex in an attachment
886 for (int si = 0; si < domain.subset_handler()->num_subsets (); si++)
887 {
888 // loop grid elements of the full dimensionality
889 ElemIterator iterEnd = u.template end<ElemType> (si);
890 for (ElemIterator iter = u.template begin<ElemType> (si); iter != iterEnd; ++iter)
891 {
892 ElemType* elem = *iter;
893
894 // get position accessor
895 const position_accessor_type& aaPos = domain.position_accessor ();
896
897 // get vertices and extract corner coordinates
898 const size_t numVertices = elem->num_vertices ();
899 for (size_t i = 0; i < numVertices; i++)
900 {
901 vVrt[i] = elem->vertex (i);
902 coCoord[i] = aaPos[vVrt[i]];
903 }
904
905 // evaluate finite volume geometry
906 geo.update (elem, coCoord, domain.subset_handler().get ());
907 size_t noc = geo.num_scv ();
908
909 // loop corners to get the volumes and average the gradients
910 for (size_t i = 0; i < noc; i++)
911 aaVolume[vVrt[i]] += geo.scv(i).volume ();
912 }
913 }
914
915# ifdef UG_PARALLEL
916 AttachmentAllReduce<Vertex> (grid, aVolume, PCL_RO_SUM);
917# endif
918}
919
923template<typename TGridFunction>
925(
926 DimFV1Geometry<dim> & geo,
927 number uValue [],
928 MathVector<dim> co_grad [],
929 number * lsf,
930 CplUserData<number,dim> * if_val_data,
931 int si
932)
933{
934 size_t noc = geo.num_scv ();
935
936// check the LSF
937 if (lsf == NULL || lsf_sign (noc, lsf) != 0) // if no LSF or not intersected
938 {
939 // loop corners to get the gradients
940 for (size_t i = 0; i < noc; i++)
941 {
942 // get scv
943 const typename DimFV1Geometry<dim>::SCV& scv = geo.scv (i);
944
945 // sum up gradients of shape functions in corner
946 co_grad[i] = 0.0;
947 for (size_t sh = 0; sh < noc; sh++)
948 VecScaleAppend (co_grad[i], uValue[sh], scv.global_grad (sh));
949 }
950 }
951 else // the element is intersected, process every corner separately
952 {
953 // loop corners to get the gradients
954 for (size_t i = 0; i < noc; i++)
955 {
956 // skip interface vertices
957 if (lsf[i] <= lsf_threshold () && lsf[i] >= - lsf_threshold ())
958 {
959 // this gradient is never really used: the value where it can occur are reset
960 co_grad[i] = 0;
961 continue;
962 }
963
964 // extrapolate the solution
965 number extValue [maxNumCo];
966 extrapolate_by_lsf (if_val_data, si, geo, uValue, lsf, i, extValue);
967
968 // get scv
969 const typename DimFV1Geometry<dim>::SCV& scv = geo.scv (i);
970
971 // sum up gradients of shape functions in corner
972 co_grad[i] = 0.0;
973 for (size_t sh = 0; sh < noc; sh++)
974 VecScaleAppend (co_grad[i], extValue[sh], scv.global_grad (sh));
975 }
976 }
977}
978
982template<typename TGridFunction>
984(
985 TGridFunction& u,
987 t_aaVol& aaVolume,
988 ADimVector& aGradient,
989 t_aaGrad& aaGradient,
990 TGridFunction * pLSF, //< the level-set function (if the interface should be specified)
991 CplUserData<number,dim> * if_val_data
992)
993{
994// get domain
995 domain_type& domain = *u.domain().get ();
996
997// get grid of domain
998 grid_type& grid = *domain.grid ();
999
1000// get position accessor
1001 const position_accessor_type& aaPos = domain.position_accessor ();
1002
1003// local algebra
1004 std::vector<DoFIndex> multInd;
1005 LocalIndices locInd; LocalVector locU; LocalVector locLSF;
1006
1007// initialize attachment value
1008 SetAttachmentValues (aaGradient, grid.vertices_begin (), grid.vertices_end (), 0);
1009
1010// local values
1011 MathVector<dim> coCoord[maxNumCo];
1012 Vertex* vVrt[maxNumCo];
1013 number uValue[maxNumCo];
1014 MathVector<dim> globalGrad [maxNumCo];
1015 number lsfValue[maxNumCo], * lsf;
1016
1017// sum up all contributions of the sub control volumes to one vertex in an attachment
1018 for (int si = 0; si < domain.subset_handler()->num_subsets (); si++)
1019 {
1020 //TODO: Skipping boundary here can lead to wrong computation of the velocity at the boundary, cannot it?
1021 // skip boundary
1022 // if (m_dirichlet_sg.size () != 0) if (m_dirichlet_sg.contains (si)) continue;
1023 // if (m_neumann_sg.size () != 0) if (m_neumann_sg.contains (si)) continue;
1024
1025 // loop grid elements of the full dimensionality
1026 ElemIterator iterEnd = u.template end<ElemType> (si);
1027 for (ElemIterator iter = u.template begin<ElemType> (si); iter != iterEnd; ++iter)
1028 {
1029 // get Elem
1030 ElemType* elem = *iter;
1031
1032 // get vertices and extract corner coordinates
1033 const size_t numVertices = elem->num_vertices ();
1034 for (size_t i = 0; i < numVertices; i++)
1035 {
1036 vVrt[i] = elem->vertex (i);
1037 coCoord[i] = aaPos[vVrt[i]];
1038 }
1039
1040 // evaluate finite volume geometry
1041 geo.update (elem, coCoord, domain.subset_handler().get ());
1042 size_t noc = geo.num_scv ();
1043
1044 // get the local solution
1045 u.indices (elem, locInd);
1046 locU.resize (locInd);
1047 GetLocalVector (locU, u);
1048 for (size_t i = 0; i < noc; i++)
1049 uValue[i] = locU (0, i);
1050
1051 // get the local LSF (if any)
1052 if (pLSF != NULL)
1053 {
1054 locLSF.resize (locInd);
1055 GetLocalVector (locLSF, *pLSF);
1056 for (size_t i = 0; i < noc; i++)
1057 lsfValue[i] = locLSF (0, i);
1058 lsf = lsfValue;
1059 }
1060 else
1061 lsf = NULL;
1062
1063 // get the gradient in the element
1064 compute_elem_grad (geo, uValue, globalGrad, lsf, if_val_data, si);
1065
1066 // loop corners to get the volumes and average the gradients
1067 for (size_t i = 0; i < noc; i++)
1068 {
1069 // scale gradient by volume
1070 globalGrad[i] *= geo.scv(i).volume ();
1071
1072 // add it to the nodal gradient
1073 aaGradient[vVrt[i]] += globalGrad[i];
1074 }
1075 }
1076 }
1077
1078# ifdef UG_PARALLEL
1079 AttachmentAllReduce<Vertex> (grid, aGradient, PCL_RO_SUM);
1080# endif
1081
1082// divide the gradients by the volumes
1083 for (int si = 0; si < u.num_subsets (); si++)
1084 {
1085 for (VertexConstIterator iter = u.template begin<Vertex> (si);
1086 iter != u.template end<Vertex> (si); ++iter)
1087 {
1088 // get vertex
1089 Vertex* vrt = *iter;
1090 if (aaVolume[vrt] != 0) //TODO: Eliminate this!
1091 aaGradient[vrt] /= aaVolume[vrt];
1092 }
1093 }
1094}
1095
1099template<typename TGridFunction>
1101(
1102 TGridFunction& numsol
1103)
1104{
1105// get domain of grid function
1106 domain_type& domain = *numsol.domain().get ();
1107 position_accessor_type aaPos = domain.position_accessor ();
1108
1109// loop the Dirichlet subsets
1110 std::vector<DoFIndex> ind (1);
1111 for (size_t i = 0; i < m_dirichlet_sg.size (); i++)
1112 {
1113 const int si = m_dirichlet_sg[i];
1114
1115 for (VertexConstIterator iter = numsol.template begin<Vertex> (si);
1116 iter != numsol.template end<Vertex> (si); ++iter)
1117 {
1118 // get vertex
1119 Vertex* vrt = *iter;
1120 number exactVal;
1121
1122 // get vector holding all indices on the vertex
1123 numsol.inner_dof_indices (vrt, 0, ind);
1124
1125 // get the bc and save it in the solution
1126 if (m_imDirichlet.valid ())
1127 (*m_imDirichlet) (&exactVal, &aaPos[vrt], m_time, si, 1);
1128 else
1129 exactVal = DoFRef (*m_oldSol, ind[0]);
1130 DoFRef (numsol, ind[0]) = exactVal;
1131 }
1132 }
1133}
1134
1141template<typename TGridFunction>
1143(
1144 TGridFunction& uOld,
1145 t_aaGrad& aaGrad
1146)
1147{
1148 grid_type& grid = *uOld.domain()->grid ();
1149 position_accessor_type& aaPos = uOld.domain()->position_accessor ();
1150
1151 std::vector<DoFIndex> ind;
1152
1153// create Attachment for scv-volume size
1154 ANumber aMax;
1155 ANumber aMin;
1156
1157// attach to grid
1158 grid.attach_to_vertices (aMin);
1159 grid.attach_to_vertices (aMax);
1160
1161// get attachment accessor to access values
1164 for (int si = 0; si < uOld.num_subsets(); si++)
1165 {
1166 for (VertexConstIterator iter = uOld.template begin<Vertex> (si);
1167 iter != uOld.template end<Vertex> (si); ++iter)
1168 {
1169 Vertex* vrt = *iter;
1170 MathVector<dim> coord;
1171 coord = aaPos[vrt];
1172 // read indices on vertex
1173 // get vector holding all indices on the vertex
1174 uOld.inner_dof_indices (vrt, 0, ind);
1175 aaMax[vrt] = DoFRef (uOld, ind[0]);
1176 aaMin[vrt] = DoFRef (uOld, ind[0]);
1177 }
1178 }
1179 for (int si = 0; si < uOld.num_subsets (); si++)
1180 {
1181 // Loop the edges
1182 for (EdgeConstIterator iter = uOld.template begin<Edge> (si);
1183 iter != uOld.template end<Edge> (si); ++iter)
1184 {
1185 Edge* edge = *iter;
1186 Vertex* vi = edge->vertex (0);
1187 Vertex* vj = edge->vertex (1);
1188 uOld.inner_dof_indices (vi, 0, ind);
1189 number ui = DoFRef (uOld, ind[0]);
1190 uOld.inner_dof_indices (vj, 0, ind);
1191 number uj = DoFRef (uOld, ind[0]);
1192 //UG_LOG ("edge " << aaPos[vi] << "-" << aaPos[vj] << " [" << ui << " " << uj << "]\n");
1193 if (uj<aaMin[vi])
1194 aaMin[vi] = uj;
1195 if (uj>aaMax[vi])
1196 aaMax[vi] = uj;
1197 if (ui<aaMin[vj])
1198 aaMin[vj] = ui;
1199 if (ui>aaMax[vj])
1200 aaMax[vj] = ui;
1201 }
1202 }
1203 for (int si = 0; si < uOld.num_subsets (); si++) //TODO Why originally only for Subset 0?
1204 {
1205 // skip the Dirichlet boundary
1206 //TODO: Is this true here?
1207 if (m_dirichlet_sg.size () != 0) if (m_dirichlet_sg.contains (si)) continue;
1208
1209 // Loop the edges
1210 for (EdgeConstIterator iter = uOld.template begin<Edge> (si);
1211 iter != uOld.template end<Edge> (si); ++iter)
1212 {
1213 Edge* edge = *iter;
1214 Vertex* vi = edge->vertex (0);
1215 Vertex* vj = edge->vertex (1);
1216 MathVector<dim> coordi,coordj,coordij,distVec,gradi,gradj;
1217 gradi = aaGrad[vi];
1218 gradj = aaGrad[vj];
1219 coordi = aaPos[vi];
1220 coordj = aaPos[vj];
1221 uOld.inner_dof_indices (vi, 0, ind);
1222 number ui = DoFRef (uOld, ind[0]);
1223 uOld.inner_dof_indices (vj, 0, ind);
1224 number uj = DoFRef (uOld, ind[0]);
1225 VecScaleAdd (coordij,0.5,coordi,0.5,coordj);
1226 VecSubtract (distVec, coordij,coordi);
1227 number uij = ui + distVec*gradi;
1228 number alpha = 1;
1229 if (uij > ui)
1230 {
1231 if (uij > aaMax[vi]) alpha = (aaMax[vi] - ui) / (distVec * gradi);
1232 if (alpha < 1)
1233 {
1234 //UG_LOG ("edge " << coordi << " " << coordj << "\n");
1235 //UG_LOG (coordi << " u " << ui << " uij " << uij << " max " << aaMax[vi] << " alpha " << alpha << "\n");
1236 aaGrad[vi] *= alpha;
1237 }
1238 }
1239 else
1240 {
1241 if (uij < aaMin[vi]) alpha = (aaMin[vi] - ui) / (distVec * gradi);
1242 if (alpha < 1)
1243 {
1244 //UG_LOG ("edge " << coordi << " " << coordj << "\n");
1245 //UG_LOG (coordi << " u " << ui << " uij " << uij << " min " << aaMax[vi] << " alpha " << alpha << "\n");
1246 aaGrad[vi] *= alpha;
1247 }
1248 }
1249 VecSubtract (distVec, coordij, coordj);
1250 uij = uj + distVec*gradj;
1251 alpha = 1;
1252 if (uij > uj)
1253 {
1254 if (uij > aaMax[vj]) alpha = (aaMax[vj] - uj) / (distVec * gradj);
1255 if (alpha < 1)
1256 {
1257 //UG_LOG ("-- edge " << coordi << " " << coordj << "\n");
1258 //UG_LOG (coordj << " u " << uj << " uij " << uij << " max " << aaMax[vj] << " alpha " << alpha << "\n");
1259 aaGrad[vj] *= alpha;
1260 }
1261 }
1262 else
1263 {
1264 if (uij < aaMin[vj]) alpha = (aaMin[vj] - uj) / (distVec * gradj);
1265 if (alpha < 1)
1266 {
1267 //UG_LOG ("-- edge " << coordi << " " << coordj << "\n");
1268 //UG_LOG (coordj << " u " << uj << " uij " << uij << " min " << aaMax[vj] << " alpha " << alpha << "\n");
1269 aaGrad[vj] *= alpha;
1270 }
1271 }
1272 // UG_LOG (" coord vertex 0 " << aaPos[v0] << " coord vertex 1 " << aaPos[v1] << "\n");
1273 }
1274
1275 // Loop full-dimensional grid elements
1276 Vertex* vVrt [maxNumCo];
1277 number u [maxNumCo];
1278 MathVector<dim> coCoord [maxNumCo];
1279 MathVector<dim> grad [maxNumCo];
1280 ElemIterator iterEnd = uOld.template end<ElemType> (si);
1281 for (ElemIterator iter = uOld.template begin<ElemType> (si); iter != iterEnd; ++iter)
1282 {
1283 // get Elem
1284 ElemType* elem = *iter;
1285
1286 // get position accessor
1287 const position_accessor_type& aaPos = uOld.domain()->position_accessor ();
1288
1289 // compute center of mass
1290 MathVector<dim> center;
1291 center=0;
1292 size_t noc = elem->num_vertices ();
1293 for (size_t i = 0; i < noc; i++)
1294 {
1295 vVrt[i] = elem->vertex (i);
1296 coCoord[i] = aaPos[vVrt[i]];
1297 grad[i] = aaGrad[vVrt[i]] ;
1298 VecAppend (center,coCoord[i]);
1299 uOld.inner_dof_indices (vVrt[i], 0, ind);
1300 u[i] = DoFRef (uOld, ind[0]);
1301 }
1302 center /= noc;
1303 for (size_t i = 0; i < noc; i++)
1304 {
1305 number alpha=1;
1306 MathVector<dim> distVec;
1307 number uCenter;
1308 VecSubtract (distVec, center, coCoord[i]);
1309 uCenter = u[i] + distVec * grad[i];
1310 if (uCenter > u[i])
1311 {
1312 if (uCenter > aaMax[vVrt[i]]) alpha = (aaMax[vVrt[i]] - u[i]) / (distVec * grad[i]);
1313 if (alpha < 1)
1314 {
1315 // UG_LOG ("* " << coCoord[i] << " uCenter " << uCenter << " ui " << u[i] << " max " << aaMax[vVrt[i]] << " alpha " << alpha << "\n");
1316 aaGrad[vVrt[i]] *= alpha;
1317 }
1318 }
1319 else
1320 {
1321 if (uCenter < aaMin[vVrt[i]]) alpha = (aaMin[vVrt[i]] - u[i]) / (distVec * grad[i]);
1322 if (alpha < 1)
1323 {
1324 // UG_LOG ("*#* " << coCoord[i] << " uCenter " << uCenter << " ui " << u[i] << " min " << aaMin[vVrt[i]] << " alpha " << alpha << "\n");
1325 aaGrad[vVrt[i]] *= alpha;
1326 }
1327 }
1328 }
1329 }
1330 }
1331 // detach from grid
1332 grid.detach_from_vertices (aMin);
1333 grid.detach_from_vertices (aMax);
1334}
1335
1342template<typename TGridFunction>
1344{
1345// should we compute anything?
1346 if (m_nrOfSteps <= 0) return;
1347
1348// get the grid functions
1349 if (m_oldSol.invalid () || m_newSol.invalid ())
1350 UG_THROW ("Grid functions for the solutions not specified.");
1351 TGridFunction& uOld = *m_oldSol;
1352 TGridFunction& uNew = *m_newSol;
1353
1354// get domain of grid function
1355 domain_type& domain = *uNew.domain().get ();
1356
1357// get the position accessor
1358 position_accessor_type aaPos = domain.position_accessor ();
1359
1360// get grid of domain
1361 grid_type& grid = *domain.grid ();
1362
1363// attachment for scv-volume size
1364 ANumber aScvVolume;
1365
1366// attachment for gradient
1367 ADimVector aGradient; // gradient of the solution
1368 ADimVector aVelGrad; // gradient used for the velocity (if any)
1369 ADimVector aSDFGrad; // gradient of the signed-distance function (if any)
1370
1371// attachments for the updates of the solution (due to the avective terms and the source)
1372 ANumber aUpdate;
1373 ANumber aSrc;
1374
1375// attachment for the update of the SDF (if needed)
1376 ANumber aSDFUpdate;
1377
1378// attachment to mark corners of intersected elements
1379 ABool aCoIE; // Corner of Intersected Element
1380
1381// attach to grid
1382 grid.attach_to_vertices (aScvVolume);
1383 grid.attach_to_vertices (aGradient);
1384 grid.attach_to_vertices (aUpdate);
1385 grid.attach_to_vertices (aSrc);
1386 grid.attach_to_vertices (aCoIE);
1387
1388// get attachment accessor to access values
1389 t_aaVol aaVolume (grid, aScvVolume);
1390 t_aaGrad aaGradient (grid, aGradient);
1391 t_aaUpd aaUpdate (grid, aUpdate);
1392 t_aaUpd aaSrc (grid, aSrc);
1393 t_aaCoIE aaCoIE (grid, aCoIE);
1394 t_aaGrad aaVelGrad;
1395 t_aaGrad aaSDFGrad;
1396 t_aaUpd aaSDFUpdate;
1397
1398// FV geometry
1400
1401// specify the neumann (outflow) bnd subsets for the geometry, so that the
1402// geometry produces boundary faces (BF) for all sides of the
1403// element, that is in one of the subsets
1404 for (size_t i = 0; i < m_neumann_sg.size (); i++)
1405 geo.add_boundary_subset (m_neumann_sg[i]);
1406
1407// calculate scv volume
1408 compute_volumes (uNew, geo, aScvVolume, aaVolume);
1409
1410// attachment for the gradient used for the velocity
1411 if (m_spVelPot.valid () && m_spVelPot != m_oldSol)
1412 {
1413 // attach, access and compute
1414 grid.attach_to_vertices (aVelGrad);
1415 aaVelGrad.access (grid, aVelGrad);
1416 compute_vertex_grad (*m_spVelPot, geo, aaVolume, aVelGrad, aaVelGrad, m_spLSF.get());
1417 if (m_limiter)
1418 limit_grad (*m_spVelPot, aaVelGrad);
1419 }
1420 else
1421 {
1422 // use the gradient of the old solution for it
1423 aaVelGrad.access (grid, aGradient); // merely redirect the accessor
1424 }
1425
1426// attachment for the gradient of the SDF
1427 if (m_spLSF.valid ())
1428 {
1429 if (m_spSDF.invalid ())
1430 UG_THROW ("Computation with the LSF interface is only possible with the SDF. Specify it!");
1431
1432 if (m_spSDF == m_oldSol)
1433 { // merely redirect the accessors
1434 aaSDFGrad.access (grid, aGradient);
1435 aaSDFUpdate.access (grid, aUpdate);
1436 }
1437 else if (m_spSDF == m_spVelPot)
1438 {
1439 // merely redirect the accessor for the gradient
1440 aaSDFGrad.access (grid, aVelGrad);
1441 // attach and access the update
1442 grid.attach_to_vertices (aSDFUpdate);
1443 aaSDFUpdate.access (grid, aSDFUpdate);
1444 }
1445 else
1446 {
1447 // attach, access and compute the gradient
1448 grid.attach_to_vertices (aSDFGrad);
1449 aaSDFGrad.access (grid, aSDFGrad);
1450 compute_vertex_grad (*m_spSDF, geo, aaVolume, aSDFGrad, aaSDFGrad, m_spLSF.get());
1451 if (m_limiter)
1452 limit_grad (*m_spSDF, aaSDFGrad);
1453 // attach and access the update
1454 grid.attach_to_vertices (aSDFUpdate);
1455 aaSDFUpdate.access (grid, aSDFUpdate);
1456 }
1457 }
1458
1459// mark the corners of the intersected elements
1460 mark_CoIE (grid, aCoIE, aaCoIE);
1461
1462 MathVector<dim> coord;
1463 std::vector<DoFIndex> ind;
1464
1465// local indices and values
1466 LocalIndices locInd; LocalVector locOldU, locLSF, locVelPot;
1467
1468 if (this->debug_writer_valid())
1469 {
1470 this->write_debug (uNew, "HR-FB-LSM-sol_step_0");
1471 }
1472
1473// computation of the time steps
1474 size_t step = 1;
1475 VecAssign (uOld, uNew);
1476 m_CFL = 0; // the Courant number over all the steps
1477 while (true)
1478 {
1479 // set the Courant number for OUTPUT to 0
1480 number current_CFL = 0;
1481 if (m_spCourant.valid ())
1482 {
1483 (* m_spCourant) = 0.0;
1484 #ifdef UG_PARALLEL
1485 m_spCourant->set_storage_type (PST_ADDITIVE);
1486 #endif
1487 }
1488 else
1489 {
1490 if (m_time_control)
1491 UG_THROW ("Time control is only possible if a grid function is specified for CFL (by save_CourantNumber_to)");
1492 }
1493
1494 // indicators of wrong signes of the gradient
1495 bool wrong_sgn_at_if_A = false, wrong_sgn_at_if_B = false;
1496
1497 // compute scv volume and the gradient
1498 compute_vertex_grad (uOld, geo, aaVolume, aGradient, aaGradient, m_spLSF.get(), m_imInterfaceVal.get ());
1499 if (m_limiter)
1500 limit_grad (uOld, aaGradient);
1501
1502 // initialize attachment values
1503 SetAttachmentValues (aaUpdate, grid.vertices_begin (), grid.vertices_end (), 0);
1504 SetAttachmentValues (aaSrc, grid.vertices_begin (), grid.vertices_end (), 0);
1505 if (m_spLSF.valid () && m_spSDF != m_oldSol)
1506 SetAttachmentValues (aaSDFUpdate, grid.vertices_begin (), grid.vertices_end (), 0);
1507
1508 // loop over subsets to compute the new solution
1509 for (int si = 0; si < uOld.num_subsets (); si++)
1510 {
1511 // loop elements compute the update of the solution
1512 ElemIterator iterEnd = uNew.template end<ElemType> (si);
1513 for (ElemIterator iter = uNew.template begin<ElemType> (si); iter != iterEnd; ++iter)
1514 {
1515 ElemType* elem = *iter;
1516 uNew.indices (elem, locInd);
1517 locOldU.resize (locInd);
1518
1519 GetLocalVector (locOldU, uOld);
1520 if (m_spLSF.invalid ())
1521 assemble_element (elem, geo, domain, locOldU, aaGradient, aaVelGrad, aaVolume, 0, aaUpdate, &aaSrc);
1522 else
1523 {
1524 locLSF.resize (locInd); locVelPot.resize (locInd);
1525 int sign = assemble_cut_element
1526 (elem, geo, domain, locOldU, locLSF, locVelPot,
1527 aaGradient, aaVelGrad, aaVolume, aaUpdate, &aaSrc, m_imInterfaceVal.get (), si);
1528 if (sign != 0)
1529 assemble_element (elem, geo, domain, locOldU,
1530 aaGradient, aaVelGrad, aaVolume, sign, aaUpdate, &aaSrc);
1531 }
1532 }
1533
1534 // loop elements to assemble the update of the SDF (if needed)
1535 if (m_spLSF.valid () && m_spSDF != m_oldSol)
1536 for (ElemIterator iter = uNew.template begin<ElemType> (si); iter != iterEnd; ++iter)
1537 {
1538 ElemType* elem = *iter;
1539
1540 // check whether we need this element: we assemble only the elements with marked corners
1541 for (size_t co = 0; co < elem->num_vertices (); co++)
1542 if (aaCoIE [elem->vertex (co)])
1543 {
1544 m_spSDF->indices (elem, locInd);
1545 locOldU.resize (locInd); locLSF.resize (locInd); locVelPot.resize (locInd);
1546
1547 GetLocalVector (locOldU, *m_spSDF);
1548 int sign = assemble_cut_element
1549 (elem, geo, domain, locOldU, locLSF, locVelPot,
1550 aaSDFGrad, aaVelGrad, aaVolume, aaSDFUpdate, NULL, NULL, si);
1551 if (sign != 0)
1552 assemble_element (elem, geo, domain, locOldU,
1553 aaSDFGrad, aaVelGrad, aaVolume, sign, aaSDFUpdate, NULL);
1554
1555 break;
1556 }
1557 }
1558 }
1559
1560# ifdef UG_PARALLEL
1561 AttachmentAllReduce<Vertex> (grid, aUpdate, PCL_RO_SUM);
1562 AttachmentAllReduce<Vertex> (grid, aSrc, PCL_RO_SUM);
1563 if (m_spLSF.valid () && m_spSDF != m_oldSol)
1564 AttachmentAllReduce<Vertex> (grid, aSDFUpdate, PCL_RO_SUM);
1565 if (m_spCourant.valid ())
1566 m_spCourant->change_storage_type (PST_CONSISTENT);
1567# endif
1568
1569 // check the CFL
1570 if (m_spCourant.valid ())
1571 {
1572 current_CFL = 0;
1573 for (VertexConstIterator iter = m_spCourant->template begin<Vertex> ();
1574 iter != m_spCourant->template end<Vertex> (); ++iter)
1575 {
1576 m_spCourant->inner_dof_indices (*iter, 0, ind);
1577 number local_CFL = DoFRef (*m_spCourant, ind[0]);
1578 if (local_CFL > current_CFL)
1579 current_CFL = local_CFL;
1580 }
1581# ifdef UG_PARALLEL
1582 {
1583 pcl::ProcessCommunicator procComm;
1584 current_CFL = procComm.allreduce (current_CFL, PCL_RO_MAX);
1585 }
1586# endif
1587 }
1588 if (m_time_control && current_CFL > 1e-10 && (current_CFL < m_minCFL || current_CFL > m_maxCFL))
1589 {
1590 number old_dt = m_dt;
1591 m_dt = m_dt / current_CFL * (m_minCFL + m_maxCFL) / 2;
1592 if (m_bVerbose)
1593 UG_LOG ("CFL " << current_CFL << " ... resetting time step: " << old_dt << " -> " << m_dt << "\n");
1594 continue; // recompute the step
1595 }
1596
1597 // take into account the source at the vertices and update the solution
1598 for (int si = 0; si < uOld.num_subsets (); si++)
1599 {
1600 // skip the Dirichlet boundary
1601 if (m_dirichlet_sg.size () != 0) if (m_dirichlet_sg.contains (si)) continue;
1602
1603 for (VertexConstIterator iter = uNew.template begin<Vertex> (si);
1604 iter != uNew.template end<Vertex> (si); ++iter)
1605 {
1606 Vertex* vrt = *iter;
1607 uNew.inner_dof_indices (vrt, 0, ind);
1608 if (!aaCoIE[vrt])
1609 {// just a normal vertex, not at the interface
1610 number co_source;
1611 if (m_spLSF.valid ())
1612 co_source = (DoFRef (*m_spLSF, ind[0]) >= 0)? m_source_pos : m_source_neg;
1613 else
1614 co_source = m_source_pos;
1615 if (m_antiderivSrc) co_source *= aaSrc[vrt];
1616 DoFRef (uNew, ind[0]) += m_dt * (aaUpdate[vrt] + co_source);
1617 }
1618 else
1619 {// at the interface; try to change the time step
1620 number lsf_val = DoFRef (*m_spLSF, ind[0]);
1621 number sdf_update = aaSDFUpdate[vrt];
1622 number dt_eff = - DoFRef (*m_spSDF, ind[0]) / sdf_update; // note that this is "-" normalized gradient!
1623 if (dt_eff > m_dt)
1624 dt_eff = m_dt;
1625 if (lsf_val > lsf_threshold ())
1626 {
1627 if (sdf_update >= 0)
1628 { // this should not happen
1629 wrong_sgn_at_if_A = true;
1630 DoFRef (uNew, ind[0]) += m_dt * m_source_pos; // only the source term
1631 }
1632 else
1633 {
1634 number co_source = m_source_pos;
1635 if (m_antiderivSrc) co_source *= aaSrc[vrt];
1636 DoFRef (uNew, ind[0]) += dt_eff * (aaUpdate[vrt] + co_source);
1637 }
1638 }
1639 else if (lsf_val < - lsf_threshold ())
1640 {
1641 if (sdf_update <= 0)
1642 { // this should not happen
1643 wrong_sgn_at_if_B = true;
1644 DoFRef (uNew, ind[0]) += m_dt * m_source_neg; // only the source term
1645 }
1646 else
1647 {
1648 number co_source = m_source_neg;
1649 if (m_antiderivSrc) co_source *= aaSrc[vrt];
1650 DoFRef (uNew, ind[0]) += dt_eff * (aaUpdate[vrt] + co_source);
1651 }
1652 }
1653 else // we consider the vertex as lying directly at the interface
1654 {
1655 if (m_imInterfaceVal.invalid ())
1656 DoFRef (uNew, ind[0]) = 0;
1657 else
1658 (* m_imInterfaceVal) (DoFRef (uNew, ind[0]), aaPos[vrt], m_time, si, vrt);
1659 }
1660 }
1661 }
1662 }
1663
1664 // warnings
1665 if (wrong_sgn_at_if_A)
1666 UG_LOG ("advect: Wrong (non-negative) sign of the gradient occured!\n");
1667 if (wrong_sgn_at_if_B)
1668 UG_LOG ("advect: Wrong (non-positive) sign of the gradient occured!\n");
1669
1670 // the new solution computed
1671 m_time += m_dt;
1672
1673 // set the Dirichlet values
1674 assign_dirichlet (uNew);
1675
1676 // update the total CFL
1677 if (current_CFL > m_CFL) m_CFL = current_CFL;
1678
1679 // the time step is done
1680 if (m_bVerbose)
1681 {
1682 UG_LOG ("step length: " << m_dt << " (step # " << step << ")\n");
1683 UG_LOG ("time: " << m_time << "\n");
1684 UG_LOG ("CFL in step: " << current_CFL << "\n");
1685
1686 UG_LOG ("advect: TS # " << step << ", time " << m_time << " (dt = " << m_dt << ")");
1687 if (m_spCourant.valid ())
1688 UG_LOG (", CFL = " << current_CFL);
1689 UG_LOG ("\n");
1690 }
1691
1692 if (this->debug_writer_valid())
1693 {
1694 char debug_file_name [128];
1695 snprintf (debug_file_name, 128, "HR-FB-LSM-sol_step_%d", (int) step);
1696 this->write_debug (uNew, debug_file_name);
1697 }
1698
1699 // is that all?
1700 if (step >= m_nrOfSteps)
1701 break;
1702 else
1703 {
1704 step++;
1705 VecAssign (uOld, uNew);
1706 }
1707 }
1708
1709 if (! m_bVerbose)
1710 {
1711 UG_LOG ("advect: " << step << " step(s) done, last dt: " << m_dt);
1712 if (m_spCourant.valid ())
1713 UG_LOG (", max. CFL = " << m_CFL);
1714 UG_LOG ("\n");
1715 }
1716
1717// detach from grid
1718 if (m_spVelPot.valid () && m_spVelPot != m_oldSol)
1719 grid.detach_from_vertices (aVelGrad);
1720 if (m_spLSF.valid () && m_spSDF != m_oldSol)
1721 {
1722 grid.detach_from_vertices (aSDFUpdate);
1723 if (m_spSDF != m_spVelPot)
1724 grid.detach_from_vertices (aSDFGrad);
1725 }
1726 grid.detach_from_vertices (aCoIE);
1727 grid.detach_from_vertices (aSrc);
1728 grid.detach_from_vertices (aUpdate);
1729 grid.detach_from_vertices (aGradient);
1730 grid.detach_from_vertices (aScvVolume);
1731}
1732
1736template<typename TGridFunction>
1738(
1739 SmartPtr<CplUserData<MathVector<dim>, dim> > spVelField,
1740 SmartPtr<TGridFunction> spNormVel
1741)
1742{
1743// we need the solution
1744 if (! m_spLSF.valid ())
1745 UG_THROW ("Specify the level-set function!");
1746
1747// get domain
1748 domain_type& domain = * (m_spLSF->domain().get ());
1749
1750// get grid of domain
1751 grid_type& grid = *domain.grid ();
1752
1753// get position accessor
1754 const position_accessor_type& aaPos = domain.position_accessor ();
1755
1756// FV geometry
1758
1759// specify the neumann (outflow) bnd subsets for the geometry, so that the
1760// geometry produces boundary faces (BF) for all sides of the
1761// element, that is in one of the subsets
1762 for (size_t i = 0; i < m_neumann_sg.size (); i++)
1763 geo.add_boundary_subset (m_neumann_sg[i]);
1764
1765// get the total scv volumes
1766 ANumber aScvVolume;
1767 grid.attach_to_vertices (aScvVolume);
1768 t_aaVol aaVolume (grid, aScvVolume);
1769 compute_volumes (*m_spLSF, geo, aScvVolume, aaVolume);
1770
1771// attach, access and compute the gradient
1772 ADimVector aGradient;
1773 grid.attach_to_vertices (aGradient);
1774 t_aaGrad aaGradient (grid, aGradient);
1775 compute_vertex_grad (*m_spLSF, geo, aaVolume, aGradient, aaGradient); /* do not specify the interface here! */
1776 if (m_limiter)
1777 limit_grad (*m_spLSF, aaGradient);
1778
1779// local indices
1780 std::vector<DoFIndex> ind;
1781
1782// from now on, aScvVolume will keep the volumes unter the interface
1783 SetAttachmentValues (aaVolume, grid.vertices_begin (), grid.vertices_end (), 0);
1784
1785// reset the data
1786 (*spNormVel) = 0.0;
1787
1788// loop over subsets to sum up the normal velocities
1789 for (int si = 0; si < m_spLSF->num_subsets (); si++)
1790 {
1791 ElemIterator iterEnd = m_spLSF->template end<ElemType> (si);
1792 for (ElemIterator iter = m_spLSF->template begin<ElemType> (si); iter != iterEnd; ++iter)
1793 {
1794 ElemType* elem = *iter;
1795
1796 // check if this is no "outside" element
1797 number uValue[maxNumCo];
1798 Vertex* vVrt[maxNumCo];
1799 bool elem_outside = true;
1800 for (size_t i = 0; i < elem->num_vertices (); ++i)
1801 {
1802 Vertex* vrt = elem->vertex (i);
1803 m_spLSF->inner_dof_indices ((vVrt[i] = vrt), 0, ind);
1804 uValue[i] = DoFRef (*m_spLSF, ind[0]);
1805 if (uValue[i] < - lsf_threshold ())
1806 elem_outside = false;
1807 }
1808
1809 if (elem_outside)
1810 continue; // we do not consider this element
1811
1812 // get vertices and extract corner coordinates
1813 MathVector<dim> coCoord[maxNumCo];
1814 for (size_t i = 0; i < elem->num_vertices (); ++i)
1815 coCoord[i] = aaPos[vVrt[i]];
1816
1817 // update fv geometry
1818 geo.update (elem, coCoord, domain.subset_handler().get ());
1819 size_t noc = geo.num_scv ();
1820
1821 // get the nodal velocity
1822 MathVector<dim> co_vel[maxNumCo];
1823 if (m_elem_vel_vec)
1824 {
1825 (*spVelField) (co_vel, geo.coe_global (), m_time, si,
1826 elem, geo.corners (), geo.coe_local (), 1, NULL);
1827 for (size_t i = 1; i < noc; i++) co_vel[i] = co_vel[0];
1828 }
1829 else
1830 (*spVelField) (co_vel, geo.scv_global_ips (), m_time, si,
1831 elem, geo.corners (), geo.scv_local_ips (), noc, NULL);
1832
1833 // compute the normal velocity
1834 for (size_t i = 0; i < noc; i++)
1835 {
1836 Vertex* vrt = vVrt[i];
1837 number vol = geo.scv(i).volume ();
1838 number gnorm = VecLength (aaGradient [vrt]);
1839 if (gnorm >= lsf_threshold ())
1840 {
1841 spNormVel->inner_dof_indices (vrt, 0, ind);
1842 DoFRef (*spNormVel, ind[0]) += (co_vel [i] * aaGradient [vrt]) * vol / gnorm;
1843 }
1844 aaVolume[vrt] += vol;
1845 }
1846 }
1847 }
1848
1849# ifdef UG_PARALLEL
1850 AttachmentAllReduce<Vertex> (grid, aScvVolume, PCL_RO_SUM);
1851 spNormVel->set_storage_type (PST_ADDITIVE);
1852 spNormVel->change_storage_type (PST_CONSISTENT);
1853# endif
1854
1855// loop over subsets to divide the normal velocities by the volumes
1856 for (int si = 0; si < m_spLSF->num_subsets (); si++)
1857 {
1858 for (VertexConstIterator iter = m_spLSF->template begin<Vertex> (si);
1859 iter != m_spLSF->template end<Vertex> (si); ++iter)
1860 {
1861 Vertex* vrt = *iter;
1862 number vol = aaVolume[vrt];
1863 if (vol == 0)
1864 continue; // we are not under the interface!
1865 spNormVel->inner_dof_indices (vrt, 0, ind);
1866 DoFRef (*spNormVel, ind[0]) /= vol;
1867 }
1868 }
1869
1870// detach from the grid
1871 grid.detach_from_vertices (aGradient);
1872 grid.detach_from_vertices (aScvVolume);
1873}
1874
1878template<typename TGridFunction>
1880(
1881 SmartPtr<CplUserData<number, dim> > spZVelField,
1882 SmartPtr<TGridFunction> spNormVel
1883)
1884{
1885// we need the solution
1886 if (! m_spLSF.valid ())
1887 UG_THROW ("Specify the level-set function!");
1888
1889// get domain
1890 domain_type& domain = * (m_spLSF->domain().get ());
1891
1892// get grid of domain
1893 grid_type& grid = *domain.grid ();
1894
1895// get position accessor
1896 const position_accessor_type& aaPos = domain.position_accessor ();
1897
1898// FV geometry
1900
1901// specify the neumann (outflow) bnd subsets for the geometry, so that the
1902// geometry produces boundary faces (BF) for all sides of the
1903// element, that is in one of the subsets
1904 for (size_t i = 0; i < m_neumann_sg.size (); i++)
1905 geo.add_boundary_subset (m_neumann_sg[i]);
1906
1907// Attachment for the contribution of the normal velocity
1908 ANumber aNVelocity;
1909 grid.attach_to_vertices (aNVelocity);
1910 t_aaVol aaNVel (grid, aNVelocity);
1911 SetAttachmentValues (aaNVel, grid.vertices_begin (), grid.vertices_end (), 0);
1912
1913// get the total scv volumes
1914 ANumber aScvVolume;
1915 grid.attach_to_vertices (aScvVolume);
1916 t_aaVol aaVolume (grid, aScvVolume);
1917 compute_volumes (*m_spLSF, geo, aScvVolume, aaVolume);
1918
1919// attach, access and compute the gradient
1920 ADimVector aGradient;
1921 grid.attach_to_vertices (aGradient);
1922 t_aaGrad aaGradient (grid, aGradient);
1923 compute_vertex_grad (*m_spLSF, geo, aaVolume, aGradient, aaGradient); /* do not specify the interface here! */
1924 if (m_limiter)
1925 limit_grad (*m_spLSF, aaGradient);
1926
1927// local indices
1928 std::vector<DoFIndex> ind;
1929
1930// from now on, aScvVolume will keep the volumes unter the interface
1931 SetAttachmentValues (aaVolume, grid.vertices_begin (), grid.vertices_end (), 0);
1932
1933// loop over subsets to sum up the normal velocities
1934 for (int si = 0; si < m_spLSF->num_subsets (); si++)
1935 {
1936 ElemIterator iterEnd = m_spLSF->template end<ElemType> (si);
1937 for (ElemIterator iter = m_spLSF->template begin<ElemType> (si); iter != iterEnd; ++iter)
1938 {
1939 ElemType* elem = *iter;
1940
1941 // check if this is an "outside" element
1942 number uValue[maxNumCo];
1943 Vertex* vVrt[maxNumCo];
1944 bool elem_outside = true;
1945 for (size_t i = 0; i < elem->num_vertices (); ++i)
1946 {
1947 Vertex* vrt = elem->vertex (i);
1948 m_spLSF->inner_dof_indices ((vVrt[i] = vrt), 0, ind);
1949 uValue[i] = DoFRef (*m_spLSF, ind[0]);
1950 if (uValue[i] < - lsf_threshold ())
1951 elem_outside = false;
1952 }
1953
1954 if (elem_outside)
1955 continue; // we do not consider this element
1956
1957 // get vertices and extract corner coordinates
1958 MathVector<dim> coCoord[maxNumCo];
1959 for (size_t i = 0; i < elem->num_vertices (); ++i)
1960 coCoord[i] = aaPos[vVrt[i]];
1961
1962 // update fv geometry
1963 geo.update (elem, coCoord, domain.subset_handler().get ());
1964 size_t noc = geo.num_scv ();
1965
1966 // get the nodal velocity
1967 number co_nVel[maxNumCo];
1968 (*spZVelField) (co_nVel, geo.scv_global_ips (), m_time, si,
1969 elem, geo.corners (), geo.scv_local_ips (), noc, NULL);
1970
1971 // compute the normal velocity
1972 for (size_t i = 0; i < noc; i++)
1973 {
1974 Vertex* vrt = vVrt[i];
1975 number vol = geo.scv(i).volume ();
1976 number gnorm = VecLength (aaGradient [vrt]);
1977 if (gnorm >= lsf_threshold ())
1978 {
1979 aaNVel [vrt] += (co_nVel [i] * aaGradient [vrt] [dim-1]) * vol / gnorm;
1980 }
1981 aaVolume[vrt] += vol;
1982 }
1983 }
1984 }
1985
1986# ifdef UG_PARALLEL
1987 AttachmentAllReduce<Vertex> (grid, aScvVolume, PCL_RO_SUM);
1988 AttachmentAllReduce<Vertex> (grid, aNVelocity, PCL_RO_SUM);
1989# endif
1990
1991// loop over subsets to divide the normal velocities by the volumes
1992 for (int si = 0; si < m_spLSF->num_subsets (); si++)
1993 {
1994 for (VertexConstIterator iter = m_spLSF->template begin<Vertex> (si);
1995 iter != m_spLSF->template end<Vertex> (si); ++iter)
1996 {
1997 Vertex* vrt = *iter;
1998 number vol = aaVolume[vrt];
1999 if (vol == 0)
2000 continue; // we are not under the interface!
2001 spNormVel->inner_dof_indices (vrt, 0, ind);
2002 DoFRef (*spNormVel, ind[0]) += aaNVel [vrt] / vol;
2003 }
2004 }
2005
2006// detach from the grid
2007 grid.detach_from_vertices (aGradient);
2008 grid.detach_from_vertices (aScvVolume);
2009 grid.detach_from_vertices (aNVelocity);
2010}
2011
2015template<typename TGridFunction>
2017(
2018 const char* subsets
2019)
2020{
2021 if (m_dirichlet_sg.subset_handler().invalid ())
2022 {
2023 if (m_newSol.invalid ())
2024 UG_THROW ("Grid function for the solution not set.");
2025 m_dirichlet_sg.set_subset_handler (m_newSol->subset_handler ());
2026 }
2027
2028 m_dirichlet_sg.add (TokenizeString (subsets));
2029}
2030
2034template<typename TGridFunction>
2036(
2037 const char* subsets
2038)
2039{
2040 if (m_neumann_sg.subset_handler().invalid ())
2041 {
2042 if (m_newSol.invalid ())
2043 UG_THROW ("Grid function for the solution not set.");
2044 m_neumann_sg.set_subset_handler (m_newSol->subset_handler ());
2045 }
2046
2047 m_neumann_sg.add (TokenizeString (subsets));
2048}
2049
2053template<typename TGridFunction>
2055(
2057 number eps
2058)
2059{
2060 if (m_newSol.invalid ())
2061 UG_THROW ("compare_lsf_with: Solution is not specified!\n");
2062
2063 bool check_failed = false;
2064 std::vector<DoFIndex> ind;
2065
2066// get domain
2067 domain_type& domain = * (m_newSol->domain().get ());
2068
2069// get position accessor
2070 const position_accessor_type& aaPos = domain.position_accessor ();
2071
2072// 1. Compare the values at the vertices
2073 UG_LOG ("--- Checking solution, phase 1: Nodal values\n");
2074 for (int si = 0; si < domain.subset_handler()->num_subsets (); si++)
2075 {
2076 UG_LOG (" -- subset "<< si << "\n");
2077 for (VertexConstIterator iter = m_newSol->template begin<Vertex> (si);
2078 iter != m_newSol->template end<Vertex> (si); ++iter)
2079 {
2080 // get vertex
2081 Vertex* vrt = *iter;
2082 // get the index in the vector
2083 m_newSol->inner_dof_indices (vrt, 0, ind);
2084 // compare the values
2085 number lsf_1 = DoFRef (*m_newSol, ind[0]);
2086 number lsf_2 = DoFRef (*spLSF2, ind[0]);
2087 if (lsf_1 * lsf_2 <= 0 && (lsf_1 != 0 || lsf_2 != 0))
2088 {
2089 check_failed = true;
2090 UG_LOG (" > vertex " << vrt->grid_data_index() << " @ (" << aaPos[vrt][0]);
2091 for (size_t i = 1; i < dim; i++)
2092 UG_LOG (", " << aaPos[vrt][i]);
2093 UG_LOG ("): sol = " << lsf_1 << ", lsf = " << lsf_2 << "\n");
2094 }
2095 }
2096 }
2097 if (check_failed)
2098 {
2099 UG_LOG ("--- failed.\n");
2100 return;
2101 }
2102 UG_LOG ("--- passed.\n");
2103
2104// 2. Compare the interface in the elements
2105 UG_LOG ("--- Checking solution, phase 2: Interface in the elements\n");
2106 for (int si = 0; si < domain.subset_handler()->num_subsets (); si++)
2107 {
2108 UG_LOG (" -- subset "<< si << "\n");
2109 // loop grid elements of the full dimensionality
2110 ElemIterator iterEnd = m_newSol->template end<ElemType> (si);
2111 for (ElemIterator iter = m_newSol->template begin<ElemType> (si); iter != iterEnd; ++iter)
2112 {
2113 ElemType* elem = *iter;
2114 const size_t numVertices = elem->num_vertices ();
2115
2116 // local values
2117 Vertex* vVrt[maxNumCo];
2118 number lsf_1 [maxNumCo], lsf_2 [maxNumCo];
2119
2120 // get the vertices, extract the values of the functions
2121 for (size_t i = 0; i < numVertices; i++)
2122 {
2123 vVrt[i] = elem->vertex (i);
2124 m_newSol->inner_dof_indices (vVrt[i], 0, ind);
2125 lsf_1[i] = DoFRef (*m_newSol, ind[0]);
2126 lsf_2[i] = DoFRef (*spLSF2, ind[0]);
2127 }
2128
2129 // check if this is an interface element
2130 if (lsf_sign (numVertices, lsf_1) != 0)
2131 continue;
2132
2133 // check the position of the interface
2134 bool bad_if_elem = false;
2135 number param_1 [maxNumCo][maxNumCo];
2136 number param_2 [maxNumCo][maxNumCo];
2137 memset (param_1, 0, maxNumCo * maxNumCo * sizeof (number));
2138 memset (param_2, 0, maxNumCo * maxNumCo * sizeof (number));
2139 for (size_t i = 0; i < numVertices; i++)
2140 for (size_t j = i + 1; j < numVertices; j++)
2141 {
2142 if (lsf_1[i] * lsf_1[j] > 0) continue;
2143 param_1[i][j] = lsf_1[i] / (lsf_1[i] - lsf_1[j]);
2144 param_2[i][j] = lsf_2[i] / (lsf_2[i] - lsf_2[j]);
2145 if (std::fabs (param_1[i][j] - param_2[i][j]) >= eps)
2146 bad_if_elem = true;
2147 }
2148 if (bad_if_elem)
2149 {
2150 check_failed = true;
2151 UG_LOG (" > elem " << elem->grid_data_index() << " (" << numVertices << " corners):\n");
2152 for (size_t i = 0; i < numVertices; i++)
2153 {
2154 UG_LOG (" : " << i << " @ (" << aaPos[vVrt[i]][0]);
2155 for (size_t j = 1; j < dim; j++)
2156 UG_LOG (", " << aaPos[vVrt[i]][j]);
2157 UG_LOG ("): sol = " << lsf_1[i] << ", lsf = " << lsf_2[i] << "\n");
2158 }
2159 for (size_t i = 0; i < numVertices; i++)
2160 for (size_t j = i + 1; j < numVertices; j++)
2161 if (std::fabs (param_1[i][j] - param_2[i][j]) >= eps)
2162 UG_LOG (" ! " << i << " to " << j << ": sol = " << param_1[i][j] << ", lsf = " << param_2[i][j] << "\n");
2163 }
2164 }
2165 }
2166 if (check_failed)
2167 {
2168 UG_LOG ("--- failed.\n");
2169 return;
2170 }
2171 UG_LOG ("--- passed.\n");
2172}
2173
2174} // end namespace LevelSet
2175} // end namespace ug
2176
2177/* End of File */
parameterString s
Definition Biogas.lua:2
size_t allreduce(const size_t &t, pcl::ReduceOperation op) const
number shape(size_t sh) const
size_t node_id() const
const MathVector< worldDim > & normal() const
const MathVector< worldDim > & global_ip() const
const MathVector< worldDim > & global_grad(size_t sh) const
const MathVector< worldDim > & normal() const
const MathVector< worldDim > & global_ip() const
number shape(size_t sh) const
const MathVector< worldDim > & global_grad(size_t sh) const
const MathVector< worldDim > & global_grad(size_t sh) const
size_t num_scv() const
const MathVector< worldDim > * coe_global() const
const MathVector< worldDim > * scv_global_ips() const
const SCVF & scvf(size_t i) const
const MathVector< dim > * coe_local() const
const MathVector< worldDim > * corners() const
const MathVector< dim > * scv_local_ips() const
size_t num_bf() const
void update(GridObject *elem, const MathVector< worldDim > *vCornerCoords, const ISubsetHandler *ish=NULL)
const std::vector< BF > & bf(int si) const
GridObject * elem() const
void add_boundary_subset(int subsetIndex)
const SCV & scv(size_t i) const
size_t num_scvf() const
virtual Vertex * vertex(size_t index) const
bool access(Grid &grid, TAttachment &a)
uint grid_data_index() const
void compare_lsf_with(SmartPtr< TGridFunction > spLSF2, number eps)
compare the solution with a given level-set function
Definition hrfblsm_discr_impl.h:2055
void assign_dirichlet(TGridFunction &numsol)
assign Dirichlet values
Definition hrfblsm_discr_impl.h:1101
void sol_update(bool redOrder, const MathVector< dim > &ip, const MathVector< dim > &x_up, number u_up, const MathVector< dim > &grad_up, const MathVector< dim > &vel_up, const MathVector< dim > &x_down, number u_down, const MathVector< dim > &grad_down, const MathVector< dim > &vel_down, number &corr_up, number &curr_down, number &src_up, number &src_down)
computes the scvf-update of the solution in an element
Definition hrfblsm_discr_impl.h:166
TGridFunction::template dim_traits< dim >::const_iterator ElemIterator
grid element iterator
Definition hrfblsm_discr.h:130
void assemble_element(ElemType *elem, DimFV1Geometry< dim > &geo, domain_type &grid, LocalVector &uOld, t_aaGrad &aaGradient, t_aaGrad &aaVelGrad, t_aaVol &aaVolume, int sign, t_aaUpd &aaUpdate, t_aaUpd *aaSrc)
assemble local contributions of one element
Definition hrfblsm_discr_impl.h:348
int assemble_cut_element(ElemType *elem, DimFV1Geometry< dim > &geo, domain_type &domain, LocalVector &uOld, LocalVector &locLSF, LocalVector &locVelPot, t_aaGrad &aaGradient, t_aaGrad &aaVelGrad, t_aaVol &aaVolume, t_aaUpd &aaUpdate, t_aaUpd *aaSrc, CplUserData< number, dim > *if_val_data, int si)
assemble an element intersected by the interface
Definition hrfblsm_discr_impl.h:619
void compute_vertex_grad(TGridFunction &u, DimFV1Geometry< dim > &geo, t_aaVol &aaVolume, ADimVector &aGradient, t_aaGrad &aaGradient, TGridFunction *pLSF=NULL, CplUserData< number, dim > *if_val_data=NULL)
compute gradients and volumes
Definition hrfblsm_discr_impl.h:984
void set_dirichlet_boundary(const char *subsets)
boundary condition subset handling: dirichlet boundary
Definition hrfblsm_discr_impl.h:2017
TGridFunction::template traits< Edge >::const_iterator EdgeConstIterator
edge iterator
Definition hrfblsm_discr.h:124
void get_bf_vel_on_if(DimFV1Geometry< dim > &geo, const typename DimFV1Geometry< dim >::BF &bf, number u[], MathVector< dim > grad[], number lsf[], MathVector< dim > &co_vel, number &flux)
get the velocity for a given BF in an element intersected by the interface
Definition hrfblsm_discr_impl.h:576
void advect()
computes the time steps of the discretization of the level-set equation
Definition hrfblsm_discr_impl.h:1343
void compute_volumes(TGridFunction &u, DimFV1Geometry< dim > &geo, ANumber &aVolume, t_aaVol &aaVolume)
compute CV volumes
Definition hrfblsm_discr_impl.h:865
void compute_normal_vel(SmartPtr< CplUserData< MathVector< dim >, dim > > spVelField, SmartPtr< TGridFunction > spNormVel)
compute the normal velocity using a user-data object
Definition hrfblsm_discr_impl.h:1738
domain_type::grid_type grid_type
grid type
Definition hrfblsm_discr.h:100
void mark_CoIE(grid_type &grid, ABool &aCoIE, t_aaCoIE &aaCoIE)
mark corners at the interface
Definition hrfblsm_discr_impl.h:81
void bnd_sol_update(bool redOrder, const MathVector< dim > &bip, const MathVector< dim > &x, number u, const MathVector< dim > &grad, const MathVector< dim > &vel, number &curr)
computes the bf-update of the solution in an element
Definition hrfblsm_discr_impl.h:236
void set_outflow_boundary(const char *subsets)
boundary condition subset handling: outflow boundary
Definition hrfblsm_discr_impl.h:2036
void get_nodal_vel(ElemType *elem, MathVector< dim > coCoord[], DimFV1Geometry< dim > &geo, LocalVector &u, MathVector< dim > grad[], MathVector< dim > co_vel[], int lsf_sign)
gets corner velocity and source
Definition hrfblsm_discr_impl.h:280
int lsf_sign(size_t noc, number lsf[])
sign of the LSF
Definition hrfblsm_discr_impl.h:60
void compute_elem_grad(DimFV1Geometry< dim > &geo, number uValue[], MathVector< dim > co_grad[], number *lsf, CplUserData< number, dim > *if_val_data, int si)
compute gradients in an element
Definition hrfblsm_discr_impl.h:925
domain_type::position_accessor_type position_accessor_type
type of the position accessor
Definition hrfblsm_discr.h:103
void limit_grad(TGridFunction &uOld, t_aaGrad &aaGradient)
slope limiter
Definition hrfblsm_discr_impl.h:1143
void append_vertical_to_normal_vel(SmartPtr< CplUserData< number, dim > > spNVelField, SmartPtr< TGridFunction > spNormVel)
appends a vertical vector the the normal velocity (using a user-data object)
Definition hrfblsm_discr_impl.h:1880
TGridFunction::domain_type domain_type
domain type
Definition hrfblsm_discr.h:91
TGridFunction::template dim_traits< dim >::grid_base_object ElemType
type of base grid object
Definition hrfblsm_discr.h:121
void get_scvf_vel_on_if(DimFV1Geometry< dim > &geo, const typename DimFV1Geometry< dim >::SCVF &scvf, number u[], MathVector< dim > grad[], number lsf[], MathVector< dim > &from_co_vel, number &from_flux, MathVector< dim > &to_co_vel, number &to_flux)
get the velocity for a given SCVF in an element intersected by the interface
Definition hrfblsm_discr_impl.h:515
TGridFunction::template traits< Vertex >::const_iterator VertexConstIterator
vertex base iterator
Definition hrfblsm_discr.h:127
void extrapolate_by_lsf(const CplUserData< number, dim > *if_val_data, int si, DimFV1Geometry< dim > &geo, number sol[], number lsf[], size_t base, number ext[])
extrapolation by the LSF
Definition hrfblsm_discr_impl.h:125
index_type & index(size_t fct, size_t dof)
comp_type & comp(size_t fct, size_t dof)
const LocalIndices & get_indices() const
void resize(const LocalIndices &ind)
void VecAssign(GPUVector< T > &dest, const GPUVector< T > &v1)
PST_CONSISTENT
PST_ADDITIVE
SmartPtr< TGrid > grid()
size_t num_subsets() const
void SetAttachmentValues(TAttachmentAccessor &aaVal, TIter elemsBegin, TIter elemsEnd, const TVal &val)
#define PCL_RO_SUM
#define PCL_RO_MAX
#define PCL_RO_LOR
bool to() const
vector< string > TokenizeString(const char *str, const char delimiter=',')
#define UG_THROW(msg)
#define UG_LOG(msg)
double number
vector_t::value_type VecLength(const vector_t &v)
void VecScaleAppend(vector_t &vOut, typename vector_t::value_type s1, const vector_t &v1)
void VecAppend(vector_t &vOut, const vector_t &v1)
void VecSubtract(vector_t &vOut, const vector_t &v, typename vector_t::value_type s)
void VecScale(vector_t &vOut, const vector_t &v, typename vector_t::value_type s)
const number & DoFRef(const TMatrix &mat, const DoFIndex &iInd, const DoFIndex &jInd)
const number & BlockRef(const number &m, size_t i)
void GetLocalVector(LocalVector &lvec, const TVector &vec)
void VecScaleAdd(double &dest, double alpha1, const double &v1, double alpha2, const double &v2)