OOFEM 3.0
Loading...
Searching...
No Matches
zzerrorestimator.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
38#include "domain.h"
39#include "dofmanager.h"
40#include "element.h"
41#include "gausspoint.h"
42#include "floatarray.h"
43#include "floatmatrix.h"
44#include "mathfem.h"
47#include "timestep.h"
48#include "integrationrule.h"
49#include "feinterpol.h"
50#include "connectivitytable.h"
51#include "errorestimatortype.h"
52#include "classfactory.h"
53#include "engngm.h"
54#include "parallelcontext.h"
55
56#include <vector>
57
58namespace oofem {
60
61#ifdef EXPERIMENT
62FloatArray sNorms;
63#endif
64
65
66int
67ZZErrorEstimator :: estimateError(EE_ErrorMode mode, TimeStep *tStep)
68{
69 int nelems = this->domain->giveNumberOfElements();
71 double sNorm;
73
74 if ( mode == temporaryEM ) {
75 type = IST_StressTensorTemp; // OOFEM_ERROR("temporaryEM mode not supported");
76 }
77
78 if ( this->stateCounter == tStep->giveSolutionStateCounter() ) {
79 return 1;
80 }
81
82 NodalRecoveryModel *oldSmoother, *rm = NULL;
83 if ( this->nodalRecoveryType == ZZRecovery ) {
84 rm = new ZZNodalRecoveryModel(this->domain);
85 } else if ( this->nodalRecoveryType == SPRRecovery ) {
86 rm = new SPRNodalRecoveryModel(this->domain);
87 } else {
88 OOFEM_ERROR("unknown nodal recovery type");
89 }
90
91 // first set the domain Smoother to suitable one, keep old one to be recovered
92 oldSmoother = this->domain->giveSmoother();
93 this->domain->setSmoother(rm, 0); // do not delete old one
94
95 // create a new set containing all elements
96 Set elemSet(0, this->domain);
97 elemSet.addAllElements();
98 // recover nodal values on entire elemSet (domain)
99 rm->recoverValues(elemSet, type, tStep);
100
101#ifdef ZZErrorEstimator_ElementResultCashed
102 this->eNorms.resize(nelems);
103 #ifdef EXPERIMENT
104 sNorms.resize(nelems);
105 #endif
106#else
107 double eNorm;
108#endif
109
110 this->globalENorm = this->globalSNorm = 0.0;
111 // loop over domain's elements
112 for ( int ielem = 1; ielem <= nelems; ielem++ ) {
113 if ( this->skipRegion( this->domain->giveElement(ielem)->giveRegionNumber() ) ) {
114 continue;
115 }
116
117 interface = static_cast< ZZErrorEstimatorInterface * >( this->domain->giveElement(ielem)->giveInterface(ZZErrorEstimatorInterfaceType) );
118 if ( interface == NULL ) {
119 OOFEM_ERROR("Element has no ZZ error estimator interface defined");
120 }
121
122#ifdef ZZErrorEstimator_ElementResultCashed
123 interface->ZZErrorEstimatorI_computeElementContributions(eNorms.at(ielem), sNorm, this->normType, type, tStep);
124 this->globalENorm += eNorms.at(ielem) * eNorms.at(ielem);
125 #ifdef EXPERIMENT
126 sNorms.at(ielem) = sNorm;
127 #endif
128#else
129 interface->ZZErrorEstimatorI_computeElementContributions(eNorm, sNorm, this->normType, type, tStep);
130 this->globalENorm += eNorm * eNorm;
131#endif
132 this->globalSNorm += sNorm * sNorm;
133 }
134
135 FloatArray gnorms;
136 ParallelContext *parallel_context = this->domain->giveEngngModel()->giveParallelContext(this->domain->giveNumber());
137 parallel_context->accumulate(Vec2(this->globalENorm, this->globalSNorm), gnorms);
138 this->globalENorm = gnorms [ 0 ];
139 this->globalSNorm = gnorms [ 1 ];
140
141
142 // recover the stored smoother
143 this->domain->setSmoother(oldSmoother); //delete old one (the rm)
144
145 // report the error estimate
146 double pe = sqrt( this->globalENorm / ( this->globalENorm + this->globalSNorm ) );
147 OOFEM_LOG_RELEVANT("Relative stress error estimate: %5.2f%%\n", pe * 100.0);
148
149 this->globalENorm = sqrt(this->globalENorm);
150 this->globalSNorm = sqrt(this->globalSNorm);
151 this->globalErrorEstimate = pe;
152
153
154 this->stateCounter = tStep->giveSolutionStateCounter();
155 return 1;
156}
157
158double
159ZZErrorEstimator :: giveElementError(EE_ErrorType type, Element *elem, TimeStep *tStep)
160{
161 if ( this->skipRegion( elem->giveRegionNumber() ) ) {
162 return 0.0;
163 }
164
165 this->estimateError(equilibratedEM, tStep);
166
167#ifdef ZZErrorEstimator_ElementResultCashed
168 if ( type == internalStressET ) {
169 return this->eNorms.at( elem->giveNumber() );
170 }
171
172#else
173 ZZErrorEstimatorInterface *interface;
174 if ( type == internalStressET ) {
175 double e, s;
176 interface = static_cast< ZZErrorEstimatorInterface * >( elem->giveInterface(ZZErrorEstimatorInterfaceType) );
177 if ( interface ) {
178 interface->ZZErrorEstimatorI_computeElementContributions(e, s, this->normType, tStep);
179 return e;
180 } else {
181 return 0.0;
182 }
183 }
184
185#endif
186 return 0.0;
187}
188
189double
190ZZErrorEstimator :: giveValue(EE_ValueType type, TimeStep *tStep)
191{
192 this->estimateError(equilibratedEM, tStep);
193 if ( type == globalErrorEEV ) {
194 return this->globalENorm;
195 } else if ( type == globalNormEEV ) {
196 return this->globalSNorm;
197 } else if ( type == relativeErrorEstimateEEV ) {
198 return this->globalErrorEstimate;
199 } else {
200 return 0.0;
201 }
202}
203
205ZZErrorEstimator :: giveRemeshingCrit()
206{
207 if ( !this->rc ) {
208 this->rc = std::make_unique<ZZRemeshingCriteria>(1, this);
209 }
210
211 return this->rc.get();
212}
213
214
215void
216ZZErrorEstimator :: initializeFrom(InputRecord &ir)
217{
218 int n;
219
220 ErrorEstimator :: initializeFrom(ir);
221 n = 0;
223 if ( n == 1 ) {
224 this->normType = EnergyNorm;
225 } else {
226 this->normType = L2Norm; // default
227 }
228
229 n = 0;
231 if ( n == 1 ) {
233 } else {
234 this->nodalRecoveryType = ZZRecovery; // default
235 }
236
237 return this->giveRemeshingCrit()->initializeFrom(ir);
238}
239
240void
241ZZErrorEstimatorInterface :: ZZErrorEstimatorI_computeElementContributions(double &eNorm, double &sNorm,
242 ZZErrorEstimator :: NormType norm,
244 TimeStep *tStep)
245{
246 int nDofMans;
247 FEInterpolation *interpol = element->giveInterpolation();
248 const FloatArray *recoveredStress;
249 FloatArray sig, lsig, diff, ldiff, n;
250 FloatMatrix nodalRecoveredStreses;
251
252 nDofMans = element->giveNumberOfDofManagers();
253 // assemble nodal recovered stresses
254 for ( int i = 1; i <= element->giveNumberOfNodes(); i++ ) {
255 element->giveDomain()->giveSmoother()->giveNodalVector( recoveredStress,
256 element->giveDofManager(i)->giveNumber() );
257 if ( i == 1 ) {
258 nodalRecoveredStreses.resize( nDofMans, recoveredStress->giveSize() );
259 }
260 for ( int j = 1; j <= recoveredStress->giveSize(); j++ ) {
261 nodalRecoveredStreses.at(i, j) = recoveredStress->at(j);
262 }
263 }
264 /* Note: The recovered stresses should be in global coordinate system. This is important for shells, for example, to make
265 * sure that forces and moments in the same directions are averaged. For elements where local and global coordina systems
266 * are the same this does not matter.
267 */
268
269 eNorm = sNorm = 0.0;
270
271 // compute the e-norm and s-norm
272 if ( norm == ZZErrorEstimator :: L2Norm ) {
274 double dV = element->computeVolumeAround(gp);
275 interpol->evalN( n, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(element) );
276
277 diff.beTProductOf(nodalRecoveredStreses, n);
278
279 element->giveIPValue(sig, gp, type, tStep);
280 /* the internal stress difference is in global coordinate system */
281 diff.subtract(sig);
282
283 eNorm += diff.computeSquaredNorm() * dV;
284 sNorm += sig.computeSquaredNorm() * dV;
285 }
286 } else if ( norm == ZZErrorEstimator :: EnergyNorm ) {
287 FloatArray help, ldiff_reduced, lsig_reduced;
288 FloatMatrix D, DInv;
289 StructuralElement *selem = static_cast< StructuralElement * >(element);
290
292 double dV = element->computeVolumeAround(gp);
293 interpol->evalN( n, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(element) );
294 selem->computeConstitutiveMatrixAt(D, TangentStiffness, gp, tStep);
295 DInv.beInverseOf(D);
296
297 diff.beTProductOf(nodalRecoveredStreses, n);
298
299 element->giveIPValue(sig, gp, type, tStep); // returns full value now
300 diff.subtract(sig);
301 /* the internal stress difference is in global coordinate system */
302 /* needs to be transformed into local system to compute associated energy */
303 this->ZZErrorEstimatorI_computeLocalStress(ldiff, diff);
304 StructuralMaterial :: giveReducedSymVectorForm( ldiff_reduced, ldiff, gp->giveMaterialMode() );
305
306 help.beProductOf(DInv, ldiff_reduced);
307 eNorm += ldiff_reduced.dotProduct(help) * dV;
309 StructuralMaterial :: giveReducedSymVectorForm( lsig_reduced, lsig, gp->giveMaterialMode() );
310 help.beProductOf(DInv, lsig_reduced);
311 sNorm += lsig_reduced.dotProduct(help) * dV;
312 }
313 } else {
314 OOFEM_ERROR("unsupported norm type");
315 }
316
317 eNorm = sqrt(eNorm);
318 sNorm = sqrt(sNorm);
319}
320
321
322ZZRemeshingCriteria :: ZZRemeshingCriteria(int n, ErrorEstimator *e) : RemeshingCriteria(n, e)
323{
324 this->mode = stressBased;
325 this->stateCounter = 0;
326}
327
328double
329ZZRemeshingCriteria :: giveRequiredDofManDensity(int num, TimeStep *tStep, int relative)
330{
331 double size;
332
333 this->estimateMeshDensities(tStep);
334 size = this->nodalDensities.at(num);
335 if ( size >= 0 ) {
336 size = max(minElemSize, size);
337 if ( relative ) {
338 return size / this->giveDofManDensity(num);
339 } else {
340 return size;
341 }
342 } else {
343 // size negative -> marks undetermined size
344 return size;
345 }
346}
347
348
350ZZRemeshingCriteria :: giveRemeshingStrategy(TimeStep *tStep)
351{
352 this->estimateMeshDensities(tStep);
353 return this->remeshingStrategy;
354}
355
356int
357ZZRemeshingCriteria :: estimateMeshDensities(TimeStep *tStep)
358{
359 int nelem, nnode, elemPolyOrder, ielemNodes;
360 double globValNorm = 0.0, globValErrorNorm = 0.0, elemErrLimit, eerror, iratio, currDensity, elemSize;
361 EE_ErrorType errorType = indicatorET;
362 double pe, coeff = 2.0;
363
364 if ( stateCounter == tStep->giveSolutionStateCounter() ) {
365 return 1;
366 }
367
368 nelem = this->domain->giveNumberOfElements();
369 nnode = this->domain->giveNumberOfDofManagers();
370
371 //std::vector<char> nodalDensities(nnode);
372 this->nodalDensities.resize(nnode);
373 std :: vector< char > dofManInitFlag(nnode);
374 for ( int i = 0; i < nnode; i++ ) {
375 dofManInitFlag [ i ] = 0;
376 }
377
378 // compute element error limit based on equally distribution error principle
379 if ( mode == stressBased ) {
380 globValNorm = this->ee->giveValue(globalNormEEV, tStep);
381 globValErrorNorm = this->ee->giveValue(globalErrorEEV, tStep);
382 errorType = internalStressET;
383 } else {
384 OOFEM_ERROR("unknown mode");
385 }
386
387
388 // test if solution is allowable
389 pe = sqrt( globValErrorNorm * globValErrorNorm / ( globValErrorNorm * globValErrorNorm + globValNorm * globValNorm ) );
390 if ( pe <= this->requiredError ) {
392 // added by bp
393 /*
394 * for (i=1; i<=nnode; i++) nodalDensities.at(i) = this->giveDofManDensity (i);
395 * stateCounter = tStep->giveSolutionStateCounter();
396 * return 1; // remove to force computing densities
397 */
398 } else {
400 }
401
402 elemErrLimit = sqrt( ( globValNorm * globValNorm + globValErrorNorm * globValErrorNorm ) / nelem ) *
403 this->requiredError * coeff;
404
405 for ( auto &elem : domain->giveElements() ) {
406
407 if ( this->ee->skipRegion( elem->giveRegionNumber() ) ) {
408 continue;
409 }
410
411 eerror = this->ee->giveElementError(errorType, elem.get(), tStep);
412 iratio = eerror / elemErrLimit;
413 if ( fabs(iratio) < 1.e-3 ) {
414 continue;
415 }
416
417 if ( iratio > 1.0 ) {
419 }
420
421 if ( iratio < 0.5 ) {
422 iratio = 0.5;
423 }
424
425 // if (iratio > 5.0)iratio = 5.0;
426
427 currDensity = elem->computeMeanSize();
428 elemPolyOrder = elem->giveInterpolation()->giveInterpolationOrder();
429 elemSize = currDensity / pow(iratio, 1.0 / elemPolyOrder);
430
431 ielemNodes = elem->giveNumberOfDofManagers();
432 for ( int j = 1; j <= ielemNodes; j++ ) {
433 int jnode = elem->giveDofManager(j)->giveNumber();
434 if ( dofManInitFlag [ jnode - 1 ] ) {
435 this->nodalDensities.at(jnode) = min(this->nodalDensities.at(jnode), elemSize);
436 } else {
437 this->nodalDensities.at(jnode) = elemSize;
438 dofManInitFlag [ jnode - 1 ] = 1;
439 }
440 }
441 }
442
443 // init non-initialized nodes -> those in skip regions
444 for ( int i = 0; i < nnode; i++ ) {
445 if ( dofManInitFlag [ i ] == 0 ) {
446 this->nodalDensities.at(i + 1) = this->giveDofManDensity(i + 1);
447 }
448 }
449
450 // remember time stamp
452 return 1;
453}
454
455void
456ZZRemeshingCriteria :: initializeFrom(InputRecord &ir)
457{
460}
461
462
463double
464ZZRemeshingCriteria :: giveDofManDensity(int num)
465{
466 int isize;
467 bool init = false;
468 ConnectivityTable *ct = domain->giveConnectivityTable();
469 const IntArray *con;
470 double density;
471
472 con = ct->giveDofManConnectivityArray(num);
473 isize = con->giveSize();
474
475#if 0
476 // Minimum density
477 for ( int i = 1; i <= isize; i++ ) {
478 Element *ielem = domain->giveElement( con->at(i) );
479 if (i==1)
480 density = ielem->computeMeanSize();
481 else
482 density = min(density, ielem->computeMeanSize());
483 }
484#endif
485
486 // Average density
487
488 density = 0.0;
489 for ( int i = 1; i <= isize; i++ ) {
490 Element *ielem = domain->giveElement( con->at(i) );
491 init = true;
492 density += ielem->computeMeanSize();
493 }
494 if ( init ) {
495 density /= isize;
496 } else {
497 // the nodal mesh density could not be determined
498 density = -1;
499 }
500
501 return density;
502}
503} // end namespace oofem
#define REGISTER_ErrorEstimator(class, type)
const IntArray * giveDofManConnectivityArray(int dofman)
double computeMeanSize()
Definition element.C:1100
int giveRegionNumber()
Definition element.C:546
std ::unique_ptr< RemeshingCriteria > rc
bool skipRegion(int reg)
InternalStateType IStype
Internal state type of variable to get internal forces.
virtual void evalN(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
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
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
double computeSquaredNorm() const
Definition floatarray.C:867
double dotProduct(const FloatArray &x) const
Definition floatarray.C:524
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void beTProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:721
void subtract(const FloatArray &src)
Definition floatarray.C:320
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
bool beInverseOf(const FloatMatrix &src)
double at(std::size_t i, std::size_t j) const
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
virtual int recoverValues(Set elementSet, InternalStateType type, TimeStep *tStep)=0
double accumulate(double local)
RemeshingCriteria(int n, ErrorEstimator *e)
Constructor.
void addAllElements()
Definition set.C:239
virtual void computeConstitutiveMatrixAt(FloatMatrix &answer, MatResponseMode rMode, GaussPoint *gp, TimeStep *tStep)=0
StateCounterType giveSolutionStateCounter()
Definition timestep.h:211
virtual void ZZErrorEstimatorI_computeElementContributions(double &eNorm, double &sNorm, ZZErrorEstimator ::NormType norm, InternalStateType type, TimeStep *tStep)
virtual IntegrationRule * ZZErrorEstimatorI_giveIntegrationRule()
virtual void ZZErrorEstimatorI_computeLocalStress(FloatArray &answer, FloatArray &sig)
double globalSNorm
Global norm of quantity which error is evaluated.
NodalRecoveryType nodalRecoveryType
Nodal recovery type.
FloatArray eNorms
Cache storing element norms.
RemeshingCriteria * giveRemeshingCrit() override
double globalErrorEstimate
Global error estimate (relative).
NormType normType
Type of norm used.
int estimateError(EE_ErrorMode mode, TimeStep *tStep) override
double globalENorm
Global error norm.
StateCounterType stateCounter
Actual state counter.
ZZRemeshingCriteriaModeType mode
Mode of receiver.
RemeshingStrategy remeshingStrategy
Remeshing strategy proposed.
StateCounterType stateCounter
Actual values (densities) state counter.
int estimateMeshDensities(TimeStep *tStep) override
double requiredError
Required error to obtain.
double minElemSize
Minimum element size allowed.
double giveDofManDensity(int num) override
FloatArray nodalDensities
Array of nodal mesh densities.
#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_RELEVANT(...)
Definition logger.h:142
static FloatArray Vec2(const double &a, const double &b)
Definition floatarray.h:606
double norm(const FloatArray &x)
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
@ equilibratedEM
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
RemeshingStrategy
Type representing the remeshing strategy.
@ RemeshingFromPreviousState_RS
@ NoRemeshing_RS
@ ZZErrorEstimatorInterfaceType
@ globalErrorEEV
@ relativeErrorEstimateEEV
@ globalNormEEV
@ EET_ZZEE
Zienkiewicz-Zhu EE.
@ internalStressET
#define _IFT_ZZErrorEstimator_normtype
#define _IFT_ZZErrorEstimator_recoverytype
#define _IFT_ZZRemeshingCriteria_requirederror
#define _IFT_ZZRemeshingCriteria_minelemsize

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