OOFEM 3.0
Loading...
Searching...
No Matches
pfem.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// Implementation according paper:
36// S.R. Idelsohn, E. Onate, F. Del Pin
37// The particle finite element method: a powerful tool to solve
38// incompressible flows with free-surface and breaking waves
39
40#include "pfem.h"
41#include "nummet.h"
42#include "timestep.h"
43#include "metastep.h"
44#include "element.h"
45#include "dofmanager.h"
46#include "elementside.h"
47#include "dof.h"
48#include "initialcondition.h"
49#include "verbose.h"
50#include "connectivitytable.h"
51#include "pfemelement.h"
52#include "tr1_2d_pfem.h"
54#include "load.h"
55#include "pfemparticle.h"
56#include "octreelocalizert.h" //changed from "octreelocalizer.h"
57#include "octreelocalizertutil.h"
58#include "spatiallocalizer.h"
59#include "classfactory.h"
60#include "mathfem.h"
61#include "datastream.h"
62#include "contextioerr.h"
63#include "leplic.h"
64
65
66namespace oofem {
68
69
70void PFEMPressureRhsAssembler :: vectorFromElement(FloatArray &vec, Element &element, TimeStep *tStep, ValueModeType mode) const
71{
72 PFEMElement &pelem = static_cast< PFEMElement & >( element );
73
75 pelem.giveCharacteristicMatrix(d, DivergenceMatrix, tStep);
76 FloatArray u_star;
77 pelem.computeVectorOf(VM_Intermediate, tStep, u_star);
78 vec.beProductOf(d, u_star);
79
80 FloatArray reducedVec;
81 pelem.computePrescribedRhsVector(reducedVec, tStep, mode);
82 reducedVec.negated();
83 vec.assemble( reducedVec, pelem.givePressureDofMask() );
84}
85
86
87void PFEMCorrectionRhsAssembler :: vectorFromElement(FloatArray &vec, Element &element, TimeStep *tStep, ValueModeType mode) const
88{
89 PFEMElement &pelem = static_cast< PFEMElement & >( element );
90
92 FloatArray p;
93 pelem.computeVectorOfPressures(VM_Total, tStep, p);
94 pelem.computeGradientMatrix(g, tStep);
95 vec.beProductOf(g, p);
96 vec.times(-deltaT);
97
99 FloatArray u;
100 pelem.computeDiagonalMassMtrx(m, tStep);
101 pelem.computeVectorOfVelocities(VM_Intermediate, tStep, u);
102 for ( int i = 0; i < m.giveNumberOfColumns(); ++i ) {
103 vec [ i ] += m(i, i) * u [ i ];
104 }
105}
106
107void PFEMCorrectionRhsAssembler :: locationFromElement(IntArray &loc, Element &element, const UnknownNumberingScheme &s, IntArray *dofIds) const
108{
109 // Note: For 2D, the V_w will just be ignored anyweay, so it's safe to use all three always.
110 //element.giveLocationArray(loc, {V_u, V_v, V_w}, s, dofIds);
111 element.giveLocationArray(loc, { V_u, V_v }, s, dofIds);
112}
113
114
115void PFEMLaplaceVelocityAssembler :: vectorFromElement(FloatArray &vec, Element &element, TimeStep *tStep, ValueModeType mode) const
116{
117 PFEMElement &pelem = static_cast< PFEMElement & >( element );
118
119 FloatMatrix l;
120 FloatArray u;
121 pelem.computeStiffnessMatrix(l, TangentStiffness, tStep);
122 pelem.computeVectorOfVelocities(VM_Total, tStep, u);
123 vec.beProductOf(l, u);
124}
125
126void PFEMLaplaceVelocityAssembler :: locationFromElement(IntArray &loc, Element &element, const UnknownNumberingScheme &s, IntArray *dofIds) const
127{
128 //element.giveLocationArray(loc, {V_u, V_v, V_w}, s, dofIds);
129 element.giveLocationArray(loc, { V_u, V_v }, s, dofIds);
130}
131
132
133void PFEMMassVelocityAssembler :: vectorFromElement(FloatArray &vec, Element &element, TimeStep *tStep, ValueModeType mode) const
134{
135 PFEMElement &pelem = static_cast< PFEMElement & >( element );
136
137 FloatMatrix m;
138 FloatArray u;
139 pelem.computeDiagonalMassMtrx(m, tStep);
140 pelem.computeVectorOfVelocities(VM_Total, tStep, u);
141 vec.beProductOf(m, u);
142}
143
144void PFEMMassVelocityAssembler :: locationFromElement(IntArray &loc, Element &element, const UnknownNumberingScheme &s, IntArray *dofIds) const
145{
146 //element.giveLocationArray(loc, {V_u, V_v, V_w}, s, dofIds);
147 element.giveLocationArray(loc, { V_u, V_v }, s, dofIds);
148}
149
150
151void PFEMPressureLaplacianAssembler :: matrixFromElement(FloatMatrix &mat, Element &element, TimeStep *tStep) const
152{
153 PFEMElement &pelem = static_cast< PFEMElement & >( element );
154 pelem.computePressureLaplacianMatrix(mat, tStep);
155}
156
157void PFEMPressureLaplacianAssembler :: locationFromElement(IntArray &loc, Element &element, const UnknownNumberingScheme &s, IntArray *dofIds) const
158{
159 element.giveLocationArray(loc, { P_f }, s, dofIds);
160}
161
162
163NumericalMethod *PFEM :: giveNumericalMethod(MetaStep *mStep)
164{
165 if ( !nMethod ) {
166 nMethod = classFactory.createSparseLinSolver(solverType, this->giveDomain(1), this);
167 if ( !nMethod) {
168 OOFEM_ERROR("linear solver creation failed for lstype %d", solverType);
169 }
170 }
171 return nMethod.get();
172}
173
174
175int
176PFEM :: forceEquationNumbering(int id)
177{
179 // forces equation renumbering for current time step
180 // intended mainly for problems with changes of static system
181 // during solution
182 // OUTPUT:
183 // sets this->numberOfEquations and this->numberOfPrescribedEquations and returns this value
184
185 // first initialize default numbering (for velocity unknowns only)
186
187 Domain *domain = this->giveDomain(id);
188 TimeStep *currStep = this->giveCurrentStep();
189
190 this->domainNeqs.at(id) = 0;
191 this->domainPrescribedNeqs.at(id) = 0;
192
193 // number velocities first
194 for ( auto &dman : domain->giveDofManagers() ) {
195 for ( Dof *jDof: *dman ) {
196 DofIDItem type = jDof->giveDofID();
197 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
198 jDof->askNewEquationNumber(currStep);
199 }
200 }
201 }
202
203 // initialize the independent pressure and auxiliary velocity/equation numbering
204 pns.init(domain, currStep);
205 avns.init(domain);
206
207 return domainNeqs.at(id);
208}
209
210
211
212void
253
254
255
256double
257PFEM :: giveUnknownComponent(ValueModeType mode, TimeStep *tStep, Domain *d, Dof *dof)
258// returns unknown quantity like pressure or velocity of dof
259{
260 if ( mode == VM_Intermediate ) {
261 if ( AuxVelocity.isNotEmpty() ) {
262 int index = avns.giveDofEquationNumber(dof);
263 if ( index > 0 && index <= AuxVelocity.giveSize() ) {
264 return AuxVelocity.at(index);
265 } else {
266 return 0.0;
267 }
268 } else {
269 return 0.;
270 }
271 } else {
272 if ( this->requiresUnknownsDictionaryUpdate() ) {
273 int hash = this->giveUnknownDictHashIndx(mode, tStep);
274 if ( dof->giveUnknowns()->includes(hash) ) {
275 return dof->giveUnknowns()->at(hash);
276 } else {
277 OOFEM_ERROR( "giveUnknown: Dof unknowns dictionary does not contain unknown of value mode (%s)", __ValueModeTypeToString(mode) );
278 return 0.; // to make compiler happy
279 }
280 } else {
281 return 0.0;
282 }
283 }
284}
285
286
287TimeStep *
288PFEM :: giveSolutionStepWhenIcApply(bool force)
289{
290 if ( master && (!force)) {
291 return master->giveSolutionStepWhenIcApply();
292 } else {
293 if ( !stepWhenIcApply ) {
294 stepWhenIcApply = std::make_unique<TimeStep>(giveNumberOfTimeStepWhenIcApply(), this, 0, 0.0, deltaT, 0);
295 }
296 return stepWhenIcApply.get();
297 }
298}
299
300void
301PFEM :: preInitializeNextStep()
302{
303 Domain *domain = this->giveDomain(1);
304 domain->clearElements();
305
306 DelaunayTriangulator myMesher(domain, alphaShapeCoef);
307 myMesher.generateMesh();
308
309 for ( auto &dman : domain->giveDofManagers() ) {
310 PFEMParticle *particle = dynamic_cast< PFEMParticle * >( dman.get() );
311 particle->setFree();
312 }
313
314 if ( domain->giveNumberOfElements() > 0 ) {
315 for ( auto &element : domain->giveElements() ) {
316 element->checkConsistency();
317
318 for ( int j = 1; j <= element->giveNumberOfDofManagers(); j++ ) {
319 dynamic_cast< PFEMParticle * >( element->giveDofManager(j) )->setFree(false);
320 }
321 }
322 } else {
323 VERBOSE_PRINTS("Mesh generation failed", "0 elements created");
324 }
325
326 for ( auto &dman : domain->giveDofManagers() ) {
327 for ( Dof *jDof: *dman ) {
328 DofIDItem type = jDof->giveDofID();
329 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
330 if ( jDof->giveBcId() ) {
331 dynamic_cast< PFEMParticle * >( dman.get() )->setFree(false);
332 break;
333 }
334 }
335 }
336 }
337}
338
339TimeStep *
340PFEM :: giveNextStep()
341{
342 int istep = this->giveNumberOfFirstStep();
343 double totalTime = 0;
344 StateCounterType counter = 1;
345 Domain *domain = this->giveDomain(1);
346
347 if ( !currentStep ) {
348 // first step -> generate initial step
349 currentStep = std::make_unique<TimeStep>( * giveSolutionStepWhenIcApply() );
350 } else {
351 istep = currentStep->giveNumber() + 1;
352 counter = currentStep->giveSolutionStateCounter() + 1;
353 }
354
355 previousStep = std :: move(currentStep);
356
357 EngngModel :: forceEquationNumbering();
358
359 double volume = 0.0;
360
361 double ndt = dynamic_cast< PFEMElement * >( domain->giveElement(1) )->computeCriticalTimeStep( previousStep.get() );
362 // check for critical time step
363 for ( int i = 2; i <= domain->giveNumberOfElements(); i++ ) {
364 TR1_2D_PFEM *ielem = dynamic_cast< TR1_2D_PFEM * >( domain->giveElement(i) );
365 double idt = ielem->computeCriticalTimeStep( previousStep.get() );
366 if ( idt < ndt ) {
367 ndt = idt;
368 OOFEM_LOG_INFO("Reducing time step due to element #%i \n", i);
369 }
370 volume += ielem->computeArea();
371 }
372
373 ndt = min(ndt, deltaT);
374
375 totalTime = previousStep->giveTargetTime() + ndt;
376
377 currentStep = std::make_unique<TimeStep>(istep, this, 1, totalTime, ndt, counter);
378 // time and dt variables are set eq to 0 for staics - has no meaning
379
380 OOFEM_LOG_INFO( "SolutionStep %d : t = %e, dt = %e\n", istep, totalTime * this->giveVariableScale(VST_Time), ndt * this->giveVariableScale(VST_Time) );
381 if ( printVolumeReport ) {
382 OOFEM_LOG_INFO("Volume leakage: %.3f%%\n", ( 1.0 - ( volume / domainVolume ) ) * 100.0);
383 }
384
385 return currentStep.get();
386}
387
388void
389PFEM :: solveYourselfAt(TimeStep *tStep)
390{
391 int auxmomneq = this->giveNumberOfDomainEquations(1, avns);
392 int momneq = this->giveNumberOfDomainEquations(1, vns);
393 int presneq = this->giveNumberOfDomainEquations(1, pns);
394
395 double deltaT = tStep->giveTimeIncrement();
396
397 FloatArray rhs(auxmomneq);
398
399
400 double d_pnorm = 1.0;
401 double d_vnorm = 1.0;
402
403 AuxVelocity.resize(auxmomneq);
404
405 avLhs.clear();
406 avLhs.resize(auxmomneq);
407
408 this->assembleVector( avLhs, tStep, LumpedMassVectorAssembler(), VM_Total, avns, this->giveDomain(1) );
409
410 pLhs = classFactory.createSparseMtrx(sparseMtrxType);
411 if ( !pLhs ) {
412 OOFEM_ERROR("solveYourselfAt: sparse matrix creation failed");
413 }
414
415 pLhs->buildInternalStructure(this, 1, pns);
416
417 this->assemble( * pLhs, tStep, PFEMPressureLaplacianAssembler(), pns, this->giveDomain(1) );
418
419 pLhs->times(deltaT);
420
422
423 vLhs.clear();
424 vLhs.resize(momneq);
425
426 this->assembleVector( vLhs, tStep, LumpedMassVectorAssembler(), VM_Total, vns, this->giveDomain(1) );
427
428 if ( tStep->giveNumber() == giveNumberOfFirstStep() ) {
431 }
432
433 if ( VelocityField.giveActualStepNumber() < tStep->giveNumber() ) {
434 VelocityField.advanceSolution(tStep);
435 }
436
437 if ( PressureField.giveActualStepNumber() < tStep->giveNumber() ) {
438 PressureField.advanceSolution(tStep);
439 }
440
441 FloatArray *velocityVector = VelocityField.giveSolutionVector(tStep);
442 FloatArray *pressureVector = PressureField.giveSolutionVector(tStep);
443
444 FloatArray velocityVectorThisStep(* velocityVector);
445 FloatArray velocityVectorLastStep(* velocityVector);
446
447 FloatArray pressureVectorThisStep(* pressureVector);
448 FloatArray pressureVectorLastStep(* pressureVector);
449
450 if ( tStep->isTheFirstStep() ) {
451 for ( int i = 1; i <= this->giveDomain(1)->giveNumberOfDofManagers(); i++ ) {
452 this->updateDofUnknownsDictionary(this->giveDomain(1)->giveDofManager(i), tStep);
453 }
454 }
455
456 FloatArray externalForces;
457 externalForces.resize(auxmomneq);
458 this->assembleVector( externalForces, tStep, ExternalForceAssembler(), VM_Total, avns, this->giveDomain(1) );
459
460 int iteration = 0;
461 do {
462 iteration++;
463
464 velocityVectorLastStep = velocityVectorThisStep;
465 pressureVectorLastStep = pressureVectorThisStep;
466
467 /************************** STEP 1 - calculates auxiliary velocities *************************/
468
469 rhs.resize(auxmomneq);
470 rhs.zero();
471
472 if ( discretizationScheme == 1 ) { //implicit
473 if ( iteration > 1 ) {
474 this->assembleVectorFromElements( rhs, tStep, PFEMLaplaceVelocityAssembler(), VM_Total, avns, this->giveDomain(1) );
475 }
476 } else if ( discretizationScheme == 0 ) { // explicit
477 this->assembleVectorFromElements( rhs, tStep->givePreviousStep(), PFEMLaplaceVelocityAssembler(), VM_Total, avns, this->giveDomain(1) );
478 }
479
480 rhs.negated();
481
482 // constant member placed outside of the loop
483 rhs.add(externalForces);
484
485 rhs.times(deltaT);
486
487
489 // for ( int i = 1; i <= momneq; i++ ) {
490 // rhs.at(i) +=  avLhs.at(i) * oldVelocityVector.at(i);
491 // }
492
493 if ( tStep->isTheFirstStep() == false ) {
494 this->assembleVectorFromElements( rhs, tStep->givePreviousStep(), PFEMMassVelocityAssembler(), VM_Total, avns, this->giveDomain(1) );
495 }
496
497 this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) );
498 AuxVelocity.resize( rhs.giveSize() );
499 for ( int i = 1; i <= auxmomneq; i++ ) {
500 AuxVelocity.at(i) = rhs.at(i) / avLhs.at(i);
501 }
502
503 /************************* STEP 2 - calculates pressure ************************************/
504
505 rhs.resize(presneq);
506 rhs.zero();
507
508 this->assembleVectorFromElements( rhs, tStep, PFEMPressureRhsAssembler(), VM_Total, pns, this->giveDomain(1) );
509
510 this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) );
511 pressureVector->resize(presneq);
512 nMethod->solve(* pLhs, rhs, * pressureVector);
513
514 for ( auto &dman : this->giveDomain(1)->giveDofManagers() ) {
515 this->updateDofUnknownsDictionaryPressure(dman.get(), tStep);
516 }
517
518 /**************************** STEP 3 - velocity correction step ********************************/
519
520
521
522 rhs.resize(momneq);
523 rhs.zero();
524 velocityVector->resize(momneq);
525
526 this->assembleVectorFromElements( rhs, tStep, PFEMCorrectionRhsAssembler(deltaT), VM_Total, vns, this->giveDomain(1) );
527
528 this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) );
529
530 velocityVector->resize( rhs.giveSize() );
531 for ( int i = 1; i <= momneq; i++ ) {
532 velocityVector->at(i) = rhs.at(i) / vLhs.at(i);
533 }
534
535 for ( int i = 1; i <= this->giveDomain(1)->giveNumberOfDofManagers(); i++ ) {
536 PFEMParticle *particle = dynamic_cast< PFEMParticle * >( this->giveDomain(1)->giveDofManager(i) );
537 this->updateDofUnknownsDictionaryVelocities(particle, tStep);
538 }
539
540 velocityVectorThisStep = * velocityVector;
541 pressureVectorThisStep = * pressureVector;
542
543 if ( iteration == 1 ) {
544 d_vnorm = velocityVectorThisStep.computeNorm();
545 d_pnorm = pressureVectorThisStep.computeNorm();
546 } else {
547 FloatArray diffVelocity = velocityVectorThisStep;
548 diffVelocity.subtract(velocityVectorLastStep);
549
550 d_vnorm = 0.0;
551 for ( int i = 1; i <= diffVelocity.giveSize(); i++ ) {
552 d_vnorm = max(d_vnorm, fabs( diffVelocity.at(i) ) > 1.e-6 ? fabs( diffVelocity.at(i) / velocityVectorLastStep.at(i) ) : 0);
553 }
554
555 FloatArray diffPressure = pressureVectorThisStep;
556 diffPressure.subtract(pressureVectorLastStep);
557 d_pnorm = 0.0;
558 for ( int i = 1; i <= diffPressure.giveSize(); i++ ) {
559 // TODO : what about divide by zero ????
560 d_pnorm = max(d_pnorm, fabs( diffPressure.at(i) ) > 1.e-6 ? fabs( diffPressure.at(i) / pressureVectorLastStep.at(i) ) : 0);
561 }
562 }
563 } while ( discretizationScheme == 1 && ( d_vnorm > rtolv || d_pnorm > rtolp ) && iteration < maxiter );
564
565 if ( iteration > maxiter ) {
566 OOFEM_ERROR("Maximal iteration count exceded");
567 } else {
568 OOFEM_LOG_INFO("\n %i iterations performed.\n", iteration);
569 }
570
571
572
573 Domain *d = this->giveDomain(1);
574 for ( auto &dman : d->giveDofManagers() ) {
575 PFEMParticle *particle = dynamic_cast< PFEMParticle * >( dman.get() );
576
577 if ( particle->isFree() && particle->isActive() ) {
578 for ( Dof *dof : *particle ) {
579 DofIDItem type = dof->giveDofID();
580 if ( type == V_u || type == V_v || type == V_w ) {
581 int eqnum = dof->giveEquationNumber(vns);
582 if ( eqnum ) {
583 double previousValue = dof->giveUnknown( VM_Total, tStep->givePreviousStep() );
584 Load *load = d->giveLoad(3);
585 FloatArray gVector;
586 load->computeComponentArrayAt(gVector, tStep, VM_Total);
587 previousValue += gVector [ type - V_w ] * deltaT; // Get the corresponding coordinate index for the velocities.
588 velocityVector->at(eqnum) = previousValue;
589 }
590 }
591 }
592 }
593 }
594 tStep->incrementStateCounter();
595}
596
597
598void
599PFEM :: updateYourself(TimeStep *stepN)
600{
601 this->updateInternalState(stepN);
602 EngngModel :: updateYourself(stepN);
603
605}
606
607
608
609void
610PFEM :: updateInternalState(TimeStep *stepN)
611{
612 for ( auto &domain : this->domainList ) {
614 for ( auto &dman : domain->giveDofManagers() ) {
615 this->updateDofUnknownsDictionary(dman.get(), stepN);
616 }
617 }
618
619 for ( auto &elem : domain->giveElements() ) {
620 elem->updateInternalState(stepN);
621 }
622 }
623}
624
625int
626PFEM :: giveUnknownDictHashIndx(ValueModeType mode, TimeStep *stepN)
627{
628 if ( ( stepN == this->giveCurrentStep() ) || ( stepN == this->givePreviousStep() ) ) {
629 int index = ( stepN->giveNumber() % 2 ) * 100 + mode;
630 return index;
631 } else {
632 OOFEM_ERROR("giveUnknownDictHashIndx: unsupported solution step");
633 }
634
635 return 0;
636}
637
638void
639PFEM :: updateDofUnknownsDictionary(DofManager *inode, TimeStep *tStep)
640{
641 for ( Dof *iDof: *inode ) {
642 int eqNum = 0;
643 double val = 0;
644 if ( iDof->hasBc(tStep) ) { // boundary condition
645 val = iDof->giveBcValue(VM_Total, tStep);
646 } else {
647 if ( iDof->giveDofID() == P_f ) {
648 eqNum = pns.giveDofEquationNumber(iDof);
649 FloatArray *vect = PressureField.giveSolutionVector(tStep);
650 if ( vect->giveSize() > 0 ) { // in the first step -> zero will be set
651 val = vect->at(eqNum);
652 }
653 } else { // velocities
654 eqNum = iDof->__giveEquationNumber();
655 FloatArray *vect = VelocityField.giveSolutionVector(tStep);
656 if ( vect->giveSize() > 0 ) {
657 val = vect->at(eqNum);
658 }
659 }
660 }
661
662 iDof->updateUnknownsDictionary(tStep, VM_Total, val);
663 }
664}
665
666void
667PFEM :: updateDofUnknownsDictionaryPressure(DofManager *inode, TimeStep *tStep)
668{
669 Dof *iDof = inode->giveDofWithID(P_f);
670 double val = 0;
671 if ( iDof->hasBc(tStep) ) {
672 val = iDof->giveBcValue(VM_Total, tStep);
673 } else {
674 int eqNum = pns.giveDofEquationNumber(iDof);
675 FloatArray *vect = PressureField.giveSolutionVector(tStep);
676 val = vect->at(eqNum);
677 }
678
679 iDof->updateUnknownsDictionary(tStep, VM_Total, val);
680}
681
682void
683PFEM :: updateDofUnknownsDictionaryVelocities(DofManager *inode, TimeStep *tStep)
684{
685 for ( Dof *iDof : *inode ) {
686 DofIDItem type = iDof->giveDofID();
687 if ( type == V_u || type == V_v || type == V_w ) {
688 int eqNum = 0;
689 double val = 0;
690 if ( iDof->hasBc(tStep) ) { // boundary condition
691 val = iDof->giveBcValue(VM_Total, tStep);
692 } else {
693 eqNum = iDof->__giveEquationNumber();
694 FloatArray *vect = VelocityField.giveSolutionVector(tStep);
695 if ( vect->giveSize() > 0 ) {
696 val = vect->at(eqNum);
697 }
698 }
699 iDof->updateUnknownsDictionary(tStep, VM_Total, val);
700 }
701 }
702}
703
704
705// NOT ACTIVE
706void
707PFEM :: saveContext(DataStream &stream, ContextMode mode)
708{
709 EngngModel :: saveContext(stream, mode);
710 PressureField.saveContext(stream);
711 VelocityField.saveContext(stream);
712}
713
714
715// NOT ACTIVE
716void
717PFEM :: restoreContext(DataStream &stream, ContextMode mode)
718{
719 EngngModel :: restoreContext(stream, mode);
720 PressureField.restoreContext(stream);
721 VelocityField.restoreContext(stream);
722}
723
724
725int
726PFEM :: checkConsistency()
727{
728 Domain *domain = this->giveDomain(1);
729
730 // check for proper element type
731 for ( auto &elem : domain->giveElements() ) {
732 if ( !dynamic_cast< PFEMElement * >( elem.get() ) ) {
733 OOFEM_WARNING( "Element %d has no PFEM base", elem->giveLabel() );
734 return 0;
735 }
736 }
737
738 return EngngModel :: checkConsistency();
739}
740
741
742void
743PFEM :: printDofOutputAt(FILE *stream, Dof *iDof, TimeStep *atTime)
744{
745 DofIDItem type = iDof->giveDofID();
746 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
747 iDof->printSingleOutputAt(stream, atTime, '*', VM_Intermediate);
748 iDof->printSingleOutputAt(stream, atTime, 'u', VM_Total);
749
750 // printing coordinate in DofMan Output
751 DofManager *dman = iDof->giveDofManager();
752 double coordinate = 0.0;
753 int dofNumber = 0;
754 switch ( type ) {
755 case V_u: dofNumber = 1;
756 break;
757 case V_v: dofNumber = 2;
758 break;
759 case V_w: dofNumber = 3;
760 break;
761 default:;
762 }
763 coordinate = dman->giveCoordinate(dofNumber);
764 fprintf(stream, " dof %d c % .8e\n", dofNumber, coordinate);
765 } else if ( ( type == P_f ) ) {
766 iDof->printSingleOutputAt(stream, atTime, 'p', VM_Total);
767 } else {
768 OOFEM_ERROR("printDofOutputAt: unsupported dof type");
769 }
770}
771
772void
773PFEM :: applyIC(TimeStep *stepWhenIcApply)
774{
775 Domain *domain = this->giveDomain(1);
776 int mbneq = this->giveNumberOfDomainEquations(1, vns);
777 int pdneq = this->giveNumberOfDomainEquations(1, pns);
778 FloatArray *velocityVector, *pressureVector;
779
780#ifdef VERBOSE
781 OOFEM_LOG_INFO("Applying initial conditions\n");
782#endif
783
784 int velocityFieldStepNumber = VelocityField.giveActualStepNumber();
785
786 if ( velocityFieldStepNumber < stepWhenIcApply->giveNumber() ) {
787 VelocityField.advanceSolution(stepWhenIcApply);
788 }
789 velocityVector = VelocityField.giveSolutionVector(stepWhenIcApply);
790 velocityVector->resize(mbneq);
791 velocityVector->zero();
792
793 int pressureFieldStepNumber = PressureField.giveActualStepNumber();
794 if ( pressureFieldStepNumber < stepWhenIcApply->giveNumber() ) {
795 PressureField.advanceSolution(stepWhenIcApply);
796 }
797 pressureVector = PressureField.giveSolutionVector(stepWhenIcApply);
798 pressureVector->resize(pdneq);
799 pressureVector->zero();
800
801
802 for ( auto &node : domain->giveDofManagers() ) {
803 for ( Dof *iDof: *node ) {
804 // ask for initial values obtained from
805 // bc (boundary conditions) and ic (initial conditions)
806 //iDof = node->giveDof(k);
807 if ( !iDof->isPrimaryDof() ) {
808 continue;
809 }
810
811 int jj = iDof->__giveEquationNumber();
812 DofIDItem type = iDof->giveDofID();
813
814 if ( jj ) {
815 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
816 velocityVector->at(jj) = iDof->giveUnknown(VM_Total, stepWhenIcApply);
817 } else {
818 pressureVector->at(jj) = iDof->giveUnknown(VM_Total, stepWhenIcApply);
819 }
820 }
821 }
822 }
823
824 // update element state according to given ic
825 for ( auto &elem : domain->giveElements() ) {
826 PFEMElement *element = static_cast< PFEMElement * >( elem.get() );
829 domainVolume += element->computeArea();
830 }
831}
832
833int
834PFEM :: giveNewEquationNumber(int domain, DofIDItem id)
835{
836 if ( ( id == V_u ) || ( id == V_v ) || ( id == V_w ) ) {
837 return this->vns.askNewEquationNumber();
838 } else {
839 OOFEM_ERROR("giveNewEquationNumber:: Unknown DofIDItem");
840 }
841
842 return 0;
843}
844
845int
846PFEM :: giveNewPrescribedEquationNumber(int domain, DofIDItem id)
847{
848 if ( ( id == V_u ) || ( id == V_v ) || ( id == V_w ) ) {
849 return prescribedVns.askNewEquationNumber();
850 } else {
851 OOFEM_ERROR("giveNewPrescribedEquationNumber:: Unknown DofIDItem");
852 }
853
854 return 0;
855}
856
857int PFEM :: giveNumberOfDomainEquations(int d, const UnknownNumberingScheme &numberingScheme) { //
858 // returns number of equations of current problem
859 // this method is implemented here, because some method may add some
860 // conditions in to system and this may results into increased number of
861 // equations.
862 //
863
865 EngngModel :: forceEquationNumbering();
866 }
867
868 return numberingScheme.giveRequiredNumberOfDomainEquation();
869}
870
871
872void
873PFEM :: resetEquationNumberings()
874{
875 vns.reset();
876 prescribedVns.reset();
877 pns.reset();
878 avns.reset();
879}
880
881void
882PFEM :: deactivateTooCloseParticles()
883{
884 Domain *d = this->giveDomain(1);
885 // deactivating particles
886 if ( particleRemovalRatio > 1.e-6 ) { // >0
887 for ( int i = 1; i <= d->giveNumberOfElements(); i++ ) {
888 TR1_2D_PFEM *element = dynamic_cast< TR1_2D_PFEM * >( d->giveElement(i) );
889
890 PFEMParticle *particle1 = dynamic_cast< PFEMParticle * >( element->giveNode(1) );
891 PFEMParticle *particle2 = dynamic_cast< PFEMParticle * >( element->giveNode(2) );
892 PFEMParticle *particle3 = dynamic_cast< PFEMParticle * >( element->giveNode(3) );
893
894 double l12 = distance( particle1->giveCoordinates(), particle2->giveCoordinates() );
895 double l23 = distance( particle2->giveCoordinates(), particle3->giveCoordinates() );
896 double l31 = distance( particle3->giveCoordinates(), particle1->giveCoordinates() );
897
898 double maxLength = max( l12, max(l23, l31) );
899 double minLength = min( l12, min(l23, l31) );
900
901 if ( minLength / maxLength < particleRemovalRatio ) {
902 if ( fabs(l12 - minLength) < 1.e-6 ) { // ==
903 if ( particle1->isActive() && particle2->isActive() ) {
904 bool isSupported = false;
905
906 for ( Dof *jDof: *particle1 ) {//int j = 1; j <= particle1->giveNumberOfDofs();
907 DofIDItem type = jDof->giveDofID();
908 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
909 if ( jDof->giveBcId() ) {
910 isSupported = true;
911 }
912 }
913 }
914 if ( isSupported == false ) {
915 particle1->deactivate();
916 } else {
917 particle2->deactivate();
918 }
919 } else if ( particle1->isActive() == false || particle2->isActive() == false ) {
920 ; // it was deactivated by other element
921 } else {
922 OOFEM_ERROR("Both particles deactivated");
923 }
924 }
925
926 if ( fabs(l23 - minLength) < 1.e-6 ) { // ==
927 if ( particle2->isActive() && particle3->isActive() ) {
928 bool isSupported = false;
929
930 for ( Dof *jDof : *particle2 ) {
931 DofIDItem type = jDof->giveDofID();
932 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
933 if ( jDof->giveBcId() ) {
934 isSupported = true;
935 }
936 }
937 }
938 if ( isSupported == false ) {
939 particle2->deactivate();
940 } else {
941 particle3->deactivate();
942 }
943 } else if ( particle2->isActive() == false || particle3->isActive() == false ) {
944 ; // it was deactivated by other element
945 } else {
946 OOFEM_ERROR("Both particles deactivated");
947 }
948 }
949
950 if ( fabs(l31 - minLength) < 1.e-6 ) { // ==
951 if ( particle3->isActive() && particle1->isActive() ) {
952 bool isSupported = false;
953 for ( Dof *jDof : *particle3 ) {
954 DofIDItem type = jDof->giveDofID();
955 if ( ( type == V_u ) || ( type == V_v ) || ( type == V_w ) ) {
956 if ( jDof->giveBcId() ) {
957 isSupported = true;
958 }
959 }
960 }
961 if ( isSupported == false ) {
962 particle3->deactivate();
963 } else {
964 particle1->deactivate();
965 }
966 } else if ( particle3->isActive() == false || particle1->isActive() == false ) {
967 ; // it was deactivated by other element
968 } else {
969 OOFEM_ERROR("Both particles deactivated");
970 }
971 }
972 }
973 }
974 }
975}
976} // end namespace oofem
#define REGISTER_EngngModel(class)
double giveCoordinate(int i) const
Definition dofmanager.h:383
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
Dof * giveDofWithID(int dofID) const
Definition dofmanager.C:127
DofIDItem giveDofID() const
Definition dof.h:276
virtual double giveBcValue(ValueModeType mode, TimeStep *tStep)
Definition dof.C:120
virtual void updateUnknownsDictionary(TimeStep *tStep, ValueModeType mode, double dofValue)
Definition dof.h:366
virtual void giveUnknowns(FloatArray &masterUnknowns, ValueModeType mode, TimeStep *tStep)
Definition dof.C:159
DofManager * giveDofManager() const
Definition dof.h:123
virtual void printSingleOutputAt(FILE *file, TimeStep *tStep, char ch, ValueModeType mode, double scale=1.0)
Definition dof.C:76
virtual bool hasBc(TimeStep *tStep)=0
void clearElements()
Clear all elements.
Definition domain.C:478
int giveNumberOfElements() const
Returns number of elements in domain.
Definition domain.h:463
std ::vector< std ::unique_ptr< DofManager > > & giveDofManagers()
Definition domain.h:427
Load * giveLoad(int n)
Definition domain.C:226
Element * giveElement(int n)
Definition domain.C:165
std ::vector< std ::unique_ptr< Element > > & giveElements()
Definition domain.h:294
Node * giveNode(int i) const
Definition element.h:629
virtual double computeArea()
Definition element.C:1136
virtual void updateYourself(TimeStep *tStep)
Definition element.C:824
void giveLocationArray(IntArray &locationArray, const UnknownNumberingScheme &s, IntArray *dofIds=NULL) const
Definition element.C:429
void computeVectorOf(ValueModeType u, TimeStep *tStep, FloatArray &answer)
Definition element.C:103
int giveNumberOfTimeStepWhenIcApply()
Returns the time step number, when initial conditions should apply.
Definition engngm.h:787
std ::vector< std ::unique_ptr< Domain > > domainList
List of problem domains.
Definition engngm.h:217
virtual TimeStep * giveCurrentStep(bool force=false)
Definition engngm.h:717
void assembleVectorFromElements(FloatArray &answer, TimeStep *tStep, const VectorAssembler &va, ValueModeType mode, const UnknownNumberingScheme &s, Domain *domain, FloatArray *eNorms=NULL)
Definition engngm.C:1351
std ::unique_ptr< TimeStep > previousStep
Previous time step.
Definition engngm.h:243
int equationNumberingCompleted
Equation numbering completed flag.
Definition engngm.h:233
Domain * giveDomain(int n)
Definition engngm.C:1936
std ::unique_ptr< TimeStep > currentStep
Current time step.
Definition engngm.h:241
MetaStep * giveMetaStep(int i)
Returns the i-th meta step.
Definition engngm.h:773
virtual double giveVariableScale(VarScaleType varId)
Returns the scale factor for given variable type.
Definition engngm.h:1183
virtual TimeStep * givePreviousStep(bool force=false)
Definition engngm.h:738
EngngModel * master
Master e-model; if defined receiver is in maintained (slave) mode.
Definition engngm.h:274
virtual int giveNumberOfFirstStep(bool force=false)
Definition engngm.h:763
std ::unique_ptr< TimeStep > stepWhenIcApply
Solution step when IC (initial conditions) apply.
Definition engngm.h:239
IntArray domainPrescribedNeqs
Number of prescribed equations per domain.
Definition engngm.h:227
void assembleVector(FloatArray &answer, TimeStep *tStep, const VectorAssembler &va, ValueModeType mode, const UnknownNumberingScheme &s, Domain *domain, FloatArray *eNorms=NULL)
Definition engngm.C:1106
IntArray domainNeqs
Number of equations per domain.
Definition engngm.h:225
void computeVectorOfPressures(ValueModeType mode, TimeStep *tStep, FloatArray &pressures)
Definition fmelement.C:51
void computeVectorOfVelocities(ValueModeType mode, TimeStep *tStep, FloatArray &velocities)
Definition fmelement.C:44
double computeNorm() const
Definition floatarray.C:861
void assemble(const FloatArray &fe, const IntArray &loc)
Definition floatarray.C:616
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void add(const FloatArray &src)
Definition floatarray.C:218
void subtract(const FloatArray &src)
Definition floatarray.C:320
void times(double s)
Definition floatarray.C:834
int giveNumberOfColumns() const
Returns number of columns of receiver.
virtual void computeComponentArrayAt(FloatArray &answer, TimeStep *tStep, ValueModeType mode)
Definition load.C:84
virtual double computeCriticalTimeStep(TimeStep *tStep)=0
Calculates critical time step.
virtual void computePrescribedRhsVector(FloatArray &answer, TimeStep *tStep, ValueModeType mode)=0
Calculates the prescribed velocity vector for the right hand side of the pressure equation.
void giveCharacteristicMatrix(FloatMatrix &answer, CharType, TimeStep *) override
Definition pfemelement.C:76
virtual void computeStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, TimeStep *atTime)=0
Calculates the stiffness matrix.
virtual const IntArray & givePressureDofMask() const =0
Returns mask of pressure Dofs.
virtual void computeDiagonalMassMtrx(FloatArray &answer, TimeStep *)=0
virtual void computePressureLaplacianMatrix(FloatMatrix &answer, TimeStep *atTime)=0
Calculates the pressure laplacian matrix.
void updateInternalState(TimeStep *tStep) override
virtual void computeGradientMatrix(FloatMatrix &answer, TimeStep *atTime)=0
Calculates the pressure gradient matrix.
virtual void setFree(bool newFlag=true)
Sets the free-property flag.
virtual void deactivate()
Sets the activeFlag to false.
virtual bool isActive()
Returns the activeFlag.
virtual bool isFree()
Returns the free-propery flag.
std ::unique_ptr< SparseLinearSystemNM > nMethod
Numerical method used to solve the problem.
Definition pfem.h:128
FloatArray AuxVelocity
Array of auxiliary velocities used during computation.
Definition pfem.h:147
void applyIC(TimeStep *)
Initializes velocity and pressure fields in the first step with prescribed values.
Definition pfem.C:773
void updateInternalState(TimeStep *)
Definition pfem.C:610
void updateDofUnknownsDictionaryVelocities(DofManager *inode, TimeStep *tStep)
Writes velocities into the dof unknown dictionaries.
Definition pfem.C:683
int giveUnknownDictHashIndx(ValueModeType mode, TimeStep *stepN) override
Definition pfem.C:626
int maxiter
Max number of iterations.
Definition pfem.h:160
bool printVolumeReport
Flag for volume report.
Definition pfem.h:165
LinSystSolverType solverType
Used solver type for linear system of equations.
Definition pfem.h:130
void updateDofUnknownsDictionaryPressure(DofManager *inode, TimeStep *tStep)
Writes pressures into the dof unknown dictionaries.
Definition pfem.C:667
double domainVolume
Area or volume of the fluid domain, which can be controlled.
Definition pfem.h:163
AuxVelocityNumberingScheme avns
Auxiliary Velocity numbering.
Definition pfem.h:180
int associatedCrossSection
Number of cross section to associate with created elements.
Definition pfem.h:171
PressureNumberingScheme pns
Pressure numbering.
Definition pfem.h:178
double deltaT
Time step length.
Definition pfem.h:150
SparseMtrxType sparseMtrxType
Used type of sparse matrix.
Definition pfem.h:132
FloatArray avLhs
Left-hand side matrix for the auxiliary velocity equations.
Definition pfem.h:135
double rtolv
Convergence tolerance.
Definition pfem.h:158
void deactivateTooCloseParticles()
Deactivates particles upon the particalRemovalRatio.
Definition pfem.C:882
TimeStep * giveSolutionStepWhenIcApply(bool force=false) override
Definition pfem.C:288
VelocityNumberingScheme vns
Velocity numbering.
Definition pfem.h:182
PrimaryField VelocityField
Velocity field.
Definition pfem.h:145
int discretizationScheme
Explicit or implicit time discretization.
Definition pfem.h:168
std ::unique_ptr< SparseMtrx > pLhs
Left-hand side matrix for the pressure equations.
Definition pfem.h:137
FloatArray vLhs
Left-hand side matrix for the velocity equations.
Definition pfem.h:139
int associatedMaterial
Number of material to associate with created elements.
Definition pfem.h:173
double minDeltaT
Minimal value of time step.
Definition pfem.h:152
double rtolp
Definition pfem.h:158
int associatedPressureBC
Number of pressure boundary condition to be prescribed on free surface.
Definition pfem.h:175
int giveNumberOfDomainEquations(int, const UnknownNumberingScheme &num) override
Definition pfem.C:857
PrimaryField PressureField
Pressure field.
Definition pfem.h:143
double alphaShapeCoef
Value of alpha coefficient for the boundary recognition.
Definition pfem.h:154
void updateDofUnknownsDictionary(DofManager *inode, TimeStep *tStep) override
Definition pfem.C:639
NumericalMethod * giveNumericalMethod(MetaStep *) override
Returns reference to receiver's numerical method.
Definition pfem.C:163
int requiresUnknownsDictionaryUpdate() override
Definition pfem.h:235
double particleRemovalRatio
Element side ratio for the removal of the close partices.
Definition pfem.h:156
void resetEquationNumberings()
Resets the equation numberings as the mesh is recreated in each time step.
Definition pfem.C:873
VelocityNumberingScheme prescribedVns
Prescribed velocity numbering.
Definition pfem.h:184
double computeCriticalTimeStep(TimeStep *tStep) override
Calculates critical time step.
int giveMetaStepNumber()
Returns receiver's meta step number.
Definition timestep.h:150
void incrementStateCounter()
Updates solution state counter.
Definition timestep.h:213
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
bool isTheFirstStep()
Definition timestep.C:148
virtual int giveRequiredNumberOfDomainEquation() const
#define _IFT_EngngModel_lstype
Definition engngm.h:91
#define _IFT_EngngModel_smtype
Definition engngm.h:92
#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 IR_GIVE_FIELD(__ir, __value, __id)
Definition inputrecord.h:67
#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)
FloatArrayF< N > assemble(const FloatArrayF< M > &x, int const (&c)[M])
Assemble components into zero matrix.
long StateCounterType
StateCounterType type used to indicate solution state.
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
ClassFactory & classFactory
double distance(const FloatArray &x, const FloatArray &y)
#define _IFT_PFEM_discretizationScheme
Definition pfem.h:56
#define _IFT_PFEM_mindeltat
Definition pfem.h:52
#define _IFT_PFEM_maxiter
Definition pfem.h:62
#define _IFT_PFEM_rtolp
Definition pfem.h:61
#define _IFT_PFEM_printVolumeReport
Definition pfem.h:55
#define _IFT_PFEM_associatedCrossSection
Definition pfem.h:58
#define _IFT_PFEM_associatedMaterial
Definition pfem.h:57
#define _IFT_PFEM_deltat
Definition pfem.h:51
#define _IFT_PFEM_particalRemovalRatio
Definition pfem.h:54
#define _IFT_PFEM_alphashapecoef
Definition pfem.h:53
#define _IFT_PFEM_rtolv
Definition pfem.h:60
#define _IFT_PFEM_pressureBC
Definition pfem.h:59
#define VERBOSE_PRINTS(str, str1)
Definition verbose.h:55

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