OOFEM 3.0
Loading...
Searching...
No Matches
transportgradientperiodic.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 "dofiditem.h"
37#include "node.h"
38#include "dofmanager.h"
39#include "dof.h"
40#include "valuemodetype.h"
41#include "floatarray.h"
42#include "floatmatrix.h"
43#include "engngm.h"
44#include "node.h"
45#include "activedof.h"
46#include "masterdof.h"
47#include "classfactory.h"
48#include "sparsemtrxtype.h"
49#include "sparsemtrx.h"
50#include "sparselinsystemnm.h"
51#include "dynamicinputrecord.h"
52#include "domain.h"
53#include "spatiallocalizer.h"
54#include "feinterpol.h"
56#include "function.h"
57#include "timestep.h"
58#include "mathfem.h"
59
60namespace oofem {
62
63TransportGradientPeriodic :: TransportGradientPeriodic(int n, Domain *d) : ActiveBoundaryCondition(n, d), //PrescribedGradientHomogenization(),
64 grad( new Node(1, d) )
65{
66 int nsd = d->giveNumberOfSpatialDimensions();
67 // The prescribed strains.
68 for ( int i = 0; i < nsd; i++ ) {
69 int dofid = d->giveNextFreeDofID();
70 grad_ids.followedBy(dofid);
71 // Just putting in X_i id-items since they don't matter.
72 // These don't actually need to be active, they are masterdofs with prescribed values, its
73 // easier to just have them here rather than trying to make another Dirichlet boundary condition.
74 grad->appendDof( new ActiveDof( grad.get(), (DofIDItem)dofid, this->giveNumber() ) );
75 //grad->appendDof( new MasterDof(grad.get(), this->giveNumber(), 0, (DofIDItem)dofid ) );
76 }
77}
78
79
80int TransportGradientPeriodic :: giveNumberOfInternalDofManagers()
81{
82 return 1;
83}
84
85
86DofManager *TransportGradientPeriodic :: giveInternalDofManager(int i)
87{
88 return this->grad.get();
89}
90
91
92void TransportGradientPeriodic :: findSlaveToMasterMap()
93{
94 FloatArray coord;
95 SpatialLocalizer *sl = this->domain->giveSpatialLocalizer();
96 //Set *masterSet = this->domain->giveSet(2);
97 const IntArray &nodes = this->domain->giveSet(this->set)->giveNodeList(); // Split into slave set and master set?
98 int nsd = jump.giveSize();
99 std :: vector< FloatArray > jumps;
100 // Construct all the possible jumps;
101 jumps.reserve((2 << (nsd-1)) - 1);
102 if ( nsd != 3 ) {
103 OOFEM_ERROR("Only 3d implemented yet!");
104 }
105 jumps.emplace_back(jump);
106 jumps.emplace_back(FloatArray{jump.at(1), jump.at(2), 0.});
107 jumps.emplace_back(FloatArray{jump.at(1), 0., jump.at(3)});
108 jumps.emplace_back(FloatArray{0., jump.at(2), jump.at(3)});
109 jumps.emplace_back(FloatArray{jump.at(1), 0., 0.});
110 jumps.emplace_back(FloatArray{0., jump.at(2), 0.});
111 jumps.emplace_back(FloatArray{0., 0., jump.at(3)});
112
113 double maxdist = jump.computeNorm()*1e-5;
114
115 this->slavemap.clear();
116 for ( int inode : nodes ) {
117 Node *masterNode = nullptr;
118 Node *node = this->domain->giveNode(inode);
119 const auto &masterCoord = node->giveCoordinates();
120 //printf("node %d\n", node->giveLabel()); masterCoord.printYourself();
121 // The difficult part, what offset to subtract to find the master side;
122 for ( FloatArray &testJump : jumps ) {
123 coord.beDifferenceOf(masterCoord, testJump);
124 masterNode = sl->giveNodeClosestToPoint(coord, maxdist);
125 if ( masterNode ) {
126 //printf("Found master (%d) to node %d (distance = %e)\n", masterNode->giveNumber(), node->giveNumber(),
127 // distance(*masterNode->giveCoordinates(), coord));
128 break;
129 }
130 }
131 if ( masterNode ) {
132 this->slavemap.insert({node->giveNumber(), masterNode->giveNumber()});
133 } else {
134 OOFEM_ERROR("Couldn't find master node!");
135 }
136 }
137}
138
139
140double TransportGradientPeriodic :: domainSize(Domain *d, int setNum)
141{
142 int nsd = d->giveNumberOfSpatialDimensions();
143 double domain_size = 0.0;
144 // This requires the boundary to be consistent and ordered correctly.
145 Set *set = d->giveSet(setNum);
146 const IntArray &boundaries = set->giveBoundaryList();
147
148 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
149 Element *e = d->giveElement( boundaries.at(pos * 2 - 1) );
150 int boundary = boundaries.at(pos * 2);
152 domain_size += fei->evalNXIntegral( boundary, FEIElementGeometryWrapper(e) );
153 }
154 return fabs(domain_size / nsd);
155}
156
157
158int TransportGradientPeriodic :: giveNumberOfMasterDofs(ActiveDof *dof)
159{
160 if ( this->isGradDof(dof) ) {
161 return 1;
162 }
163 return this->giveDomain()->giveNumberOfSpatialDimensions() + 1;
164}
165
166
167Dof *TransportGradientPeriodic :: giveMasterDof(ActiveDof *dof, int mdof)
168{
169 if ( this->isGradDof(dof) ) {
170 return nullptr;
171 }
172 if ( mdof == 1 ) {
173 int node = this->slavemap[dof->giveDofManager()->giveNumber()];
174 return this->domain->giveDofManager(node)->giveDofWithID(dof->giveDofID());
175 } else {
176 return this->grad->giveDofWithID(this->grad_ids[mdof-2]);
177 }
178}
179
180
181void TransportGradientPeriodic :: computeField(FloatArray &flux, TimeStep *tStep)
182{
184 EngngModel *emodel = this->giveDomain()->giveEngngModel();
185 FloatArray tmp;
186 int npeq = grad_ids.giveSize();
187 // sigma = residual (since we use the slave dofs) = f_ext - f_int
188 flux.resize(npeq);
189 flux.zero();
190 emodel->assembleVector(flux, tStep, InternalForceAssembler(), VM_Total, pnum, this->domain);
191 tmp.resize(npeq);
192 tmp.zero();
193 emodel->assembleVector(tmp, tStep, ExternalForceAssembler(), VM_Total, pnum, this->domain);
194 flux.subtract(tmp);
195 // Divide by the RVE-volume
196 flux.times(1.0 / ( this->domainSize(this->giveDomain(), this->set) + this->domainSize(this->giveDomain(), this->masterSet) ));
197}
198
199
200void TransportGradientPeriodic :: computeTangent(FloatMatrix &k, TimeStep *tStep)
201{
203 //DofIDEquationNumbering pnum(true, this->grad_ids);
205 int nsd = this->domain->giveNumberOfSpatialDimensions();
206
207 EngngModel *rve = this->giveDomain()->giveEngngModel();
209 std :: unique_ptr< SparseLinearSystemNM > solver( classFactory.createSparseLinSolver( ST_Petsc, this->domain, this->domain->giveEngngModel() ) ); // = rve->giveLinearSolver();
210 SparseMtrxType stype = solver->giveRecommendedMatrix(true);
211 std :: unique_ptr< SparseMtrx > Kff( classFactory.createSparseMtrx( stype ) );
212 std :: unique_ptr< SparseMtrx > Kfp( classFactory.createSparseMtrx( stype ) );
213 std :: unique_ptr< SparseMtrx > Kpp( classFactory.createSparseMtrx( stype ) );
214
215 Kff->buildInternalStructure(rve, this->domain->giveNumber(), fnum);
216 int neq = Kff->giveNumberOfRows();
217 Kfp->buildInternalStructure(rve, this->domain->giveNumber(), fnum, pnum);
218 Kpp->buildInternalStructure(rve, this->domain->giveNumber(), pnum);
219 //Kfp->buildInternalStructure(rve, neq, nsd, {}, {});
220 //Kpp->buildInternalStructure(rve, nsd, nsd, {}, {});
221#if 1
222 rve->assemble(*Kff, tStep, TangentAssembler(TangentStiffness), fnum, this->domain);
223 rve->assemble(*Kfp, tStep, TangentAssembler(TangentStiffness), fnum, pnum, this->domain);
224 rve->assemble(*Kpp, tStep, TangentAssembler(TangentStiffness), pnum, this->domain);
225#else
226 auto ma = TangentAssembler(TangentStiffness);
227 IntArray floc, ploc;
228 FloatMatrix mat, R;
229
230 int nelem = domain->giveNumberOfElements();
231#ifdef _OPENMP
232 #pragma omp parallel for shared(Kff, Kfp, Kpp) private(mat, R, floc, ploc)
233#endif
234 for ( int ielem = 1; ielem <= nelem; ielem++ ) {
235 Element *element = domain->giveElement(ielem);
236 // skip remote elements (these are used as mirrors of remote elements on other domains
237 // when nonlocal constitutive models are used. They introduction is necessary to
238 // allow local averaging on domains without fine grain communication between domains).
239 if ( element->giveParallelMode() == Element_remote || !element->isActivated(tStep) ) {
240 continue;
241 }
242
243 ma.matrixFromElement(mat, *element, tStep);
244
245 if ( mat.isNotEmpty() ) {
246 ma.locationFromElement(floc, *element, fnum);
247 ma.locationFromElement(ploc, *element, pnum);
249 if ( element->giveRotationMatrix(R) ) {
250 mat.rotatedWith(R);
251 }
252
253#ifdef _OPENMP
254 #pragma omp critical
255#endif
256 {
257 Kff->assemble(floc, mat);
258 Kfp->assemble(floc, ploc, mat);
259 Kpp->assemble(ploc, mat);
260 }
261 }
262 }
263 Kff->assembleBegin();
264 Kfp->assembleBegin();
265 Kpp->assembleBegin();
266
267 Kff->assembleEnd();
268 Kfp->assembleEnd();
269 Kpp->assembleEnd();
270#endif
271
272 FloatMatrix grad_pert(nsd, nsd), rhs, sol(neq, nsd);
273 grad_pert.resize(nsd, nsd);
274 grad_pert.beUnitMatrix();
275 // Workaround since the matrix size is inflexible with custom dof numbering (so far, planned to be fixed).
276 IntArray grad_loc;
277 this->grad->giveLocationArray(this->grad_ids, grad_loc, pnum);
278 FloatMatrix pert(Kpp->giveNumberOfRows(), nsd);
279 pert.assemble(grad_pert, grad_loc, {1,2,3});
280 //pert.printYourself("pert");
281
282 //printf("Kfp = %d x %d\n", Kfp->giveNumberOfRows(), Kfp->giveNumberOfColumns());
283 //printf("Kff = %d x %d\n", Kff->giveNumberOfRows(), Kff->giveNumberOfColumns());
284 //printf("Kpp = %d x %d\n", Kpp->giveNumberOfRows(), Kpp->giveNumberOfColumns());
285
286 // Compute the solution to each of the pertubation of eps
287 Kfp->times(pert, rhs);
288 //rhs.printYourself("rhs");
289
290 // Initial guess (Taylor assumption) helps KSP-iterations
291 for ( auto &n : domain->giveDofManagers() ) {
292 int k1 = n->giveDofWithID( this->dofs[0] )->__giveEquationNumber();
293 if ( k1 ) {
294 const auto &coords = n->giveCoordinates();
295 for ( int i = 1; i <= nsd; ++i ) {
296 sol.at(k1, i) = -(coords.at(i) - mCenterCoord.at(i));
297 }
298 }
299 }
300
301 if ( solver->solve(*Kff, rhs, sol) != CR_CONVERGED ) {
302 OOFEM_ERROR("Failed to solve Kff");
303 }
304 // Compute the solution to each of the pertubation of eps
305 Kfp->timesT(sol, k); // Assuming symmetry of stiffness matrix
306 // This is probably always zero, but for generality
307 FloatMatrix tmpMat;
308 Kpp->times(pert, tmpMat);
309 k.subtract(tmpMat);
310 k.times( - 1.0 / ( this->domainSize(this->giveDomain(), this->set) + this->domainSize(this->giveDomain(), this->masterSet) ));
311
312 // Temp workaround on sizing issue mentioned above:
313 FloatMatrix k2 = k;
314 k.beSubMatrixOf(k2, grad_loc, {1,2,3});
315}
316
317
318void TransportGradientPeriodic :: computeDofTransformation(ActiveDof *dof, FloatArray &masterContribs)
319{
320 DofManager *master = this->domain->giveDofManager(this->slavemap[dof->giveDofManager()->giveNumber()]);
321 const auto &coords = dof->giveDofManager()->giveCoordinates();
322 const auto &masterCoords = master->giveCoordinates();
323
324 FloatArray dx = coords - masterCoords;
325
326 masterContribs.resize(dx.giveSize() + 1);
327
328 masterContribs.at(1) = 1.; // Master dof is always weight 1.0
329 for ( int i = 1; i <= dx.giveSize(); ++i ) {
330 masterContribs.at(i+1) = dx.at(i);
331 }
332}
333
334
335double TransportGradientPeriodic :: giveUnknown(double val, ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
336{
337 DofManager *master = this->domain->giveDofManager(this->slavemap[dof->giveDofManager()->giveNumber()]);
338 FloatArray dx, g;
340 this->grad->giveUnknownVector(g, this->grad_ids, mode, tStep);
341 return val + g.dotProduct(dx);
342}
343
344
345double TransportGradientPeriodic :: giveUnknown(PrimaryField &field, ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
346{
347 if ( this->isGradDof(dof) ) {
348 int ind = grad_ids.findFirstIndexOf(dof->giveDofID()) - 1;
349 return this->mGradient(ind) * this->giveTimeFunction()->evaluateAtTime(tStep->giveTargetTime());
350 }
351
352 DofManager *master = this->domain->giveDofManager(this->slavemap[dof->giveDofManager()->giveNumber()]);
353 double val = master->giveDofWithID(dof->giveDofID())->giveUnknown(field, mode, tStep);
354 return this->giveUnknown(val, mode, tStep, dof);
355}
356
357
358double TransportGradientPeriodic :: giveUnknown(ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
359{
360 if ( this->isGradDof(dof) ) {
361 int ind = grad_ids.findFirstIndexOf(dof->giveDofID()) - 1;
362 return this->mGradient(ind) * this->giveTimeFunction()->evaluateAtTime(tStep->giveTargetTime());
363 }
364
365 DofManager *master = this->domain->giveDofManager(this->slavemap[dof->giveDofManager()->giveNumber()]);
366
367 if ( mode == VM_Incremental ) {
368 double val = master->giveDofWithID(dof->giveDofID())->giveUnknown(mode, tStep);
369 return this->giveUnknown(val, mode, tStep, dof);
370 }
371 double val = master->giveDofWithID(dof->giveDofID())->giveUnknown(mode, tStep);
372 return this->giveUnknown(val, mode, tStep, dof);
373}
374
375
376bool TransportGradientPeriodic :: isPrimaryDof(ActiveDof *dof)
377{
378 return this->isGradDof(dof);
379}
380
381
382double TransportGradientPeriodic :: giveBcValue(Dof *dof, ValueModeType mode, TimeStep *tStep)
383{
384 int index = grad_ids.findFirstIndexOf(dof->giveDofID()) - 1;
385 return this->mGradient(index) * this->giveTimeFunction()->evaluateAtTime(tStep->giveTargetTime());
386}
387
388
389bool TransportGradientPeriodic :: hasBc(Dof *dof, TimeStep *tStep)
390{
391 return this->isGradDof(dof);
392}
393
394
395bool TransportGradientPeriodic :: isGradDof(Dof *dof)
396{
397 return this->grad.get() == dof->giveDofManager();
398}
399
400
401void TransportGradientPeriodic :: initializeFrom(InputRecord &ir)
402{
403 ActiveBoundaryCondition :: initializeFrom(ir);
404 //PrescribedGradientHomogenization::initializeFrom(ir);
405
407 this->mCenterCoord = {0., 0., 0.};
409
412}
413
414
415void TransportGradientPeriodic :: giveInputRecord(DynamicInputRecord &input)
416{
417 ActiveBoundaryCondition :: giveInputRecord(input);
418 //PrescribedGradientHomogenization :: giveInputRecord(input);
421
424}
425
426
427void TransportGradientPeriodic :: postInitialize()
428{
429 this->findSlaveToMasterMap();
430}
431} // end namespace oofem
#define REGISTER_BoundaryCondition(class)
ActiveBoundaryCondition(int n, Domain *d)
Definition activebc.h:71
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 giveUnknown(ValueModeType mode, TimeStep *tStep)=0
DofManager * giveDofManager() const
Definition dof.h:123
Set * giveSet(int n)
Definition domain.C:366
int giveNextFreeDofID(int increment=1)
Definition domain.C:1519
Element * giveElement(int n)
Definition domain.C:165
int giveNumberOfSpatialDimensions()
Returns number of spatial dimensions.
Definition domain.C:1137
void setField(int item, InputFieldType id)
virtual bool giveRotationMatrix(FloatMatrix &answer)
Definition element.C:298
virtual bool isActivated(TimeStep *tStep)
Definition element.C:838
virtual FEInterpolation * giveInterpolation() const
Definition element.h:648
elementParallelMode giveParallelMode() const
Definition element.h:1139
virtual void assemble(SparseMtrx &answer, TimeStep *tStep, const MatrixAssembler &ma, const UnknownNumberingScheme &s, Domain *domain)
Definition engngm.C:889
void assembleVector(FloatArray &answer, TimeStep *tStep, const VectorAssembler &va, ValueModeType mode, const UnknownNumberingScheme &s, Domain *domain, FloatArray *eNorms=NULL)
Definition engngm.C:1106
virtual double evalNXIntegral(int boundary, const FEICellGeometry &cellgeo) const
Definition feinterpol.h:477
Domain * giveDomain() const
Definition femcmpnn.h:97
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 dotProduct(const FloatArray &x) const
Definition floatarray.C:524
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void subtract(const FloatArray &src)
Definition floatarray.C:320
void times(double s)
Definition floatarray.C:834
void times(double f)
void rotatedWith(const FloatMatrix &r, char mode='n')
void beSubMatrixOf(const FloatMatrix &src, Index topRow, Index bottomRow, Index topCol, Index bottomCol)
bool isNotEmpty() const
Tests for empty matrix.
void assemble(const FloatMatrix &src, const IntArray &loc)
double at(std::size_t i, std::size_t j) const
void subtract(const FloatMatrix &a)
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).
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
virtual Node * giveNodeClosestToPoint(const FloatArray &coords, double maxDist)=0
double giveTargetTime()
Returns target time.
Definition timestep.h:164
virtual double domainSize(Domain *d, int setNum)
double giveUnknown(double val, ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
#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
@ Element_remote
Element in active domain is only mirror of some remote element.
Definition element.h:89
ClassFactory & classFactory
#define _IFT_TransportGradientPeriodic_masterSet
#define _IFT_TransportGradientPeriodic_centerCoords
#define _IFT_TransportGradientPeriodic_gradient
#define _IFT_TransportGradientPeriodic_jump

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