OOFEM 3.0
Loading...
Searching...
No Matches
transportgradientneumann.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 "classfactory.h"
37#include "node.h"
38#include "masterdof.h"
39#include "element.h"
40#include "feinterpol.h"
41#include "feinterpol2d.h"
42#include "gausspoint.h"
43#include "sparsemtrx.h"
46#include "timestep.h"
47#include "function.h"
48#include "sparselinsystemnm.h"
50#include "engngm.h"
51#include "mathfem.h"
52#include "dynamicinputrecord.h"
54
55#ifdef _OPENMP
56#include <omp.h>
57#endif
58
59namespace oofem {
61
62TransportGradientNeumann :: TransportGradientNeumann(int n, Domain *d) :
64 //PrescribedGradientHomogenization(),
65 mpFluxHom( std::make_unique<Node>(0, d) )
66{
67 int nsd = d->giveNumberOfSpatialDimensions();
68 for ( int i = 0; i < nsd; i++ ) {
69 // Just putting in X_i id-items since they don't matter.
70 int dofId = d->giveNextFreeDofID();
71 mFluxIds.followedBy(dofId);
72 mpFluxHom->appendDof( new MasterDof( mpFluxHom.get(), ( DofIDItem ) ( dofId ) ) );
73 }
74}
75
76
77void TransportGradientNeumann :: initializeFrom(InputRecord &ir)
78{
79 ActiveBoundaryCondition :: initializeFrom(ir);
80
82
84 this->mCenterCoord.clear();
86
88}
89
90
91void TransportGradientNeumann :: giveInputRecord(DynamicInputRecord &input)
92{
93 //ActiveBoundaryCondition :: giveInputRecord(input);
94 //PrescribedGradientHomogenization :: giveInputRecord(input);
96}
97
98
99void TransportGradientNeumann :: postInitialize()
100{
101 ActiveBoundaryCondition :: postInitialize();
102
103 if ( this->dispControl ) this->computeEta();
104}
105
106
107DofManager *TransportGradientNeumann :: giveInternalDofManager(int i)
108{
109 return mpFluxHom.get();
110}
111
112void TransportGradientNeumann :: scale(double s)
113{
114 this->mGradient.times(s);
115}
116
117double TransportGradientNeumann :: domainSize()
118{
119 Domain *domain = this->giveDomain();
120 int nsd = domain->giveNumberOfSpatialDimensions();
121 double domain_size = 0.0;
122 // This requires the boundary to be consistent and ordered correctly.
123 for ( auto &setNum : this->surfSets ) {
124 Set *set = domain->giveSet(setNum);
125 const IntArray &boundaries = set->giveBoundaryList();
126
127 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
128 Element *e = domain->giveElement( boundaries[pos * 2] );
129 int boundary = boundaries[pos * 2 + 1];
131 domain_size += fei->evalNXIntegral( boundary, FEIElementGeometryWrapper(e) );
132 }
133 }
134 return fabs(domain_size / nsd);
135}
136
137void TransportGradientNeumann :: assembleVector(FloatArray &answer, TimeStep *tStep,
138 CharType type, ValueModeType mode,
139 const UnknownNumberingScheme &s,
140 FloatArray *eNorm,
141 void* lock)
142{
143 IntArray flux_loc; // For the displacements and flux respectively
144 mpFluxHom->giveLocationArray(mFluxIds, flux_loc, s);
145
146 if ( type == ExternalForcesVector ) {
147 // The external forces have two contributions. On the additional equations for flux, the load is simply the prescribed gradient.
148 double rve_size = this->domainSize();
149 FloatArray fluxLoad;
150
151 double loadLevel = this->giveTimeFunction()->evaluateAtTime(tStep->giveTargetTime());
152 fluxLoad.beScaled(-rve_size*loadLevel, mGradient);
153#ifdef _OPENMP
154 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
155#endif
156 answer.assemble(fluxLoad, flux_loc);
157#ifdef _OPENMP
158 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
159#endif
160 } else if ( type == InternalForcesVector ) {
161 FloatMatrix Ke;
162 FloatArray fe_v, fe_s;
163 FloatArray fluxHom, e_u;
164 IntArray loc, masterDofIDs, fluxMasterDofIDs;
165
166 // Fetch the current values of the flux;
167 mpFluxHom->giveUnknownVector(fluxHom, mFluxIds, mode, tStep);
168 // and the master dof ids for flux used for the internal norms
169 mpFluxHom->giveMasterDofIDArray(mFluxIds, fluxMasterDofIDs);
170
171 // Assemble
172 for ( int i = 0; i < this->surfSets.giveSize(); ++i ) {
173 int surfSet = this->surfSets[i];
174 Set *setPointer = this->giveDomain()->giveSet(surfSet);
175 const IntArray &boundaries = setPointer->giveBoundaryList();
176 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
177 Element *e = this->giveDomain()->giveElement( boundaries[pos * 2] );
178 int boundary = boundaries[pos * 2 + 1];
179
180 // Fetch the element information;
181 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
182 e->giveBoundaryLocationArray(loc, bNodes, this->dofs, s, & masterDofIDs);
183 e->computeBoundaryVectorOf(bNodes, this->dofs, mode, tStep, e_u);
184 this->integrateTangent(Ke, e, boundary, i, pos);
185
186 // We just use the tangent, less duplicated code (the addition of flux is linear).
187 fe_v.beProductOf(Ke, e_u);
188 fe_s.beTProductOf(Ke, fluxHom);
189
190 // Note: The terms appear negative in the equations:
191 fe_v.negated();
192 fe_s.negated();
193#ifdef _OPENMP
194 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
195#endif
196 answer.assemble(fe_s, loc); // Contributions to delta_v equations
197 answer.assemble(fe_v, flux_loc); // Contribution to delta_s_i equations
198 if ( eNorm != NULL ) {
199 eNorm->assembleSquared(fe_s, masterDofIDs);
200 eNorm->assembleSquared(fe_v, fluxMasterDofIDs);
201 }
202#ifdef _OPENMP
203 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
204#endif
205 }
206 }
207 }
208}
209
210void TransportGradientNeumann :: assemble(SparseMtrx &answer, TimeStep *tStep,
211 CharType type, const UnknownNumberingScheme &r_s,
212 const UnknownNumberingScheme &c_s, double scale,
213 void* lock)
214{
215 if ( type == TangentStiffnessMatrix || type == SecantStiffnessMatrix || type == ElasticStiffnessMatrix ) {
216 FloatMatrix Ke, KeT;
217 IntArray loc_r, loc_c, flux_loc_r, flux_loc_c;
218
219 // Fetch the columns/rows for the flux contributions;
220 mpFluxHom->giveLocationArray(mFluxIds, flux_loc_r, r_s);
221 mpFluxHom->giveLocationArray(mFluxIds, flux_loc_c, c_s);
222
223 for ( int i = 0; i < this->surfSets.giveSize(); ++i ) {
224 int surfSet = this->surfSets[i];
225 Set *set = this->giveDomain()->giveSet(surfSet);
226 const IntArray &boundaries = set->giveBoundaryList();
227 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
228 Element *e = this->giveDomain()->giveElement( boundaries[pos * 2] );
229 int boundary = boundaries[pos * 2 + 1];
230
231 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
232 e->giveBoundaryLocationArray(loc_r, bNodes, this->dofs, r_s);
233 e->giveBoundaryLocationArray(loc_c, bNodes, this->dofs, c_s);
234
235 this->integrateTangent(Ke, e, boundary, i, pos);
236 Ke.times(-scale);
237 KeT.beTranspositionOf(Ke);
238#ifdef _OPENMP
239 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
240#endif
241 answer.assemble(flux_loc_r, loc_c, Ke); // Contribution to delta_s_i equations
242 answer.assemble(loc_r, flux_loc_c, KeT); // Contributions to delta_v equations
243#ifdef _OPENMP
244 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
245#endif
246 }
247 }
248 } else {
249 printf("Skipping assembly in TransportGradientNeumann::assemble().\n");
250 }
251}
252
253void TransportGradientNeumann :: giveLocationArrays(std :: vector< IntArray > &rows, std :: vector< IntArray > &cols, CharType type,
254 const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s)
255{
256 IntArray loc_r, loc_c, flux_loc_r, flux_loc_c;
257
258 // Fetch the columns/rows for the flux contributions;
259 mpFluxHom->giveLocationArray(mFluxIds, flux_loc_r, r_s);
260 mpFluxHom->giveLocationArray(mFluxIds, flux_loc_c, c_s);
261
262 rows.clear();
263 cols.clear();
264
265 int i = 0;
266 for ( auto &surfSet : this->surfSets ) {
267 Set *set = this->giveDomain()->giveSet(surfSet);
268 const IntArray &boundaries = set->giveBoundaryList();
269
270 rows.resize( rows.size() + boundaries.giveSize() );
271 cols.resize( cols.size() + boundaries.giveSize() );
272 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
273 Element *e = this->giveDomain()->giveElement( boundaries[pos * 2] );
274 int boundary = boundaries[pos * 2 + 1];
275
276 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
277 e->giveBoundaryLocationArray(loc_r, bNodes, this->dofs, r_s);
278 e->giveBoundaryLocationArray(loc_c, bNodes, this->dofs, c_s);
279
280 // For most uses, loc_r == loc_c, and flux_loc_r == flux_loc_c.
281 rows [ i ] = loc_r;
282 cols [ i ] = flux_loc_c;
283 i++;
284 // and the symmetric part (usually the transpose of above)
285 rows [ i ] = flux_loc_r;
286 cols [ i ] = loc_c;
287 i++;
288 }
289 }
290}
291
292void TransportGradientNeumann :: computeField(FloatArray &flux, TimeStep *tStep)
293{
294 mpFluxHom->giveUnknownVector(flux, mFluxIds, VM_Total, tStep);
295}
296
297
298void TransportGradientNeumann :: computeTangent(FloatMatrix &tangent, TimeStep *tStep)
299{
300 EngngModel *rve = this->giveDomain()->giveEngngModel();
302 std :: unique_ptr< SparseLinearSystemNM > solver(
303 classFactory.createSparseLinSolver( ST_Petsc, this->domain, this->domain->giveEngngModel() ) ); // = rve->giveLinearSolver();
304 SparseMtrxType stype = solver->giveRecommendedMatrix(true);
305 double rve_size = this->domainSize();
306
307 // Solving the system:
308 // [Kuu Kus] [u] = [0] => Kuu*u + Kus*s = 0
309 // [Ksu 0 ] [s] = [I] => Ksu*u = I
310 // 1. u = -Kuu^(-1)*Kus*s. Denote us = -Kuu^(-1)*Kus
311 // 2. -[Ksu*us]*s = I. Denote Ks = Ksu*us
312 // 3. s = Ks^(-1)*I
313 // Here, s = tangent as rhs is identity.
314
315 // 1.
316 // This is not very good. We have to keep Kuu and Kff in memory at the same time. Not optimal
317 // Consider changing this approach.
319 std :: unique_ptr< SparseMtrx > Kff( classFactory.createSparseMtrx(stype) );
320 if ( !Kff ) {
321 OOFEM_ERROR("Couldn't create sparse matrix of type %d\n", stype);
322 }
323 Kff->buildInternalStructure(rve, this->domain->giveNumber(), fnum);
324
325 rve->assemble(*Kff, tStep, TangentAssembler(TangentStiffness), fnum, this->domain);
326
327 IntArray loc_u, loc_s;
328 this->mpFluxHom->giveLocationArray(this->mFluxIds, loc_s, fnum);
329 int neq = Kff->giveNumberOfRows();
330 loc_u.resize(neq - loc_s.giveSize());
331 int k = 0;
332 for ( int i = 1; i <= neq; ++i ) {
333 if ( !loc_s.contains(i) ) {
334 loc_u.at(++k) = i;
335 }
336 }
337
338 std :: unique_ptr< SparseMtrx > Kuu = Kff->giveSubMatrix(loc_u, loc_u);
339 FloatMatrix KusD;
340#if 0
341 // NOTE: Kus is actually a dense matrix, but we have to make it a dense matrix first
342 std :: unique_ptr< SparseMtrx > Kus = Kff->giveSubMatrix(loc_u, loc_s);
343 Kus->toFloatMatrix(KusD);
344 Kus.reset();
345#else
346 // Ugly code-duplication, but worth it for performance.
347 // PETSc doesn't allow you to take non-symmetric submatrices from a SBAIJ-matrix.
348 // Which means extracting "Kus" puts limitations on Kuu.
349 FloatMatrix Ke, KeT;
350 IntArray loc_r;
351
352 KusD.resize(neq - loc_s.giveSize(), loc_s.giveSize());
353 for ( int i = 0; i < this->surfSets.giveSize(); ++i ) {
354 int surfSet = this->surfSets[i];
355 Set *set = this->giveDomain()->giveSet(surfSet);
356 const IntArray &boundaries = set->giveBoundaryList();
357 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
358 Element *e = this->giveDomain()->giveElement( boundaries[pos * 2] );
359 int boundary = boundaries[pos * 2 + 1];
360
361 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
362 e->giveBoundaryLocationArray(loc_r, bNodes, this->dofs, fnum);
363
364 this->integrateTangent(Ke, e, boundary, i, pos);
365 Ke.negated();
366 KeT.beTranspositionOf(Ke);
367
368 KusD.assemble(KeT, loc_r, {1, 2, 3}); // Contributions to delta_v equations
369 }
370 }
371#endif
372 // Release a large chunk of redundant memory early.
373 Kff.reset();
374
375 // 1.
376 FloatMatrix us;
377#if 1
378 // Initial guess can help significantly for KSP solver,
379 // However, it is difficult to construct a cheap, reliable estimate for Neumann b.c.
380 // We need the tangent to relate q-bar to g-bar. Since this would be meaningless
381 // we shall instead assume isotropic response, and
382 int nsd = domain->giveNumberOfSpatialDimensions();
383#if 0
384 FloatMatrix Di(nsd, nsd), tmpD, tmpDi;
385 double vol = 0;
386 for ( auto &e : domain->giveElements() ) {
387 static_cast< TransportElement* >(e.get())->computeConstitutiveMatrixAt(tmpD, Capacity,
388 e->giveDefaultIntegrationRulePtr()->getIntegrationPoint(1), tStep);
389 double tmpVol = e->computeVolumeAreaOrLength();
390 vol += tmpVol;
391 tmpDi.beInverseOf(tmpD);
392 Di.add(tmpVol, tmpDi);
393 }
394 Di.times(1/vol);
395#endif
397 for ( auto &n : domain->giveDofManagers() ) {
398 int k1 = n->giveDofWithID( this->dofs[0] )->__giveEquationNumber();
399 if ( k1 ) {
400 const auto &coords = n->giveCoordinates();
401 for ( int i = 1; i <= nsd; ++i ) {
402 us.at(k1, i) += -(coords.at(i) - mCenterCoord.at(i));
403 }
404 }
405 }
406 // Now "us" will have roughly the correct shape, but the wrong magnitude, so we rescale it:
407 FloatMatrix KusD0;
408 Kuu->times(us, KusD0);
409 us.times( KusD.computeFrobeniusNorm() / KusD0.computeFrobeniusNorm() );
410#endif
411
412 if ( solver->solve(*Kuu, KusD, us) != CR_CONVERGED ) {
413 OOFEM_ERROR("Failed to solve Kuu");
414 }
415 us.negated();
416
417 // 2.
418 FloatMatrix Ks;
419 Ks.beTProductOf(KusD, us);
420
421 // 3.
422 tangent.beInverseOf(Ks);
423 tangent.times(rve_size);
424 tangent.negated();
425}
426
427
428void TransportGradientNeumann :: giveFluxLocationArray(IntArray &oCols, const UnknownNumberingScheme &r_s)
429{
430 mpFluxHom->giveLocationArray(mFluxIds, oCols, r_s);
431}
432
433
434void TransportGradientNeumann :: computeEta()
435{
436 OOFEM_LOG_INFO("Computing eta for Neumann b.c.\n");
437 TimeStep *tStep = domain->giveEngngModel()->giveCurrentStep();
438 eta.resize(this->surfSets.giveSize());
439 for ( int i = 0; i < this->surfSets.giveSize(); ++i ) {
440 // Compute the coordinate indices based on what surface we're on.
441 int i_r;
442 int i_t;
443 if ( i % 3 == 0 ) { // Plane facing +- x
444 i_r = 1;
445 i_t = 2;
446 } else if ( i % 3 == 1 ) { // Plane facing +- y
447 i_r = 0;
448 i_t = 2;
449 } else { // Plane facing +- z
450 i_r = 0;
451 i_t = 1;
452 }
453 FloatArray coords, normal, tmp;
454 FloatMatrix d;
455 Set *setPointer = this->giveDomain()->giveSet(surfSets[i]);
456 const IntArray &boundaries = setPointer->giveBoundaryList();
457
458 eta[i].resize(boundaries.giveSize() / 2);
459
460 // Set up and solve: c * eta_c = f
461 // which represents the equations:
462 // int (eta - 1) dA = 0
463 // int (eta - 1) r dA = 0
464 // int (eta - 1) t dA = 0
465 //
466 // int eta_0 + eta_r * r + eta_t * t dA = A
467 // int (eta_0 + eta_r * r + eta_t * t) r dA = int r dA
468 // int (eta_0 + eta_r * r + eta_t * t) t dA = int t dA
469 FloatArray f(3), eta_c;
470 FloatMatrix c(3, 3);
471 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
472 Element *e = this->giveDomain()->giveElement( boundaries[pos * 2] );
473 int boundary = boundaries[pos * 2 + 1];
474
475 FEInterpolation *interp = e->giveInterpolation(); // Geometry interpolation
476 int order = interp->giveInterpolationOrder();
477 std :: unique_ptr< IntegrationRule > ir( interp->giveBoundaryIntegrationRule(order, boundary, e->giveGeometryType()) );
478 static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(d, Capacity, e->giveDefaultIntegrationRulePtr()->getIntegrationPoint(1), tStep);
479
480 for ( auto &gp: *ir ) {
481 const FloatArray &lcoords = gp->giveNaturalCoordinates();
482 FEIElementGeometryWrapper cellgeo(e);
483
484 double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
485 double dA = detJ * gp->giveWeight();
486 interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo);
487 coords.subtract(this->mCenterCoord);
488 double r = coords[i_r], t = coords[i_t];
489
490 // Compute material property
492 //static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(d, Capacity, gp, tStep);
493 tmp.beProductOf(d, normal);
494 double k = tmp.dotProduct(normal);
495
496 f[0] += dA;
497 f[1] += dA * r;
498 f[2] += dA * t;
499
500 c(0, 0) += dA * k;
501 c(0, 1) += dA * k * r;
502 c(0, 2) += dA * k * t;
503 c(1, 0) += dA * k * r;
504 c(1, 1) += dA * k * r * r;
505 c(1, 2) += dA * k * t * r;
506 c(2, 0) += dA * k * t;
507 c(2, 1) += dA * k * r * t;
508 c(2, 2) += dA * k * t * t;
509 }
510 }
511 c.solveForRhs(f, eta_c);
512
513 for ( int pos = 0; pos < boundaries.giveSize() / 2; ++pos ) {
514 Element *e = this->giveDomain()->giveElement( boundaries[pos * 2] );
515 int boundary = boundaries[pos * 2 + 1];
516
517 FEInterpolation *interp = e->giveInterpolation(); // Geometry interpolation
518 int order = interp->giveInterpolationOrder();
519 std :: unique_ptr< IntegrationRule > ir( interp->giveBoundaryIntegrationRule(order, boundary, e->giveGeometryType()) );
520 static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(d, Capacity, e->giveDefaultIntegrationRulePtr()->getIntegrationPoint(1), tStep);
521
522 eta[i][pos].resize(ir->giveNumberOfIntegrationPoints());
523 for ( auto &gp: *ir ) {
524 const FloatArray &lcoords = gp->giveNaturalCoordinates();
525 FEIElementGeometryWrapper cellgeo(e);
526
527 interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
528 interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo);
529 coords.subtract(this->mCenterCoord);
530 double r = coords[i_r], t = coords[i_t];
531
532 // Compute material property
533 //static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(d, Capacity, gp, tStep);
534 tmp.beProductOf(d, normal);
535 double k = tmp.dotProduct(normal);
536
537 eta[i][pos].at(gp->giveNumber()) = (eta_c[0] + eta_c[1] * r + eta_c[2] * t) * k;
538 }
539 }
540 }
541}
542
543
544void TransportGradientNeumann :: integrateTangent(FloatMatrix &oTangent, Element *e, int boundary, int surfSet, int pos)
545{
546 FloatArray normal, n;
547
548 FEInterpolation *interp = e->giveInterpolation(); // Geometry interpolation
549 //FEInterpolation *interpUnknown = e->giveInterpolation(this->dofs[0]);
550
551 int order = interp->giveInterpolationOrder();
552 std :: unique_ptr< IntegrationRule > ir( interp->giveBoundaryIntegrationRule(order, boundary, e->giveGeometryType()) );
553
554 oTangent.clear();
555
556 for ( auto &gp: *ir ) {
557 const FloatArray &lcoords = gp->giveNaturalCoordinates();
558 FEIElementGeometryWrapper cellgeo(e);
559 // If eta isn't set, assume that classical Neumann b.c. is used (eta = 1)
560 double scale = 1.0;
561 if ( !eta.empty() ) {
562 //printf(" surfset %d / %d, pos %d, number %d\n", surfSet, pos, gp->giveNumber(), eta.size());
563 scale = eta[surfSet][pos].at(gp->giveNumber());
564 }
565
566 double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
567 interp->boundaryEvalN(n, boundary, lcoords, cellgeo);
568 oTangent.plusDyadUnsym(normal, n, scale * detJ * gp->giveWeight());
569 }
570}
571} /* namespace oofem */
#define REGISTER_BoundaryCondition(class)
ActiveBoundaryCondition(int n, Domain *d)
Definition activebc.h:71
int giveNextFreeDofID(int increment=1)
Definition domain.C:1519
int giveNumberOfSpatialDimensions()
Returns number of spatial dimensions.
Definition domain.C:1137
void setField(int item, InputFieldType id)
virtual void giveBoundaryLocationArray(IntArray &locationArray, const IntArray &bNodes, const UnknownNumberingScheme &s, IntArray *dofIds=NULL)
Definition element.C:485
virtual FEInterpolation * giveInterpolation() const
Definition element.h:648
virtual IntegrationRule * giveDefaultIntegrationRulePtr()
Definition element.h:886
void computeBoundaryVectorOf(const IntArray &bNodes, const IntArray &dofIDMask, ValueModeType u, TimeStep *tStep, FloatArray &answer, bool padding=false)
Definition element.C:163
virtual Element_Geometry_Type giveGeometryType() const =0
virtual void assemble(SparseMtrx &answer, TimeStep *tStep, const MatrixAssembler &ma, const UnknownNumberingScheme &s, Domain *domain)
Definition engngm.C:889
virtual std::unique_ptr< IntegrationRule > giveBoundaryIntegrationRule(int order, int boundary, const Element_Geometry_Type) const
Definition feinterpol.C:101
virtual IntArray boundaryGiveNodes(int boundary, const Element_Geometry_Type) const =0
virtual double evalNXIntegral(int boundary, const FEICellGeometry &cellgeo) const
Definition feinterpol.h:477
int giveInterpolationOrder() const
Definition feinterpol.h:199
virtual void boundaryLocal2Global(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
virtual double boundaryEvalNormal(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
virtual void boundaryEvalN(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
Domain * giveDomain() const
Definition femcmpnn.h:97
Domain * domain
Link to domain object, useful for communicating with other FEM components.
Definition femcmpnn.h:79
void assemble(const FloatArray &fe, const IntArray &loc)
Definition floatarray.C:616
double dotProduct(const FloatArray &x) const
Definition floatarray.C:524
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void assembleSquared(const FloatArray &fe, const IntArray &loc)
Definition floatarray.C:637
void beScaled(double s, const FloatArray &b)
Definition floatarray.C:208
void beTProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:721
void subtract(const FloatArray &src)
Definition floatarray.C:320
void times(double f)
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
*Sets size of receiver to be an empty matrix It will have zero rows and zero columns size void clear()
int giveNumberOfColumns() const
Returns number of columns of receiver.
void plusDyadUnsym(const FloatArray &a, const FloatArray &b, double dV)
void beTranspositionOf(const FloatMatrix &src)
bool beInverseOf(const FloatMatrix &src)
double computeFrobeniusNorm() const
int giveNumberOfRows() const
Returns number of rows of receiver.
void assemble(const FloatMatrix &src, const IntArray &loc)
double at(std::size_t i, std::size_t j) const
bool solveForRhs(const FloatArray &b, FloatArray &answer, bool transpose=false)
void beTProductOf(const FloatMatrix &a, const FloatMatrix &b)
int set
Set number for boundary condition to be applied to.
IntArray dofs
Dofs that b.c. is applied to (relevant for Dirichlet type b.c.s).
virtual bool hasField(InputFieldType id)=0
Returns true if record contains field identified by idString keyword.
void resize(int n)
Definition intarray.C:73
bool contains(int value) const
Definition intarray.h:292
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
GaussPoint * getIntegrationPoint(int n)
const IntArray & giveBoundaryList()
Definition set.C:160
virtual int assemble(const IntArray &loc, const FloatMatrix &mat)=0
double giveTargetTime()
Returns target time.
Definition timestep.h:164
virtual void computeConstitutiveMatrixAt(FloatMatrix &answer, MatResponseMode rMode, GaussPoint *gp, TimeStep *tStep)
std ::vector< std ::vector< FloatArray > > eta
Scaling factor (one array per edge with one scaling factor per GP).
std ::unique_ptr< Node > mpFluxHom
DOF-manager containing the unknown homogenized stress.
void computeEta()
Help function computes phi by solving a diffusion problem on the RVE-surface.
void integrateTangent(FloatMatrix &oTangent, Element *e, int iBndIndex, int surfSet, int pos)
Help function that integrates the tangent contribution from a single element boundary.
#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
ClassFactory & classFactory
#define _IFT_TransportGradientNeumann_surfSets
#define _IFT_TransportGradientNeumann_centerCoords
#define _IFT_TransportGradientNeumann_gradient
#define _IFT_TransportGradientNeumann_dispControl

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