OOFEM 3.0
Loading...
Searching...
No Matches
leplic.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "leplic.h"
36#include "mathfem.h"
37#include "timestep.h"
38#include "geotoolbox.h"
39#include "node.h"
40#include "connectivitytable.h"
41#include "datastream.h"
42#include "spatiallocalizer.h"
43#include "contextioerr.h"
44#include "element.h"
45#include "dynamicinputrecord.h"
46#include "engngm.h"
47
48namespace oofem {
49#define LEPLIC_ZERO_VOF 1.e-8
50#define LEPLIC_BRENT_EPS 1.e-8
51
52
53bool
54LEPlicElementInterface :: isBoundary()
55{
56 double fvk, fvi = this->giveTempVolumeFraction();
57 IntArray currCell(1), neighborList;
58 LEPlicElementInterface *ineghbrInterface;
59 Domain *domain = this->giveElement()->giveDomain();
60 ConnectivityTable *contable = domain->giveConnectivityTable();
61 if ( ( fvi > 0. ) && ( fvi <= 1.0 ) ) {
62 // potentially boundary cell
63 if ( ( fvi > 0. ) && ( fvi < 1.0 ) ) {
64 return true;
65 }
66
67 currCell.at(1) = this->giveElement()->giveNumber();
68 contable->giveElementNeighbourList(neighborList, currCell);
69 // loop over neighbors to assemble normal equations
70 for ( int ineighbr: neighborList ) {
71 if ( ( ineghbrInterface =
72 static_cast< LEPlicElementInterface * >( domain->giveElement(ineighbr)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
73 fvk = ineghbrInterface->giveTempVolumeFraction();
74 if ( fvk < 1.0 ) {
75 return true;
76 }
77 }
78 }
79 }
80
81 return false;
82}
83
84
85void
86LEPlicElementInterface :: saveContext(DataStream &stream, ContextMode mode)
87{
89
90 if ( !stream.write(vof) ) {
92 }
93
94 if ( !stream.write(p) ) {
96 }
97
98 if ( ( iores = normal.storeYourself(stream) ) != CIO_OK ) {
99 THROW_CIOERR(iores);
100 }
101}
102
103void
104LEPlicElementInterface :: restoreContext(DataStream &stream, ContextMode mode)
105{
107
108 if ( !stream.read(vof) ) {
110 }
111
112 temp_vof = vof;
113 if ( !stream.read(p) ) {
115 }
116
117 temp_p = p;
118 if ( ( iores = normal.restoreYourself(stream) ) != CIO_OK ) {
119 THROW_CIOERR(iores);
120 }
121
123}
124
125
126
127void
128LEPlic :: updatePosition(TimeStep *tStep)
129{
131#ifdef __OOFEG
132 //deleteLayerGraphics(OOFEG_DEBUG_LAYER);
134#endif
135 this->doLagrangianPhase(tStep);
136 this->doInterfaceReconstruction(tStep, true, false);
137#ifdef __OOFEG
138 //ESIEventLoop (YES, "doInterfaceReconstruction Finished; Press Ctrl-p to continue");
140#endif
141 this->doInterfaceRemapping(tStep);
142 // here the new VOF values are determined, now we call doInterfaceReconstruction
143 // to reconstruct interface (normal, constant) on original grid
144 this->doInterfaceReconstruction(tStep, false, true);
145#ifdef __OOFEG
146 ESIEventLoop( NO, const_cast< char * >("doInterfaceReconstruction Finished; Press Ctrl-p to continue") );
147 //ESIEventLoop (YES, "doInterfaceReconstruction Finished; Press Ctrl-p to continue");
148#endif
149}
150
151void
152LEPlic :: doLagrangianPhase(TimeStep *tStep)
153{
154 //Maps element nodes along trajectories using basic Runge-Kutta method (midpoint rule)
155 int ci, ndofman = domain->giveNumberOfDofManagers();
156 int nsd = 2;
157 double dt = tStep->giveTimeIncrement();
158 IntArray velocityMask;
159 FloatArray x2(nsd), v_t, v_tn1;
160 FloatMatrix t;
161#if 1
162 EngngModel *emodel = domain->giveEngngModel();
163 int err;
164#endif
165 velocityMask = {V_u, V_v};
166
167 updated_XCoords.resize(ndofman);
168 updated_YCoords.resize(ndofman);
169
170
171 for ( int i = 1; i <= ndofman; i++ ) {
172 DofManager *dman = domain->giveDofManager(i);
173 Node *inode = dynamic_cast< Node * >(dman);
174 // skip dofmanagers with no position information
175 if ( !inode ) {
176 continue;
177 }
178
179 // get node coordinates
180 const auto &x = inode->giveCoordinates();
181 // get velocity field v(tn, x(tn)) for dof manager
182
183#if 1
184 /* Original version */
185 dman->giveUnknownVector( v_t, velocityMask, VM_Total, tStep->givePreviousStep() );
186 /* Modified version */
187 //dman->giveUnknownVector(v_t, velocityMask, VM_Total, tStep);
188
189 // Original version
190 // compute updated position x(tn)+0.5*dt*v(tn,x(tn))
191 for ( ci = 1; ci <= nsd; ci++ ) {
192 x2.at(ci) = x.at(ci) + 0.5 *dt *v_t.at(ci);
193 }
194
195 // compute interpolated velocity field at x2 [ v(tn+1, x(tn)+0.5*dt*v(tn,x(tn))) = v(tn+1, x2) ]
196
197 FieldPtr vfield = emodel->giveContext()->giveFieldManager()->giveField(FT_Velocity);
198 if ( !vfield ) {
199 OOFEM_ERROR("Velocity field not available");
200 }
201
202 err = vfield->evaluateAt(v_tn1, x2, VM_Total, tStep);
203 if ( err == 1 ) {
204 // point outside domain -> be explicit
205 v_tn1 = v_t;
206 } else if ( err != 0 ) {
207 OOFEM_ERROR("vfield->evaluateAt failed, error code %d", err);
208 }
209
210 // compute final updated position
211 for ( ci = 1; ci <= nsd; ci++ ) {
212 x2.at(ci) = x.at(ci) + dt * v_tn1.at(ci);
213 }
214
215#else
216 // pure explicit version
217 dman->giveUnknownVector(v_t, velocityMask, VM_Total, tStep);
218
219 for ( ci = 1; ci <= nsd; ci++ ) {
220 x2.at(ci) = x.at(ci) + dt *v_t.at(ci);
221 }
222
223#endif
224 // store updated node position
225 updated_XCoords.at(i) = x2.at(1);
226 updated_YCoords.at(i) = x2.at(2);
227 }
228}
229
230void
231LEPlic :: doInterfaceReconstruction(TimeStep *tStep, bool coord_upd, bool temp_vof)
232{
233 /* Here volume materials are reconstructed on the new Lagrangian grid */
234
235 int nelem = domain->giveNumberOfElements();
236 double p;
237
238 FloatArray fvgrad(2);
239 LEPlicElementInterface *interface;
240
241
242 // loop over elements
243 for ( int ie = 1; ie <= nelem; ie++ ) {
244 /* STEP 1: first do DLS (Differential least square reconstruction) */
245 this->doCellDLS(fvgrad, ie, coord_upd, temp_vof);
246 /* STEP 2: Finding the line constant */
247 this->findCellLineConstant(p, fvgrad, ie, coord_upd, temp_vof);
248
249 interface = static_cast< LEPlicElementInterface * >( domain->giveElement(ie)->giveInterface(LEPlicElementInterfaceType) );
250 interface->setTempLineConstant(p);
251 interface->setTempInterfaceNormal(fvgrad);
252 } // end loop over all elements
253}
254
255
256void
257LEPlic :: doInterfaceRemapping(TimeStep *tStep)
258{
259 /*
260 * Final step: deposition of volume materials truncated on Lagrangian (updated)
261 * grid to the target grid, which is the original one in our Eulerian case.
262 */
263 int neighbrNum, nelem = domain->giveNumberOfElements();
264 double in_vof, total_volume = 0.0, in_vol;
265 IntArray neighbours, elNum(1);
266 FloatArray normal;
267 Polygon matvolpoly, elemPoly;
268 Graph g;
269
270 double matVol = 0.0, matVolSum = 0.0;
271
272 LEPlicElementInterface *interface, *neghbrInterface;
273 // loop over elements
274 for ( int ie = 1; ie <= nelem; ie++ ) {
275 if ( ( interface = static_cast< LEPlicElementInterface * >( domain->giveElement(ie)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
276 interface->setTempVolumeFraction(0.0);
277 }
278 }
279
280 // loop over elements
281 for ( int ie = 1; ie <= nelem; ie++ ) {
282 //fprintf (stderr, "doInterfaceRemapping: processing elem %d\n", ie);
283
284 // examine only neighbours -> this is the limit on time step
285 elNum.at(1) = ie;
286 domain->giveConnectivityTable()->giveElementNeighbourList(neighbours, elNum);
287 // form polygon of material volume on Lagrangian element
288 if ( ( interface = static_cast< LEPlicElementInterface * >( domain->giveElement(ie)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
289 if ( interface->giveVolumeFraction() > LEPLIC_ZERO_VOF ) {
290 interface->giveTempInterfaceNormal(normal);
291 interface->formMaterialVolumePoly(matvolpoly, this, normal, interface->giveTempLineConstant(), true);
292 matVol = matvolpoly.computeVolume();
293
294#ifdef __OOFEG
295 //EASValsSetColor(::gc[OOFEG_DEBUG_LAYER].getElementColor());
296 //GraphicObj *go = matvolpoly.draw(::gc[OOFEG_DEBUG_LAYER],true);
297 //EVHiliteGraphics (myview, go);
298 //ESIEventLoop (YES, "Press Ctrl-p to continue");
299 //EVFastRedraw(myview);
300#endif
301
302
303 try {
304 matVolSum = 0.0;
305 // loop over neighbours to truncate material volume on target (original) grid
306 for ( int in = 1; in <= neighbours.giveSize(); in++ ) {
307 neighbrNum = neighbours.at(in);
308 if ( ( neghbrInterface = static_cast< LEPlicElementInterface * >
309 ( domain->giveElement(neighbrNum)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
310 in_vof = neghbrInterface->truncateMatVolume(matvolpoly, in_vol);
311 neghbrInterface->addTempVolumeFraction(in_vof);
312 total_volume += in_vol;
313 matVolSum += in_vol;
314 }
315 }
316 } catch(GT_Exception & c) {
317 c.print();
318
319 neighbrNum = neighbours.at(1);
320 if ( ( neghbrInterface = static_cast< LEPlicElementInterface * >
321 ( domain->giveElement(neighbrNum)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
322 in_vof = neghbrInterface->truncateMatVolume(matvolpoly, in_vol);
323 neghbrInterface->addTempVolumeFraction(in_vof);
324 }
325 }
326
327#ifdef __OOFEG
328 //ESIEventLoop (YES, "Step Finished; Press Ctrl-p to continue");
329#endif
330 double err = fabs(matVol - matVolSum) / matVol;
331 if ( ( err > 1.e-12 ) && ( fabs(matVol - matVolSum) > 1.e-4 ) && ( matVol > 1.e-6 ) ) {
332 OOFEM_WARNING("volume inconsistency %5.2f%%\n\ttstep %d, element %d\n", err * 100, tStep->giveNumber(), ie);
333 }
334
335#if 0
336 if ( ( err > 2.e-3 ) && ( fabs(matVol - matVolSum) > 2.e-3 ) ) {
337 //debug
338
339 #ifdef __OOFEG
340 //ESIEventLoop (YES, "Press Ctrl-p to continue");
342 EASValsSetColor( :: gc [ OOFEG_DEBUG_LAYER ].getElementColor() );
343 //GraphicObj *go = matvolpoly.draw(::gc[OOFEG_DEBUG_LAYER],true);
344 matvolpoly.draw(:: gc [ OOFEG_DEBUG_LAYER ], true);
345 //EVHiliteGraphics (myview, go);
346 //ESIEventLoop (YES, "Press Ctrl-p to continue");
348 #endif
349
350 matVolSum = 0.0;
351 // loop over neighbours to truncate material volume on target (original) grid
352 for ( int in = 1; in <= neighbours.giveSize(); in++ ) {
353 neighbrNum = neighbours.at(in);
354 if ( neghbrInterface = static_cast< LEPlicElementInterface * >
355 ( domain->giveElement(neighbrNum)->giveInterface(LEPlicElementInterfaceType) ) ) {
356 in_vof = neghbrInterface->truncateMatVolume(matvolpoly, in_vol);
357 neghbrInterface->addTempVolumeFraction(in_vof);
358 total_volume += in_vol;
359 matVolSum += in_vol;
360 }
361 }
362
363 matVolSum = 0.0;
364 // loop over neighbours to truncate material volume on target (original) grid
365 for ( int in = 1; in <= neighbours.giveSize(); in++ ) {
366 neighbrNum = neighbours.at(in);
367 if ( neghbrInterface = static_cast< LEPlicElementInterface * >
368 ( domain->giveElement(neighbrNum)->giveInterface(LEPlicElementInterfaceType) ) ) {
369 in_vof = neghbrInterface->truncateMatVolume(matvolpoly, in_vol);
370 neghbrInterface->addTempVolumeFraction(in_vof);
371 total_volume += in_vol;
372 matVolSum += in_vol;
373 }
374 }
375
376 matVolSum = 0.0;
377 // loop over neighbours to truncate material volume on target (original) grid
378 for ( int in = 1; in <= neighbours.giveSize(); in++ ) {
379 neighbrNum = neighbours.at(in);
380 if ( neghbrInterface = static_cast< LEPlicElementInterface * >
381 ( domain->giveElement(neighbrNum)->giveInterface(LEPlicElementInterfaceType) ) ) {
382 in_vof = neghbrInterface->truncateMatVolume(matvolpoly, in_vol);
383 neghbrInterface->addTempVolumeFraction(in_vof);
384 total_volume += in_vol;
385 matVolSum += in_vol;
386 }
387 }
388
389 /*
390 * ESIEventLoop (YES, "Press Ctrl-p to exit");
391 * ESIEventLoop (YES, "Press Ctrl-p to exit");
392 */
393 exit(1);
394 }
395
396#endif
397 }
398 } else {
399 OOFEM_ERROR("Element with no LEPlicInterface support encountered");
400 }
401 } // end loop over elements
402
403 // loop over elements
404 for ( int ie = 1; ie <= nelem; ie++ ) {
405 if ( ( interface = static_cast< LEPlicElementInterface * >( domain->giveElement(ie)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
406 if ( interface->giveTempVolumeFraction() > 1.0 ) {
407 OOFEM_LOG_INFO( "LEPlic::doInterfaceRemapping - Element %d: vof out of range, vof =%e", ie, interface->giveTempVolumeFraction() );
408 }
409
410 if ( interface->giveTempVolumeFraction() >= 0.99999999 ) {
411 interface->setTempVolumeFraction(1.0);
412 }
413 }
414 }
415
416 OOFEM_LOG_INFO("LEPlic::doInterfaceRemapping: Total volume is %e", total_volume);
417 if ( orig_reference_fluid_volume > 0.0 ) {
418 OOFEM_LOG_INFO("LEPlic::doInterfaceRemapping: Volume error is %5.2f%%\n",
419 ( ( total_volume - orig_reference_fluid_volume ) / orig_reference_fluid_volume ) * 100.0);
420 }
421
422
423#ifdef __OOFEG
424 //ESIEventLoop (YES, "Step Finished; Press Ctrl-p to continue");
425 //deleteLayerGraphics(OOFEG_DEBUG_LAYER);
426#endif
427}
428
429
430void
431LEPlic :: doCellDLS(FloatArray &fvgrad, int ie, bool coord_upd, bool vof_temp_flag)
432{
433 double fvi, fvk, wk, dx, dy;
434 bool isBoundaryCell = false;
435 LEPlicElementInterface *interface, *ineghbrInterface;
436 FloatMatrix lhs(2, 2);
437 FloatArray rhs(2), xi(2), xk(2);
438 IntArray currCell(1), neighborList;
439 ConnectivityTable *contable = domain->giveConnectivityTable();
440
441 if ( ( interface = static_cast< LEPlicElementInterface * >( domain->giveElement(ie)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
442 if ( vof_temp_flag ) {
443 fvi = interface->giveTempVolumeFraction();
444 } else {
445 fvi = interface->giveVolumeFraction();
446 }
447
448 if ( ( fvi > 0. ) && ( fvi <= 1.0 ) ) {
449 // potentially boundary cell
450
451 if ( ( fvi > 0. ) && ( fvi < 1.0 ) ) {
452 isBoundaryCell = true;
453 }
454
455 /* DLS (Differential least square reconstruction)
456 *
457 * In the DLS method, volume fraction Taylor series expansion of vf (volume fraction)
458 * is formed from each reference cell volume fraction vf at element center x(i) to each
459 * cell neighbor at point x(k). The sum (vf(i)-vf(k))^2 over all immediate neighbors
460 * is then minimized inthe least square sense.
461 */
462 // get list of neighbours to current cell including current cell
463 currCell.at(1) = ie;
464 contable->giveElementNeighbourList(neighborList, currCell);
465 // loop over neighbors to assemble normal equations
466 interface->giveElementCenter(this, xi, coord_upd);
467 lhs.zero();
468 rhs.zero();
469 for ( int ineighbr: neighborList ) {
470 if ( ineighbr == ie ) {
471 continue; // skip itself
472 }
473
474 if ( ( ineghbrInterface =
475 static_cast< LEPlicElementInterface * >( domain->giveElement(ineighbr)->giveInterface(LEPlicElementInterfaceType) ) ) ) {
476 if ( vof_temp_flag ) {
477 fvk = ineghbrInterface->giveTempVolumeFraction();
478 } else {
479 fvk = ineghbrInterface->giveVolumeFraction();
480 }
481
482 if ( fvk < 1.0 ) {
483 isBoundaryCell = true;
484 }
485
486 ineghbrInterface->giveElementCenter(this, xk, coord_upd);
487 wk = distance(xk, xi);
488 dx = ( xk.at(1) - xi.at(1) ) / wk;
489 dy = ( xk.at(2) - xi.at(2) ) / wk;
490 lhs.at(1, 1) += dx * dx;
491 lhs.at(1, 2) += dx * dy;
492 lhs.at(2, 2) += dy * dy;
493
494 rhs.at(1) += ( fvi - fvk ) * dx / wk;
495 rhs.at(2) += ( fvi - fvk ) * dy / wk;
496 }
497 }
498
499 if ( isBoundaryCell ) {
500 // symmetry
501 lhs.at(2, 1) = lhs.at(1, 2);
502
503 // solve normal equation for volume fraction gradient
504 lhs.solveForRhs(rhs, fvgrad);
505
506 // compute unit normal
507 fvgrad.normalize();
508 fvgrad.negated();
509#ifdef __OOFEG
510 /*
511 * EASValsSetLayer(OOFEG_DEBUG_LAYER);
512 * WCRec p[2];
513 * double tx = -fvgrad.at(2), ty=fvgrad.at(1);
514 * p[0].x=xi.at(1)-tx*0.1;
515 * p[0].y=xi.at(2)-ty*0.1;
516 * p[1].x=xi.at(1)+tx*0.1;
517 * p[1].y=xi.at(2)+ty*0.1;
518 * p[0].z = p[1].z = 0.0;
519 * GraphicObj *go = CreateLine3D(p);
520 * EGWithMaskChangeAttributes(LAYER_MASK, go);
521 * EMAddGraphicsToModel(ESIModel(), go);
522 * ESIEventLoop (YES, "Cell DLS finished; Press Ctrl-p to continue");
523 */
524#endif
525 } else {
526 fvgrad.zero();
527 }
528 }
529 }
530}
531
532void
533LEPlic :: findCellLineConstant(double &p, FloatArray &fvgrad, int ie, bool coord_upd, bool temp_vof_flag)
534{
535 /* The line constatnt p is solved from the general non-linear function
536 * F(p) = V(p)-V = 0,
537 * where V(p) is the truncated volume resulting from the intersection between
538 * assumed line segment and the reference cell
539 * V is the given Volume of Fluid ratio
540 * To find zero of this function, Brent's method is been used.
541 */
542 Element *elem = domain->giveElement(ie);
544 int nelemnodes = elem->giveNumberOfNodes();
545 double ivof, fvi;
546 double ivx, ivy, pp, target_vof;
547 if ( temp_vof_flag ) {
548 target_vof = interface->giveTempVolumeFraction();
549 } else {
550 target_vof = interface->giveVolumeFraction();
551 }
552
553 computeLEPLICVolumeFractionWrapper wrapper(interface, this, fvgrad, target_vof, coord_upd);
554 /*
555 * Initial part: find lower and uper bounds for Brent algorithm
556 * Here lines with given interface normal are passed through each vertex
557 * and corresponding volume fractions are computed. The two lines forming
558 * truncation volumes that bound the actual material in the cell provide
559 * upper and lower bounds for line constant
560 */
561 double upper_vof = 10.0, lower_vof = -10.0;
562 double upper_p = 0.0, lower_p = 0.0;
563
564 if ( temp_vof_flag ) {
565 fvi = interface->giveTempVolumeFraction();
566 } else {
567 fvi = interface->giveVolumeFraction();
568 }
569
570 if ( ( fvi > LEPLIC_ZERO_VOF ) && ( fvi < 1.0 ) ) {
571 // boundary cell
572
573
574 for ( int ivert = 1; ivert <= nelemnodes; ivert++ ) {
575 if ( coord_upd ) {
576 ivx = giveUpdatedXCoordinate( elem->giveNode(ivert)->giveNumber() );
577 ivy = giveUpdatedYCoordinate( elem->giveNode(ivert)->giveNumber() );
578 } else {
579 ivx = elem->giveNode(ivert)->giveCoordinate(1);
580 ivy = elem->giveNode(ivert)->giveCoordinate(2);
581 }
582
583 // determine line constant for vertex ivert
584 pp = -( fvgrad.at(1) * ivx + fvgrad.at(2) * ivy );
585 ivof = interface->computeLEPLICVolumeFraction(fvgrad, pp, this, coord_upd);
586 if ( ( ( ivof - target_vof ) >= 0. ) && ( ivof < upper_vof ) ) {
587 upper_vof = ivof;
588 upper_p = pp;
589 } else if ( ( ( target_vof - ivof ) >= 0. ) && ( ivof > lower_vof ) ) {
590 lower_vof = ivof;
591 lower_p = pp;
592 }
593 }
594
595 if ( ( lower_vof >= 0. ) && ( upper_vof <= 1.00000000001 ) ) {
596 // now use brent's method to find minima of V(p)-V function
597 brent(lower_p, 0.5 * ( lower_p + upper_p ), upper_p,
598 mem_fun< computeLEPLICVolumeFractionWrapper >(& wrapper, & computeLEPLICVolumeFractionWrapper :: eval),
600 //interface->setTempLineConstant (p);
601
602
603#ifdef __OOFEG
604 /*
605 * Polygon grp, cell;
606 * // check here
607 * //Polygon testvolpoly;
608 * //interface->formMaterialVolumePoly(testvolpoly, this, fvgrad, p, true);
609 * //double debug_vof = interface->truncateMatVolume(testvolpoly);
610 *
611 * //printf ("Cell %d-> target_vof is %e, debug val is %e\n", ie, target_vof, debug_vof);
612 * interface->formMyVolumePoly (cell, this, true);
613 * GraphicObj *goc = cell.draw(::gc[0], false);
614 * EASValsSetLayer(OOFEG_DEBUG_LAYER);
615 * EASValsSetColor(::gc[0].getBcIcColor());
616 * EGWithMaskChangeAttributes(COLOR_MASK | LAYER_MASK, goc);
617 * EMDrawGraphics (ESIModel(), goc);
618 *
619 * interface->formVolumeInterfacePoly (grp, this, fvgrad, p, true);
620 * GraphicObj *go = grp.draw(::gc[0], true);
621 * EASValsSetColor(::gc[0].getActiveCrackColor());
622 * EGWithMaskChangeAttributes(COLOR_MASK | LAYER_MASK, go);
623 * EMDrawGraphics (ESIModel(), go);
624 * //ESIEventLoop (YES, "findCellLineConstant -> Press Ctrl-p to continue");
625 */
626#endif
627 } else {
628 //fprintf (stderr, "target_vof = %le, fvi=%le\n", target_vof, fvi);
629 OOFEM_ERROR("finding lower and uper bounds of line constant value failed (lowerVOF = %lf, upperVOF=%lf)", lower_vof, upper_vof);
630 }
631 }
632}
633
634void
640
641
642void
643LEPlic :: giveInputRecord(DynamicInputRecord &input)
644{
646}
647
648
649double
650LEPlic :: computeCriticalTimeStep(TimeStep *tStep)
651{
652 double dt = 1.e6;
653 LEPlicElementInterface *interface;
654
655 for ( auto &elem : domain->giveElements() ) {
656 if ( ( interface = static_cast< LEPlicElementInterface * >( elem->giveInterface(LEPlicElementInterfaceType) ) ) ) {
657 dt = min( dt, interface->computeCriticalLEPlicTimeStep(tStep) );
658 }
659 }
660
661 return 0.9 * dt;
662}
663
664void
665LEPlic :: giveMaterialMixtureAt(FloatArray &answer, FloatArray &position)
666{
667 answer.resize(2);
668 Element *elem = domain->giveSpatialLocalizer()->giveElementContainingPoint(position);
670 if ( interface ) {
671 Polygon pg;
672 FloatArray n;
673 interface->giveTempInterfaceNormal(n);
674 interface->formVolumeInterfacePoly(pg, this, n, interface->giveTempLineConstant(), false);
675 if ( pg.testPoint( position.at(1), position.at(2) ) ) {
676 answer.at(1) = 1.0;
677 answer.at(2) = 0.0;
678 } else {
679 answer.at(1) = 0.0;
680 answer.at(2) = 1.0;
681 }
682 } else {
683 answer.at(1) = 1.0;
684 answer.at(2) = 0.0;
685 }
686}
687
688void
689LEPlic :: giveElementMaterialMixture(FloatArray &answer, int ie)
690{
691 answer.resize(2);
692 Element *elem = domain->giveElement(ie);
694 if ( interface ) {
695 answer.at(1) = interface->giveTempVolumeFraction();
696 answer.at(2) = 1. - answer.at(1);
697 } else {
698 answer.at(1) = 1.0;
699 answer.at(2) = 0.0;
700 }
701}
702
703double
704LEPlic :: giveNodalScalarRepresentation(int inode)
705{
706 bool vof_1 = false, vof_0 = false;
707 double vof, vofsum = 0.0;
708 const IntArray *shelem = domain->giveConnectivityTable()->giveDofManConnectivityArray(inode);
709
710 for ( int i = 1; i <= shelem->giveSize(); i++ ) {
711 LEPlicElementInterface *interface = static_cast< LEPlicElementInterface * >( domain->giveElement( shelem->at(i) )->giveInterface(LEPlicElementInterfaceType) );
712 if ( interface ) {
713 vof = interface->giveTempVolumeFraction();
714 if ( vof == 0.0 ) {
715 vof_0 = true;
716 } else if ( vof == 1.0 ) {
717 vof_1 = true;
718 }
719
720 vofsum += vof;
721 }
722 }
723
724 if ( vof_0 && vof_1 ) {
725 return 0.5;
726 } else if ( vof_0 ) {
727 return 0.0;
728 } else if ( vof_1 ) {
729 return 1.0;
730 } else {
731 return vofsum / shelem->giveSize();
732 }
733}
734} // end namespace oofem
void giveElementNeighbourList(IntArray &answer, const IntArray &elemList)
virtual int read(int *data, std::size_t count)=0
Reads count integer values into array pointed by data.
virtual int write(const int *data, std::size_t count)=0
Writes count integer values from array pointed by data.
double giveCoordinate(int i) const
Definition dofmanager.h:383
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
void giveUnknownVector(FloatArray &answer, const IntArray &dofMask, ValueModeType mode, TimeStep *tStep, bool padding=false)
Definition dofmanager.C:657
ConnectivityTable * giveConnectivityTable()
Definition domain.C:1240
Element * giveElement(int n)
Definition domain.C:165
void setField(int item, InputFieldType id)
Node * giveNode(int i) const
Definition element.h:629
virtual int giveNumberOfNodes() const
Definition element.h:703
FieldManager * giveFieldManager()
Definition engngm.h:141
EngngModelContext * giveContext()
Context requesting service.
Definition engngm.h:1174
virtual Interface * giveInterface(InterfaceType t)
Definition femcmpnn.h:181
Domain * domain
Link to domain object, useful for communicating with other FEM components.
Definition femcmpnn.h:79
int giveNumber() const
Definition femcmpnn.h:104
FieldPtr giveField(FieldType key)
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void zero()
Zeroes all coefficient of receiver.
double at(std::size_t i, std::size_t j) const
bool solveForRhs(const FloatArray &b, FloatArray &answer, bool transpose=false)
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
virtual Element * giveElement()=0
Return number of receiver's element.
FloatArray normal
Interface segment normal.
Definition leplic.h:67
void setTempLineConstant(double tp)
Definition leplic.h:99
void addTempVolumeFraction(double v)
Definition leplic.h:110
virtual double computeCriticalLEPlicTimeStep(TimeStep *tStep)=0
Computes critical time step.
double p
Line constant of line segment representing interface.
Definition leplic.h:65
void setTempInterfaceNormal(FloatArray tg)
Definition leplic.h:100
virtual double truncateMatVolume(const Polygon &matvolpoly, double &volume)=0
Truncates given material polygon to receiver.
void giveTempInterfaceNormal(FloatArray &n)
Definition leplic.h:120
void setTempVolumeFraction(double v)
Definition leplic.h:101
virtual void formMaterialVolumePoly(Polygon &matvolpoly, LEPlic *matInterface, const FloatArray &normal, const double p, bool updFlag)=0
Assembles the true element material polygon (takes receiver vof into accout).
double vof
Volume fraction of reference fluid in element.
Definition leplic.h:63
virtual void giveElementCenter(LEPlic *mat_interface, FloatArray &center, bool updFlag)=0
Computes the receiver center (in updated Lagrangian configuration).
void doInterfaceReconstruction(TimeStep *tStep, bool coord_upd, bool temp_vof)
Definition leplic.C:231
double orig_reference_fluid_volume
Definition leplic.h:156
double giveUpdatedXCoordinate(int num)
Definition leplic.h:185
void doInterfaceRemapping(TimeStep *tStep)
Definition leplic.C:257
void findCellLineConstant(double &p, FloatArray &fvgrad, int ie, bool coord_upd, bool temp_vof_flag)
Definition leplic.C:533
void doLagrangianPhase(TimeStep *tStep)
Definition leplic.C:152
FloatArray updated_YCoords
Array used to store updated y-coordinates of nodes as moved along streamlines.
Definition leplic.h:155
void doCellDLS(FloatArray &fvgrad, int ie, bool coord_upd, bool temp_vof_flag)
Definition leplic.C:431
double giveUpdatedYCoordinate(int num)
Definition leplic.h:186
FloatArray updated_XCoords
Array used to store updated x-coordinates of nodes as moved along streamlines.
Definition leplic.h:153
GraphicObj * draw(oofegGraphicContext &, bool filled, int layer=OOFEG_DEBUG_LAYER)
Definition geotoolbox.C:152
double computeVolume() const
Definition geotoolbox.C:72
int testPoint(double x, double y) const
Definition geotoolbox.C:47
double giveTimeIncrement()
Returns solution step associated time increment.
Definition timestep.h:168
int giveNumber()
Returns receiver's number.
Definition timestep.h:144
TimeStep * givePreviousStep()
Returns pointer to previous solution step.
Definition timestep.C:132
#define THROW_CIOERR(e)
#define OOFEM_WARNING(...)
Definition error.h:80
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Definition inputrecord.h:75
#define LEPLIC_ZERO_VOF
Definition leplic.C:49
#define LEPLIC_BRENT_EPS
Definition leplic.C:50
#define _IFT_LEPLIC_refVol
Definition leplic.h:45
#define OOFEM_LOG_INFO(...)
Definition logger.h:143
long ContextMode
Definition contextmode.h:43
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
@ LEPlicElementInterfaceType
std::shared_ptr< Field > FieldPtr
Definition field.h:78
double distance(const FloatArray &x, const FloatArray &y)
@ CIO_IOERR
General IO error.
double brent(double ax, double bx, double cx, const T &f, double tol, double &xmin)
Definition mathfem.h:262
void EVFastRedraw(EView *v_p)
oofem::oofegGraphicContext gc[OOFEG_LAST_LAYER]
#define OOFEG_DEBUG_LAYER
EView * myview
void deleteLayerGraphics(int iLayer)

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011