OOFEM 3.0
Loading...
Searching...
No Matches
delaunaytriangulator.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
36#include "octreelocalizert.h"
37#include "delaunaytriangle.h"
38#include "tr1_2d_pfem.h"
39#include "intarray.h"
40#include "contextioerr.h"
41#include "verbose.h"
42#include "timer.h"
43#include "mathfem.h"
44#include "pfemparticle.h"
45#include "pfem.h"
46
47#define _USING_OCTREE
48
49namespace oofem {
50DelaunayTriangulator :: DelaunayTriangulator(Domain *d, double setAlpha) :
52{
53 domain = d;
54 alphaValue = setAlpha;
55 nnode = domain->giveNumberOfDofManagers();
56 // Option 2: setting bounds vor computed Alpha
57 //minAlpha = 0.08;
58 //maxAlpha = 0.2;
59}
60
61DelaunayTriangulator :: ~DelaunayTriangulator()
62{
63 for ( auto tri : generalTriangleList ) {
64 delete tri;
65 }
66
67 for ( auto edge : edgeList ) {
68 delete edge;
69 }
70}
71
72
73
74void DelaunayTriangulator :: addUniqueEdgeToPolygon(Edge2D edge, std :: list< Edge2D > &polygon)
75{
76 int do_add = 1;
77
78 for ( auto pos = polygon.begin(); pos != polygon.end(); ) {
79 if ( ( * pos ) == edge ) {
80 pos = polygon.erase(pos);
81 do_add = 0;
82 break;
83 } else {
84 ++pos;
85 }
86 }
87
88 if ( do_add ) {
89 polygon.push_back(edge);
90 }
91}
92
93
94void DelaunayTriangulator :: generateMesh()
95{
97
98 buildInitialBBXMesh(tInsert);
99
101
102 for ( int insertedNode = 1; insertedNode <= nnode; insertedNode++ ) {
103 PFEMParticle *particle = dynamic_cast< PFEMParticle * >( domain->giveDofManager(insertedNode) );
104 if ( particle->isActive() ) {
105 std :: list< Edge2D >polygon;
106
107 findNonDelaunayTriangles(insertedNode, tInsert, polygon);
108
109 meshPolygon(insertedNode, tInsert, polygon);
110 }
111 }
112
113 //giveTimeReport();
114
116
117 //deleting BBX-corner particles
118 domain->resizeDofManagers(nnode);
119
120 int size = generalTriangleList.size();
121
122 VERBOSE_PRINT0("Number of generated elements", size);
123 triangleOctree.giveReport();
124
125 if ( alphaValue > 0.001 ) {
128 }
129
131
132 writeMesh();
133}
134
135void DelaunayTriangulator :: writeMesh()
136{
137 int num = 1;
138 int nelem = generalTriangleList.size();
139 IntArray dmans(3);
140 DofManager *dman;
141 DofIDItem type;
142 bool hasNoBcOnItself;
143
144 int mat = 0;
145 int cs = 0;
146 int pressureBC = 0;
147 PFEM *pfemEngngModel = dynamic_cast< PFEM * >( domain->giveEngngModel() );
148 if ( pfemEngngModel ) {
149 mat = pfemEngngModel->giveAssociatedMaterialNumber();
150 cs = pfemEngngModel->giveAssociatedCrossSectionNumber();
151 pressureBC = pfemEngngModel->giveAssociatedPressureBC();
152 }
153
154 domain->resizeElements(nelem);
155 //from domain.C
156 for ( auto gen : generalTriangleList ) {
157 auto elem = std::make_unique<TR1_2D_PFEM>(num, domain, gen->giveNode(1), gen->giveNode(2), gen->giveNode(3), mat, cs);
158
159 domain->setElement(num, std::move(elem));
160 num++;
161 }
162
163 if ( alphaValue > 0.001 ) {
164 // first reset all pressure boundary conditions and alphaShapeProperty
165 for ( int i = 1; i <= domain->giveNumberOfDofManagers(); i++ ) {
166 Dof *jDof = domain->giveDofManager(i)->giveDofWithID(P_f);
167 jDof->setBcId(0);
168
169 dynamic_cast< PFEMParticle * >( domain->giveDofManager(i) )->setOnAlphaShape(false);
170 }
171
172 // and then prescribe zero pressure on the free surface
173 for ( auto el : alphaShapeEdgeList ) {
174 bool oneIsFree = false;
175 hasNoBcOnItself = true;
176 dman = domain->giveDofManager( el->giveFirstNodeNumber() );
177 for ( Dof *dof: *dman ) {
178 type = dof->giveDofID();
179 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
180 if ( dof->giveBcId() ) {
181 hasNoBcOnItself = false;
182 }
183 }
184 }
185
186 if ( hasNoBcOnItself ) {
187 oneIsFree = true;
188 }
189 dynamic_cast< PFEMParticle * >( dman )->setOnAlphaShape();
190
191 hasNoBcOnItself = true;
192 dman = domain->giveDofManager( el->giveSecondNodeNumber() );
193 for ( Dof *dof: *dman ) {
194 type = dof->giveDofID();
195 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
196 if ( dof->giveBcId() ) {
197 hasNoBcOnItself = false;
198 }
199 }
200 }
201
202 if ( hasNoBcOnItself ) {
203 oneIsFree = true;
204 }
205 dynamic_cast< PFEMParticle * >( dman )->setOnAlphaShape();
206
207 if ( oneIsFree ) {
208 Dof *dofOnNode1 = domain->giveDofManager( el->giveFirstNodeNumber() )->giveDofWithID(P_f);
209 dofOnNode1->setBcId(pressureBC);
210
211 Dof *dofOnNode2 = domain->giveDofManager( el->giveSecondNodeNumber() )->giveDofWithID(P_f);
212 dofOnNode2->setBcId(pressureBC);
213 }
214 }
215 }
216}
217
219void DelaunayTriangulator :: computeAlphaComplex()
220{
221 bool alphaLengthInitialized = false;
222 double minimalLength = 1.e6;
223
224 for ( auto &gen : generalTriangleList ) {
225 if ( alphaLengthInitialized ) {
226 minimalLength = min( gen->giveShortestEdgeLength(), minimalLength );
227 } else {
228 minimalLength = gen->giveShortestEdgeLength();
229 alphaLengthInitialized = true;
230 }
231
232 int par1 = gen->giveNode(1);
233 int par2 = gen->giveNode(2);
234 int par3 = gen->giveNode(3);
235 double ccRadius = gen->giveCircumRadius();
236
237 AlphaEdge2D *containedEdge;
238
239 AlphaEdge2D *edge1 = new AlphaEdge2D( par1, par2, gen->giveEdgeLength(1, 2) );
240
241 containedEdge = giveBackEdgeIfAlreadyContainedInList(*edge1);
242
243 if ( containedEdge ) {
244 delete edge1;
245 containedEdge->setSharing( 2, gen );
246 double outAlph = containedEdge->giveOuterAlphaBound();
247 if ( ccRadius < outAlph ) {
248 containedEdge->setOuterAlphaBound(ccRadius);
249 }
250
251 double innAlph = containedEdge->giveInnerAlphaBound();
252 if ( ccRadius > innAlph ) {
253 containedEdge->setInnerAlphaBound(ccRadius);
254 }
255
256 containedEdge->setHullFlag(false);
257
258 edgeList.push_back(containedEdge);
259 } else {
260 edge1->setOuterAlphaBound(ccRadius);
261 edge1->setInnerAlphaBound(ccRadius);
262 edge1->setHullFlag(true);
263
264 edge1->setSharing( 1, gen );
265 edgeList.push_back(edge1);
266 }
267
268 AlphaEdge2D *edge2 = new AlphaEdge2D( par2, par3, gen->giveEdgeLength(2, 3) );
269
270 containedEdge = giveBackEdgeIfAlreadyContainedInList(*edge2);
271
272 if ( containedEdge ) {
273 delete edge2;
274 containedEdge->setSharing( 2, gen );
275
276 double outAlph = containedEdge->giveOuterAlphaBound();
277 if ( ccRadius < outAlph ) {
278 containedEdge->setOuterAlphaBound(ccRadius);
279 }
280
281 double innAlph = containedEdge->giveInnerAlphaBound();
282 if ( ccRadius > innAlph ) {
283 containedEdge->setInnerAlphaBound(ccRadius);
284 }
285
286 containedEdge->setHullFlag(false);
287
288 edgeList.push_back(containedEdge);
289 } else {
290 edge2->setOuterAlphaBound(ccRadius);
291 edge2->setInnerAlphaBound(ccRadius);
292 edge2->setHullFlag(true);
293
294 edge2->setSharing( 1, gen );
295 edgeList.push_back(edge2);
296 }
297
298 AlphaEdge2D *edge3 = new AlphaEdge2D( par3, par1, gen->giveEdgeLength(3, 1) );
299
300 containedEdge = giveBackEdgeIfAlreadyContainedInList(*edge3);
301
302 if ( containedEdge ) {
303 delete edge3;
304 containedEdge->setSharing( 2, gen );
305
306 double outAlph = containedEdge->giveOuterAlphaBound();
307 if ( ccRadius < outAlph ) {
308 containedEdge->setOuterAlphaBound(ccRadius);
309 }
310
311 double innAlph = containedEdge->giveInnerAlphaBound();
312 if ( ccRadius > innAlph ) {
313 containedEdge->setInnerAlphaBound(ccRadius);
314 }
315
316 containedEdge->setHullFlag(false);
317
318 edgeList.push_back(containedEdge);
319 } else {
320 edge3->setOuterAlphaBound(ccRadius);
321 edge3->setInnerAlphaBound(ccRadius);
322 edge3->setHullFlag(true);
323
324 edge3->setSharing( 1, gen );
325 edgeList.push_back(edge3);
326 }
327 }
328
329 //alphaValue *= minimalLength;
330}
331
332//gives back pointer from edgeList
334AlphaEdge2D *DelaunayTriangulator :: giveBackEdgeIfAlreadyContainedInList(AlphaEdge2D &alphaEdge)
335{
336 for ( auto elIT = edgeList.begin(); elIT != edgeList.end(); ++elIT ) {
337 if ( ( * * elIT ) == alphaEdge ) {
338 AlphaEdge2D *foundEdge = * elIT;
339 edgeList.erase(elIT);
340 return foundEdge;
341 }
342 }
343
344 return nullptr;
345}
346
348void DelaunayTriangulator :: giveAlphaShape()
349{
350 for ( auto el : edgeList ) {
351 // Option 2 : setting bounds vor computed Alpha
352 //double alpha = max(min(alphaValue * el->giveLength(), maxAlpha), minAlpha);
353 double alpha = alphaValue;
354 double outBound = el->giveOuterAlphaBound();
355
356 //innerBound = infinity
357 if ( el->giveHullFlag() ) {
358 if ( alpha > outBound ) {
359 alphaShapeEdgeList.push_back(el);
360 } else {
361 //invalidating element
362 el->giveShared(1)->setValidFlag(false);
363 }
364 } else {
365 double innBound = el->giveInnerAlphaBound();
366 if ( alpha > outBound && alpha < innBound ) {
367 alphaShapeEdgeList.push_back(el);
368 if ( el->giveShared(1)->giveCircumRadius() > alpha ) {
369 el->giveShared(1)->setValidFlag(false);
370 } else {
371 el->giveShared(2)->setValidFlag(false);
372 }
373 }
374
375 if ( alpha < outBound ) {
376 for ( int i = 1; i <= 2; i++ ) {
377 el->giveShared(i)->setValidFlag(false);
378 }
379 }
380 }
381 }
382}
383
384void
385DelaunayTriangulator :: initializeTimers()
386{
387 this->meshingTimer.startTimer();
388 this->searchingTimer.startTimer();
389 this->searchingTimer.pauseTimer();
390 this->polygonTimer.startTimer();
391 this->polygonTimer.pauseTimer();
392 this->creativeTimer.startTimer();
393 this->creativeTimer.pauseTimer();
394}
395
396void
397DelaunayTriangulator :: findNonDelaunayTriangles(int insertedNode, InsertTriangleBasedOnCircumcircle &tInsert, std :: list< Edge2D > &polygon)
398{
399 DofManager *node = domain->giveNode(insertedNode);
400 const auto &nodeCoords = node->giveCoordinates();
401
402 ElementCircumCirclesContainingNode findElements(nodeCoords, domain);
403 std :: list< DelaunayTriangle * > nonDelaunayTriangles;
404
405 this->searchingTimer.resumeTimer();
406 triangleOctree.proceedDataOnFilterAndRemoveFromOctree(nonDelaunayTriangles, findElements, tInsert, searchingTimer);
407 this->searchingTimer.pauseTimer();
408
409 this->polygonTimer.resumeTimer();
410 for ( auto triangle : nonDelaunayTriangles ) {
411 addUniqueEdgeToPolygon({triangle->giveNode(1), triangle->giveNode(2)}, polygon);
412 addUniqueEdgeToPolygon({triangle->giveNode(2), triangle->giveNode(3)}, polygon);
413 addUniqueEdgeToPolygon({triangle->giveNode(3), triangle->giveNode(1)}, polygon);
414 triangle->setValidFlag(false);
415 }
416
417 this->polygonTimer.pauseTimer();
418}
419
420void
421DelaunayTriangulator :: meshPolygon(int insertedNode, InsertTriangleBasedOnCircumcircle &tInsert, std :: list< Edge2D > &polygon)
422{
423 for ( auto polygonIT = polygon.begin(); polygonIT != polygon.end(); polygonIT++ ) {
424 DelaunayTriangle *newTriangle = new DelaunayTriangle(domain, ( * polygonIT ).giveFirstNodeNumber(), ( * polygonIT ).giveSecondNodeNumber(), insertedNode);
425
426 this->creativeTimer.resumeTimer();
427 triangleOctree.insertMemberIntoOctree(newTriangle, tInsert);
428 this->creativeTimer.pauseTimer();
429
430 generalTriangleList.push_back(newTriangle);
431 }
432
433 polygon.clear();
434}
435
436void
437DelaunayTriangulator :: giveTimeReport()
438{
439 this->meshingTimer.stopTimer();
440 double _utime = this->meshingTimer.getUtime();
441
442 this->searchingTimer.stopTimer();
443 double _searchutime = this->searchingTimer.getUtime();
444
445 this->polygonTimer.stopTimer();
446 double _polygonutime = this->polygonTimer.getUtime();
447
448 this->creativeTimer.stopTimer();
449 double _creativeutime = this->creativeTimer.getUtime();
450
451 printf("\nUser time consumed by searching: %.3f [s]\n\n", _searchutime);
452 printf("\nUser time consumed by building insertion polygon: %.3f [s]\n\n", _polygonutime);
453 printf("\nUser time consumed by creating elements: %.3f [s]\n\n", _creativeutime);
454 printf("\nUser time consumed by meshing: %.3f [s]\n\n", _utime);
455}
456
457void
458DelaunayTriangulator :: cleanUpTriangleList()
459{
460 for ( auto genIT = generalTriangleList.begin(); genIT != generalTriangleList.end(); ) {
461 int node1 = ( * genIT )->giveNode(1);
462 int node2 = ( * genIT )->giveNode(2);
463 int node3 = ( * genIT )->giveNode(3);
464
465 if ( node1 == nnode + 1 || node1 == nnode + 2 || node1 == nnode + 3 || node1 == nnode + 4 ||
466 node2 == nnode + 1 || node2 == nnode + 2 || node2 == nnode + 3 || node2 == nnode + 4 ||
467 node3 == nnode + 1 || node3 == nnode + 2 || node3 == nnode + 3 || node3 == nnode + 4 ||
468 !( ( * genIT )->giveValidFlag() ) ) {
469 delete( * genIT );
470 genIT = generalTriangleList.erase(genIT);
471 } else {
472 genIT++;
473 }
474 }
475}
476
477void DelaunayTriangulator :: buildInitialBBXMesh(InsertTriangleBasedOnCircumcircle &tInsert)
478{
479 BoundingBox BBX;
480 this->computeBBXBasedOnNodeData(BBX);
481
482 //int initialDivision = 5;
483 triangleOctree.init(BBX);
484
485 FloatArray coords;
486
487 auto bottomLeftNode = std::make_unique<Node>(nnode + 1, domain);
488 BBX.giveOrigin(coords);
489 double diff = BBX.giveSize();
490 for ( int ci = 1; ci <= 2; ci++ ) {
491 coords.at(ci) -= diff;
492 }
493
494 bottomLeftNode->setCoordinates(coords);
495
496 auto bottomRightNode = std::make_unique<Node>(nnode + 2, domain);
497 coords.at(1) += BBX.giveSize() + 2.0 * diff;
498 bottomRightNode->setCoordinates(coords);
499
500 auto topRightNode = std::make_unique<Node>(nnode + 3, domain);
501 coords.at(2) += BBX.giveSize() + 2.0 * diff;
502 topRightNode->setCoordinates(coords);
503
504 auto topLeftNode = std::make_unique<Node>(nnode + 4, domain);
505 coords.at(1) -= BBX.giveSize() + 2.0 * diff;
506 topLeftNode->setCoordinates(coords);
507
508 domain->resizeDofManagers(nnode + 4);
509 domain->setDofManager(nnode + 1, std::move(bottomLeftNode));
510 domain->setDofManager(nnode + 2, std::move(bottomRightNode));
511 domain->setDofManager(nnode + 3, std::move(topRightNode));
512 domain->setDofManager(nnode + 4, std::move(topLeftNode));
513
514 DelaunayTriangle *firstTriangle = new DelaunayTriangle(domain, nnode + 1, nnode + 2, nnode + 3);
515 generalTriangleList.push_back(firstTriangle);
516
517 DelaunayTriangle *secondTriangle = new DelaunayTriangle(domain, nnode + 3, nnode + 4, nnode + 1);
518 generalTriangleList.push_back(secondTriangle);
519
520 triangleOctree.insertMemberIntoOctree(firstTriangle, tInsert);
521 triangleOctree.insertMemberIntoOctree(secondTriangle, tInsert);
522}
523
524void
526{
527 int init = 1, nnode = this->domain->giveNumberOfDofManagers();
528 FloatArray minc(3), maxc(3);
529
530 // first determine domain extends (bounding box), and check for degenerated domain type
531 for ( int i = 1; i <= nnode; i++ ) {
532 auto node = domain->giveNode(i);
533 const auto &coords = node->giveCoordinates();
534 if ( init ) {
535 init = 0;
536 for ( int j = 1; j <= coords.giveSize(); j++ ) {
537 minc.at(j) = maxc.at(j) = coords.at(j);
538 }
539 } else {
540 for ( int j = 1; j <= coords.giveSize(); j++ ) {
541 if ( coords.at(j) < minc.at(j) ) {
542 minc.at(j) = coords.at(j);
543 }
544 if ( coords.at(j) > maxc.at(j) ) {
545 maxc.at(j) = coords.at(j);
546 }
547 }
548 }
549 } // end loop over nodes
550
551 BBX.setOrigin(minc);
552
553 // determine root size
554 double rootSize = 0.0;
555 for ( int i = 1; i <= 3; i++ ) {
556 rootSize = 1.000001 * max( rootSize, maxc.at(i) - minc.at(i) );
557 }
558
559 BBX.setSize(rootSize);
560
561 // check for degenerated domain
562 double resolutionLimit = min(1.e-3, rootSize / 1.e6);
563 for ( int i = 1; i <= 3; i++ ) {
564 if ( ( maxc.at(i) - minc.at(i) ) > resolutionLimit ) {
565 BBX.setMask(i, 1);
566 } else {
567 BBX.setMask(i, 0);
568 }
569 }
570}
571
572
573} // end namespace oofem
double giveOuterAlphaBound()
Returns the outer limit.
Definition edge2d.h:90
void setOuterAlphaBound(double alphaMin)
Sets the outer limit.
Definition edge2d.h:86
void setSharing(int n, DelaunayTriangle *pTE)
Stores DelaunayTriangle sharing the receiver.
Definition edge2d.C:70
void setHullFlag(bool flag)
Sets the convex hull property.
Definition edge2d.h:94
void setInnerAlphaBound(double alphaMax)
Sets the inner limit.
Definition edge2d.h:88
double giveInnerAlphaBound()
Returns the inner limit.
Definition edge2d.h:92
void setMask(int i, int mask)
Sets the spatial mask.
void giveOrigin(FloatArray &answer)
void setOrigin(FloatArray &coords)
Sets the origin of the bounding box.
void setSize(double s)
Sets the size of the bounding box (all sides are equal).
double giveSize()
Gives the size of the bounding box.
Timer searchingTimer
Measures time needed by searching for non-delaunay triangles.
void addUniqueEdgeToPolygon(Edge2D edge, std ::list< Edge2D > &polygon)
Edge is added to the polygon only if it's not contained. Otherwise both are removed (edge shared by t...
void giveAlphaShape()
Iterates through the edgeList container and compares alpha-value with alphaEdge bounds....
Timer meshingTimer
Measures overall time of triangulation procedure.
void meshPolygon(int insertedNode, InsertTriangleBasedOnCircumcircle &tInsert, std ::list< Edge2D > &polygon)
Retriangulates the polygon.
std ::list< AlphaEdge2D * > alphaShapeEdgeList
Contains resulting alpha-shape in form of a list.
void computeAlphaComplex()
Reads the triangulation and fills tha edgeList container with alpha-shape edges and set their bounds.
Timer polygonTimer
Measures time needed for identifying polygon to be retriangulated.
AlphaEdge2D * giveBackEdgeIfAlreadyContainedInList(AlphaEdge2D &alphaEdge)
void computeBBXBasedOnNodeData(BoundingBox &BBX)
Calculates the bounding box base on the domain's nodes.
std ::list< AlphaEdge2D * > edgeList
contains all edges of the triangulation
OctreeSpatialLocalizerT< DelaunayTriangle * > triangleOctree
Octree with Delaunay triangles allowing fast search.
Domain * domain
Domain of the PFEM problem containing nodes to be triangulated.
void buildInitialBBXMesh(InsertTriangleBasedOnCircumcircle &tInsert)
Identifies the bounding box of pfemparticles and creates initial triangulation consisting of 2 triang...
void cleanUpTriangleList()
Iterates through generalTringleList und removes non-valid ones or those containing bounding box nodes...
void writeMesh()
Writes the mesh into the domain by creating new tr1_2d_pfem elements and prescribes zero-pressure bou...
void initializeTimers()
Initializes Timers and.
Timer creativeTimer
Measures time needed for creating new Delaunay triangles.
void findNonDelaunayTriangles(int insertedNode, InsertTriangleBasedOnCircumcircle &tInsert, std ::list< Edge2D > &polygon)
Looks for non-Delaunay triangles in octree and creates a polygon.
std ::list< DelaunayTriangle * > generalTriangleList
Contains all triangles (even not valid).
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
virtual void setBcId(int bcId)
Overwrites the boundary condition id (0-inactive BC), intended for specific purposes such as coupling...
Definition dof.h:382
double & at(Index i)
Definition floatarray.h:202
virtual bool isActive()
Returns the activeFlag.
virtual void setOnAlphaShape(bool newFlag=true)
Sets the alphaShapeFlag.
int giveAssociatedMaterialNumber()
Returns number of material to be associated with created elements.
Definition pfem.h:273
int giveAssociatedCrossSectionNumber()
Returns number of cross section to be associated with created elements.
Definition pfem.h:275
int giveAssociatedPressureBC()
Returns number of zero pressure boundary condition to be prescribed on free surface.
Definition pfem.h:277
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
#define VERBOSE_PRINT0(str, number)
Definition verbose.h:56

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