OOFEM 3.0
Loading...
Searching...
No Matches
transportgradientdirichlet.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 "dofmanager.h"
38#include "dof.h"
39#include "valuemodetype.h"
40#include "floatarray.h"
41#include "floatmatrix.h"
42#include "function.h"
43#include "engngm.h"
44#include "set.h"
45#include "node.h"
46#include "element.h"
47#include "classfactory.h"
48#include "dynamicinputrecord.h"
50#include "sparsemtrx.h"
51#include "sparselinsystemnm.h"
52#include "assemblercallback.h"
53#include "mathfem.h"
54#include "feinterpol.h"
55#include "feinterpol3d.h"
57#include "gausspoint.h"
58#include "sparselinsystemnm.h"
59
60#include "timer.h" // Benchmarking
61
62#include <tuple>
63#include <vector>
64#include <algorithm>
65#include <iterator>
66
67namespace oofem {
69
70
71void TransportGradientDirichlet :: initializeFrom(InputRecord &ir)
72{
73 GeneralBoundaryCondition :: initializeFrom(ir);
74
76
77 mCenterCoord.resize(3);
79
81 if ( this->tractionControl ) {
83 //IR_GIVE_FIELD(ir, edgeSets, _IFT_TransportGradientDirichlet_edgeSets);
84 }
85}
86
87
88void TransportGradientDirichlet :: giveInputRecord(DynamicInputRecord &input)
89{
93 //input.setField(edgeSets, _IFT_TransportGradientDirichlet_edgeSets);
94 if ( this->tractionControl ) {
96 }
97
98 return GeneralBoundaryCondition :: giveInputRecord(input);
99}
100
101
102void TransportGradientDirichlet :: postInitialize()
103{
104 BoundaryCondition :: postInitialize();
105
106 if ( this->tractionControl ) this->computeXi();
107}
108
109
110double TransportGradientDirichlet :: give(Dof *dof, ValueModeType mode, double time)
111{
112 const auto &coords = dof->giveDofManager()->giveCoordinates();
113
114 if ( coords.giveSize() != this->mCenterCoord.giveSize() ) {
115 OOFEM_ERROR("Size of coordinate system different from center coordinate in b.c.");
116 }
117
118 double factor = 0;
119 if ( mode == VM_Total ) {
120 factor = this->giveTimeFunction()->evaluateAtTime(time);
121 } else if ( mode == VM_Velocity ) {
122 factor = this->giveTimeFunction()->evaluateVelocityAtTime(time);
123 } else if ( mode == VM_Acceleration ) {
124 factor = this->giveTimeFunction()->evaluateAccelerationAtTime(time);
125 } else {
126 OOFEM_ERROR("Should not be called for value mode type then total, velocity, or acceleration.");
127 }
128
129 // Reminder: u_i = g_i . (x_i - xc_i + xi_i)
130 FloatArray dx = coords - this->mCenterCoord;
131 // Add "xi" if it is defined. Classical Dirichlet b.c. is retained if this isn't defined (or set to zero).
132 if ( !xis.empty() ) {
133 dx.add(xis[dof->giveDofManager()->giveNumber()]);
134 }
135
136 return mGradient.dotProduct(dx) * factor;
137}
138
139
140double TransportGradientDirichlet :: domainSize()
141{
142 Domain *domain = this->giveDomain();
143 int nsd = domain->giveNumberOfSpatialDimensions();
144 double domain_size = 0.0;
145 if ( this->tractionControl ) {
146 for ( auto &surf : this->surfSets ) {
147 const IntArray &boundaries = domain->giveSet(surf)->giveBoundaryList();
148
149 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
150 Element *e = domain->giveElement( boundaries.at(pos * 2 - 1) );
151 int boundary = boundaries.at(pos * 2);
153 domain_size += fei->evalNXIntegral( boundary, FEIElementGeometryWrapper(e) );
154 }
155 }
156 } else {
157 const IntArray &boundaries = domain->giveSet(this->set)->giveBoundaryList();
158
159 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
160 Element *e = domain->giveElement( boundaries.at(pos * 2 - 1) );
161 int boundary = boundaries.at(pos * 2);
163 domain_size += fei->evalNXIntegral( boundary, FEIElementGeometryWrapper(e) );
164 }
165 }
166 return fabs(domain_size / nsd);
167}
168
169
170void TransportGradientDirichlet :: computeCoefficientMatrix(FloatMatrix &C)
171// v_prescribed = C.g = (x-xbar + xi).g;
172// C = [x-xi_x y-xi_y]
173// C = [x-xi_x y-xi_y z-xi_z]
174{
175 Domain *domain = this->giveDomain();
176
177 int nsd = domain->giveNumberOfSpatialDimensions();
178 int npeq = domain->giveEngngModel()->giveNumberOfDomainEquations( domain->giveNumber(), EModelDefaultPrescribedEquationNumbering() );
179 C.resize(npeq, nsd);
180 C.zero();
181
182 for ( auto &n : domain->giveDofManagers() ) {
183 const auto &coords = n->giveCoordinates();
184 Dof *d1 = n->giveDofWithID( this->dofs[0] );
185 int k1 = d1->__givePrescribedEquationNumber();
186 if ( k1 ) {
187 // Add "xi" if it is defined. Classical Dirichlet b.c. is retained if this isn't defined (or set to zero).
188 FloatArray xi(nsd);
189 if ( this->tractionControl ) {
190 xi = xis[n->giveNumber()];
191 }
192 for ( int i = 1; i <= nsd; ++i ) {
193 C.at(k1, i) = coords.at(i) - mCenterCoord.at(i) + xi.at(i);
194 }
195 //printf("C.at(%d, :) = %e, %e, %e\n", k1, C.at(k1, 1), C.at(k1, 2), C.at(k1, 3));
196 }
197 }
198}
199
200
201void TransportGradientDirichlet :: computeField(FloatArray &sigma, TimeStep *tStep)
202{
203 EngngModel *emodel = this->domain->giveEngngModel();
205 FloatArray R_c(npeq), R_ext(npeq);
206
207 R_c.zero();
208 R_ext.zero();
209 emodel->assembleVector( R_c, tStep, InternalForceAssembler(), VM_Total,
211 emodel->assembleVector( R_ext, tStep, ExternalForceAssembler(), VM_Total,
213 R_c.subtract(R_ext);
214
215 // Condense it;
216 FloatMatrix C;
218 sigma.beTProductOf(C, R_c);
219 sigma.times( -1. / this->domainSize() );
220}
221
222
223void TransportGradientDirichlet :: computeTangent(FloatMatrix &tangent, TimeStep *tStep)
224// a = [a_c; a_f];
225// K.a = [R_c,0];
226// [K_cc, K_cf; K_fc, K_ff].[a_c;a_f] = [R_c; 0];
227// a_c = d.[x-x_b] = [x-x_b].d = C.d
228// E = C'.(K_cc - K_cf.K_ff^(-1).K_fc).C
229// = C'.(K_cc.C - K_cf.(K_ff^(-1).(K_fc.C)))
230// = C'.(K_cc.C - K_cf.a)
231// = C'.X
232{
233 // Fetch some information from the engineering model
234 EngngModel *rve = this->giveDomain()->giveEngngModel();
236 std :: unique_ptr< SparseLinearSystemNM >solver( classFactory.createSparseLinSolver( ST_Petsc, this->domain, this->domain->giveEngngModel() ) ); // = rve->giveLinearSolver();
237 SparseMtrxType stype = solver->giveRecommendedMatrix(true);
240
241 // Set up and assemble tangent FE-matrix which will make up the sensitivity analysis for the macroscopic material tangent.
242 std :: unique_ptr< SparseMtrx >Kff( classFactory.createSparseMtrx(stype) );
243 //std :: unique_ptr< SparseMtrx >Kfp( classFactory.createSparseMtrx(stype) );
244 std :: unique_ptr< SparseMtrx >Kpf( classFactory.createSparseMtrx(stype) );
245 std :: unique_ptr< SparseMtrx >Kpp( classFactory.createSparseMtrx(stype) );
246 if ( !Kff ) {
247 OOFEM_ERROR("Couldn't create sparse matrix of type %d\n", stype);
248 }
249 Kff->buildInternalStructure(rve, 1, fnum);
250 //Kfp->buildInternalStructure(rve, 1, fnum, pnum);
251 Kpf->buildInternalStructure(rve, 1, pnum, fnum);
252 Kpp->buildInternalStructure(rve, 1, pnum);
253
254 Timer t;
255 t.startTimer();
256#if 0
257 rve->assemble(*Kff, tStep, TangentAssembler(TangentStiffness), fnum, this->domain);
258 //rve->assemble(*Kfp, tStep, TangentAssembler(TangentStiffness), fnum, pnum, this->domain);
259 rve->assemble(*Kpf, tStep, TangentAssembler(TangentStiffness), pnum, fnum, this->domain);
260 rve->assemble(*Kpp, tStep, TangentAssembler(TangentStiffness), pnum, this->domain);
261#else
262 auto ma = TangentAssembler(TangentStiffness);
263 IntArray floc, ploc;
264 FloatMatrix mat, R;
265
266 int nelem = domain->giveNumberOfElements();
267#ifdef _OPENMP
268 #pragma omp parallel for shared(Kff, Kpf, Kpp) private(mat, R, floc, ploc)
269#endif
270 for ( int ielem = 1; ielem <= nelem; ielem++ ) {
271 Element *element = domain->giveElement(ielem);
272 // skip remote elements (these are used as mirrors of remote elements on other domains
273 // when nonlocal constitutive models are used. They introduction is necessary to
274 // allow local averaging on domains without fine grain communication between domains).
275 if ( element->giveParallelMode() == Element_remote || !element->isActivated(tStep) ) {
276 continue;
277 }
278
279 ma.matrixFromElement(mat, *element, tStep);
280
281 if ( mat.isNotEmpty() ) {
282 ma.locationFromElement(floc, *element, fnum);
283 ma.locationFromElement(ploc, *element, pnum);
285 if ( element->giveRotationMatrix(R) ) {
286 mat.rotatedWith(R);
287 }
288
289#ifdef _OPENMP
290 #pragma omp critical
291#endif
292 {
293 Kff->assemble(floc, mat);
294 Kpf->assemble(ploc, floc, mat);
295 Kpp->assemble(ploc, mat);
296 }
297 }
298 }
299 Kff->assembleBegin();
300 Kpf->assembleBegin();
301 Kpp->assembleBegin();
302
303 Kff->assembleEnd();
304 Kpf->assembleEnd();
305 Kpp->assembleEnd();
306#endif
307 t.stopTimer();
308 OOFEM_LOG_INFO("Assembly time %.3f s\n", t.getUtime());
309
310 FloatMatrix C, X, Kpfa, KfpC, sol;
311
313 Kpf->timesT(C, KfpC);
314
315 // Initial guess (Taylor assumption) helps KSP-iterations
316 sol.resize(KfpC.giveNumberOfRows(), KfpC.giveNumberOfColumns());
317 int nsd = domain->giveNumberOfSpatialDimensions();
318 for ( auto &n : domain->giveDofManagers() ) {
319 int k1 = n->giveDofWithID( this->dofs[0] )->__giveEquationNumber();
320 if ( k1 ) {
321 const auto &coords = n->giveCoordinates();
322 for ( int i = 1; i <= nsd; ++i ) {
323 sol.at(k1, i) = -(coords.at(i) - mCenterCoord.at(i));
324 }
325 }
326 }
327
328 t.startTimer();
329 if ( solver->solve(*Kff, KfpC, sol) != CR_CONVERGED ) {
330 OOFEM_ERROR("Failed to solve Kff");
331 }
332 t.stopTimer();
333 Kpp->times(C, X);
334 Kpf->times(sol, Kpfa);
335 X.subtract(Kpfa);
336 tangent.beTProductOf(C, X);
337 tangent.times( 1. / this->domainSize() );
338 OOFEM_LOG_INFO("Tangent problem solve time %.3f s\n", t.getUtime());
339}
340
341void TransportGradientDirichlet :: computeXi()
342{
343 TimeStep *tStep = domain->giveEngngModel()->giveCurrentStep();
344
345 std :: unique_ptr< SparseLinearSystemNM > solver( classFactory.createSparseLinSolver(ST_Petsc, this->giveDomain(), this->giveDomain()->giveEngngModel()) );
346
347 // One "xi" per node on the boundary. Initially all to zero.
348 this->xis.clear();
349 for ( int node : domain->giveSet(this->giveSetNumber())->giveNodeList() ) {
350 this->xis.emplace(node, FloatArray(3));
351 }
352 for ( auto &surf : this->surfSets ) {
353 for ( int node : domain->giveSet(surf)->giveNodeList() ) {
354 this->xis.emplace(node, FloatArray(3));
355 }
356 }
357
358 OOFEM_LOG_INFO("Computing edge sets from surfaces\n");
359 // Instead of requiring the input file to specify the edges, this code will automatically detect them
360 std :: vector< std :: vector< int > > surf2edges = {{1, 2, 3, 4},
361 {9, 10, 11, 12},
362 {1, 5, 6, 9},
363 {2, 6, 7, 10},
364 {3, 7, 8, 11},
365 {4, 5, 8, 12}};
366
367 // Edge sets generated from surface sets:
368 // 1-2, 1-3, 1-4, .. 2-3, 2-4, ..., 5-6 (skipping the empty sets)
369 // In case we ever want to use more arbitrary RVE "cutouts", this could be used.
370 std :: vector< Set > edgeSets;
371 std :: vector< std :: vector< std :: tuple< int, int > > > surfedges( this->surfSets.giveSize() );
372 for ( int i = 0; i < this->surfSets.giveSize(); ++i ) {
373 const IntArray &surfs = this->giveDomain()->giveSet(surfSets[i])->giveBoundaryList();
374 surfedges[i].reserve( 4 * surfs.giveSize() / 2 );
375 for ( int pos = 0; pos < surfs.giveSize() / 2; ++pos ) {
376 for ( int edgenum : surf2edges[surfs[pos * 2 + 1]-1] ) {
377 surfedges[i].emplace_back( std :: make_tuple(surfs[pos * 2], edgenum) );
378 }
379 }
380 }
381
382 for ( int i = 0; i < this->surfSets.giveSize() - 1; ++i ) {
383 for ( int j = i+1; j < this->surfSets.giveSize(); ++j ) {
384 std :: vector< std :: tuple< int, int > > ijEdgeSet;
385 std :: set_intersection(surfedges[i].begin(), surfedges[i].end(),
386 surfedges[j].begin(), surfedges[j].end(), std::back_inserter(ijEdgeSet));
387 IntArray edgelist;
388 edgelist.preallocate(ijEdgeSet.size() * 2);
389 for ( auto &edge : ijEdgeSet ) {
390 edgelist.followedBy( std :: get<0>(edge) );
391 edgelist.followedBy( std :: get<1>(edge) );
392 }
393
394 if ( edgelist.giveSize() > 0 ) {
395 Set s(0, this->giveDomain());
396 s.setEdgeList(edgelist);
397 edgeSets.emplace_back(std :: move(s));
398 }
399 }
400 }
401 // END OF EDGE-SET GENERATION
402
403 // Identify corner nodes and all the total edge nodes (needed for equation numbering)
404 IntArray totalCornerNodes;
405 IntArray totalEdgeNodes;
406 for ( auto &setPointer : edgeSets ) {
407 const IntArray &nodes = setPointer.giveNodeList();
408 for ( int n : nodes ) {
409 if ( !totalEdgeNodes.insertSortedOnce(n, 10) ) {
410 totalCornerNodes.insertSortedOnce(n);
411 }
412 }
413 }
414
415#if 1
416 //IntArray edgeOrder{2, 1, 2, 1, 3, 3, 3, 3, 2, 1, 2, 1};
417 // First we must determine the values along the edges, which become boundary conditions for the surfaces
418 OOFEM_LOG_INFO("Computing xi on edges\n");
419 for ( auto &setPointer : edgeSets ) {
420 const IntArray &edges = setPointer.giveEdgeList();
421
422 // Number the equations along this edge set
423 std :: map< int, int > eqs;
424 int eq_count = 0;
425 for ( int n : setPointer.giveNodeList() ) {
426 if ( totalCornerNodes.containsSorted(n) ) {
427 eqs[n] = 0;
428 } else {
429 eqs[n] = ++eq_count;
430 }
431 }
432
433 FloatMatrix f;
434 FloatArray q;
436 std :: unique_ptr< SparseMtrx > K( classFactory.createSparseMtrx(solver->giveRecommendedMatrix(true)) );
437 K->buildInternalStructure(domain->giveEngngModel(), eq_count, eq_count, {}, {});
438 f.resize(eq_count, 3);
439
440 K->assembleBegin();
441 for ( int pos = 0; pos < edges.giveSize() / 2; ++pos ) {
442 Element *e = this->giveDomain()->giveElement( edges[pos * 2] );
443 int edge = edges[pos * 2 + 1];
444
445 FloatMatrix D, Ke, fe;
446 FloatArray b;
447
448 FEInterpolation3d *interp = static_cast< FEInterpolation3d* >( e->giveInterpolation() );
449 const auto &bNodes = interp->boundaryEdgeGiveNodes(edge, e->giveGeometryType());
450 int order = interp->giveInterpolationOrder();
451 std :: unique_ptr< IntegrationRule > ir( interp->giveBoundaryEdgeIntegrationRule(order, edge, e->giveGeometryType()) );
452 static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(D, Capacity, e->giveDefaultIntegrationRulePtr()->getIntegrationPoint(1), tStep);
453
454 // Compute integral of B'*D*B and N:
455 for ( auto &gp: *ir ) {
456 const FloatArray &lcoords = gp->giveNaturalCoordinates();
457 FEIElementGeometryWrapper cellgeo(e);
458
459 double detJ = interp->boundaryEdgeGiveTransformationJacobian(edge, lcoords, cellgeo);
460 interp->edgeEvaldNdxi(b, edge, lcoords, cellgeo);
461 b.times(1. / detJ);
462 double dL = detJ * gp->giveWeight();
463
464 // Compute material property
466 //static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(D, Capacity, gp, tStep);
467#if 1
468 FloatArray t;
469 for ( int i = 1; i <= b.giveSize(); ++i ) {
470 t.add(b.at(i), e->giveNode(bNodes.at(i))->giveCoordinates());
471 }
472 t.normalize();
473 FloatArray tmp;
474 tmp.beProductOf(D, t);
475 double k = tmp.dotProduct(t);
476#else
477 double k = D.at(1,1);
478#endif
479
480 Ke.plusDyadSymmUpper(b, k * dL);
481 }
482 Ke.symmetrized();
483
484 // Need the element-nodal coordinates for the RHS, as the associated location array:
485 IntArray loc(bNodes.giveSize());
486 FloatMatrix cvec(bNodes.giveSize(), 3);
487 for ( int i = 1; i <= bNodes.giveSize(); ++i ) {
488 int enode = bNodes.at(i);
489 Node *n = e->giveNode(enode);
490 const auto &x = n->giveCoordinates();
491 cvec.at(i, 1) = x.at(1);
492 cvec.at(i, 2) = x.at(2);
493 cvec.at(i, 3) = x.at(3);
494 loc.at(i) = eqs[n->giveNumber()];
495 }
496
497 fe.beProductOf(Ke, cvec);
498 fe.negated();
499 f.assemble(fe, loc, {1, 2, 3});
500 K->assemble(loc, Ke);
501 }
502 K->assembleEnd();
503
504 FloatMatrix x;
505 solver->solve(*K, f, x);
506
507 for ( int n : setPointer.giveNodeList() ) {
508 int eq = eqs[n];
509 if ( eq > 0 ) {
510 this->xis[n] = {x.at(eq, 1), x.at(eq, 2), x.at(eq, 3)};
511 }
512 }
513 }
514#endif
515
516 OOFEM_LOG_INFO("Computing xi on surface sets\n");
517#if 1
518 // Surfaces use the edge solutions are boundary conditions:
519 for ( auto &setNum : surfSets ) {
520 Set *setPointer = this->giveDomain()->giveSet(setNum);
521 const IntArray &surfs = setPointer->giveBoundaryList();
522
523 // Number the equations along this surface set
524 std :: map< int, int > eqs;
525 int eq_count = 0;
526 for ( int n : setPointer->giveNodeList() ) {
527 if ( totalEdgeNodes.containsSorted(n) ) {
528 eqs[n] = 0;
529 } else {
530 eqs[n] = ++eq_count;
531 }
532 }
533
534 FloatMatrix f;
536 FloatArray q;
537 std :: unique_ptr< SparseMtrx > K( classFactory.createSparseMtrx(solver->giveRecommendedMatrix(true)) );
538 K->buildInternalStructure(domain->giveEngngModel(), eq_count, eq_count, {}, {});
539 f.resize(eq_count, 3);
540 q.resize(eq_count);
541
542 K->assembleBegin();
544 for ( int pos = 0; pos < surfs.giveSize() / 2; ++pos ) {
545 Element *e = this->giveDomain()->giveElement( surfs[pos * 2] );
546 int surf = surfs[pos * 2 + 1];
547
548 FloatMatrix D, B, dNdx, DB, Ke, fe;
549 FloatArray n, qe, normal;
550
551 FEInterpolation3d *interp = static_cast< FEInterpolation3d* >( e->giveInterpolation() );
552 int order = interp->giveInterpolationOrder();
553 std :: unique_ptr< IntegrationRule > ir( interp->giveBoundaryIntegrationRule(order, surf, e->giveGeometryType()) );
554 static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(D, Capacity, e->giveDefaultIntegrationRulePtr()->getIntegrationPoint(1), tStep);
555
556 for ( auto &gp: *ir ) {
557 const FloatArray &lcoords = gp->giveNaturalCoordinates();
558 FEIElementGeometryWrapper cellgeo(e);
559
560 interp->boundaryEvalN(n, surf, lcoords, cellgeo);
561
562 double detJ = interp->boundaryEvalNormal(normal, surf, lcoords, cellgeo);
563 interp->surfaceEvaldNdx(dNdx, surf, lcoords, cellgeo);
564 B.beTranspositionOf(dNdx);
565 double dA = detJ * gp->giveWeight();
566
567 for (int i = 1; i <= B.giveNumberOfRows(); ++i ) {
568 for (int j = 1; j <= B.giveNumberOfColumns(); ++j ) {
569 double tmp = 0;
570 for (int k = 1; k <= 3; ++k ) {
571 tmp += normal.at(k) * B.at(k,j);
572 }
573 B.at(i,j) -= normal.at(i) * tmp;
574 }
575 }
576
577 // Compute material property
579 //static_cast< TransportElement* >(e)->computeConstitutiveMatrixAt(D, Capacity, gp, tStep);
580
581 // Vector:
582 DB.beProductOf(D, B);
583 Ke.plusProductSymmUpper(B, DB, dA);
584 qe.add(dA, n);
585 }
586 Ke.symmetrized();
587
588 const auto &bNodes = interp->boundaryGiveNodes(surf, e->giveGeometryType());
589 IntArray loc(bNodes.giveSize());
590 FloatMatrix cvec(bNodes.giveSize(), 3);
591 for ( int i = 1; i <= bNodes.giveSize(); ++i ) {
592 int enode = bNodes.at(i);
593 Node *n = e->giveNode(enode);
594 FloatArray x = n->giveCoordinates() + this->xis[n->giveNumber()];
595 cvec.at(i, 1) = x.at(1);
596 cvec.at(i, 2) = x.at(2);
597 cvec.at(i, 3) = x.at(3);
598 loc.at(i) = eqs[n->giveNumber()];
599 }
600 fe.beProductOf(Ke, cvec);
601 fe.negated();
602
603 K->assemble(loc, Ke);
604 f.assemble(fe, loc, {1, 2, 3});
605 q.assemble(qe, loc);
606 }
607 K->assembleEnd();
608
609 // Solve with constraints:
610 // [K Q] [xi ] = [f]
611 // [Q^T 0] [lambda ] [0]
612 // ==>
613 // [Q^T . K^(-1) . Q] . lamda = Q^T . K^(-1) . f
614 // xi = K^(-1) . f - K^(-1) . Q . lambda
615 // alternatively:
616 // [Q^T . Qx] . lamda = Q^T . fx
617 // xi = fx - Qx . lambda
618
619 double qTKiq;
620 FloatMatrix x;
621 FloatArray qx, lambda, tmp, qTKif;
622 solver->solve(*K, q, qx);
623 solver->solve(*K, f, x);
624
625 qTKif.beTProductOf(x, q);
626 qTKiq = q.dotProduct(qx);
627 lambda.beScaled(1./qTKiq, qTKif);
628 x.plusDyadUnsym(qx, lambda, -1.0);
629
630 for ( int n : setPointer->giveNodeList() ) {
631 int eq = eqs[n];
632 if ( eq > 0 ) {
633 this->xis[n] = {x.at(eq, 1), x.at(eq, 2), x.at(eq, 3)};
634 }
635 }
636
637 }
638#endif
639}
640
641} // end namespace oofem
#define REGISTER_BoundaryCondition(class)
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
DofManager * giveDofManager() const
Definition dof.h:123
virtual int __givePrescribedEquationNumber()=0
void setField(int item, InputFieldType id)
Node * giveNode(int i) const
Definition element.h:629
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 IntegrationRule * giveDefaultIntegrationRulePtr()
Definition element.h:886
virtual Element_Geometry_Type giveGeometryType() const =0
virtual int giveNumberOfDomainEquations(int di, const UnknownNumberingScheme &num)
Definition engngm.C:452
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
IntArray boundaryEdgeGiveNodes(int boundary, const Element_Geometry_Type, bool includeHierarchical=false) const override
std::unique_ptr< IntegrationRule > giveBoundaryIntegrationRule(int _order, int boundary, const Element_Geometry_Type) const override
double boundaryEvalNormal(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
virtual void surfaceEvaldNdx(FloatMatrix &answer, int isurf, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
double boundaryEdgeGiveTransformationJacobian(int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
void boundaryEvalN(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
IntArray boundaryGiveNodes(int boundary, const Element_Geometry_Type) const override
std::unique_ptr< IntegrationRule > giveBoundaryEdgeIntegrationRule(int order, int boundary, const Element_Geometry_Type) const override
virtual void edgeEvaldNdxi(FloatArray &answer, int iedge, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
virtual double evalNXIntegral(int boundary, const FEICellGeometry &cellgeo) const
Definition feinterpol.h:477
int giveInterpolationOrder() const
Definition feinterpol.h:199
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 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
double dotProduct(const FloatArray &x) const
Definition floatarray.C:524
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 beScaled(double s, const FloatArray &b)
Definition floatarray.C:208
void beTProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:721
void add(const FloatArray &src)
Definition floatarray.C:218
void times(double s)
Definition floatarray.C:834
void times(double f)
void rotatedWith(const FloatMatrix &r, char mode='n')
void plusProductSymmUpper(const FloatMatrix &a, const FloatMatrix &b, double dV)
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
int giveNumberOfColumns() const
Returns number of columns of receiver.
void beProductOf(const FloatMatrix &a, const FloatMatrix &b)
void plusDyadUnsym(const FloatArray &a, const FloatArray &b, double dV)
void beTranspositionOf(const FloatMatrix &src)
void zero()
Zeroes all coefficient of receiver.
bool isNotEmpty() const
Tests for empty matrix.
void plusDyadSymmUpper(const FloatArray &a, double dV)
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
void subtract(const FloatMatrix &a)
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.
bool insertSortedOnce(int value, int allocChunk=0)
Definition intarray.C:309
void followedBy(const IntArray &b, int allocChunk=0)
Definition intarray.C:94
bool containsSorted(int value) const
Definition intarray.h:247
void preallocate(int futureSize)
Definition intarray.C:79
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
GaussPoint * getIntegrationPoint(int n)
void setEdgeList(IntArray newEdges)
Definition set.C:235
const IntArray & giveBoundaryList()
Definition set.C:160
const IntArray & giveNodeList()
Definition set.C:168
double getUtime()
Returns total user time elapsed in seconds.
Definition timer.C:105
void startTimer()
Definition timer.C:69
void stopTimer()
Definition timer.C:77
std ::map< int, FloatArray > xis
Stores one "psi" value for each node.
void computeXi()
Computes the offset values for "improved" Dirichlet. See class description.
#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
@ Element_remote
Element in active domain is only mirror of some remote element.
Definition element.h:89
ClassFactory & classFactory
#define _IFT_TransportGradientDirichlet_gradient
#define _IFT_TransportGradientDirichlet_centerCoords
#define _IFT_TransportGradientDirichlet_surfSets
#define _IFT_TransportGradientDirichlet_tractionControl

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