OOFEM 3.0
Loading...
Searching...
No Matches
weakperiodicbc.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#include <cstdio>
36#include <cstdlib>
37#include <algorithm>
38#include <memory>
39
40#include "activebc.h"
41#include "weakperiodicbc.h"
42#include "inputrecord.h"
43#include "element.h"
44#include "node.h"
45#include "masterdof.h"
46#include "sparsemtrx.h"
47#include "gausspoint.h"
48#include "integrationrule.h"
49#include "mathfem.h"
50#include "fei2dtrlin.h"
51#include "fei2dtrquad.h"
52#include "classfactory.h"
53#include "set.h"
54#include "function.h"
55
56#ifdef _OPENMP
57#include <omp.h>
58#endif
59
60#include "timestep.h"
61// #include "sm/Elements/tet21ghostsolid.h"
63
64namespace oofem {
66
67WeakPeriodicBoundaryCondition :: WeakPeriodicBoundaryCondition(int n, Domain *d) : ActiveBoundaryCondition(n, d), gammaDman( new Node(0, this->domain) )
68{
70 doUpdateSminmax = true;
71}
72
73WeakPeriodicBoundaryCondition :: ~WeakPeriodicBoundaryCondition()
74{
75}
76
77void
78WeakPeriodicBoundaryCondition :: initializeFrom(InputRecord &ir)
79{
80 ActiveBoundaryCondition :: initializeFrom(ir);
81
84
85 int t = ( int ) monomial;
87 useBasisType = ( basisType ) t; // Fourierseries by default
88
89 //dofids = P_f; // Pressure as default
91 ndofids = dofids.giveSize();
92
93 ngp = -1; // ngp is deprecated
94
95 nlgeo = false;
97
99
100 IntArray temp;
101
102 posSet = -1;
103 negSet = -1;
104
107
108 if ( posSet == -1 ) {
110 for ( int i = 0; i < temp.giveSize() / 2; i++ ) {
111 side [ 0 ].push_back( temp.at(2 * i + 1) );
112 element [ 0 ].push_back( temp.at(2 * i + 2) );
113 }
114 }
115
116 if ( negSet == -1 ) {
118 for ( int i = 0; i < temp.giveSize() / 2; i++ ) {
119 side [ 1 ].push_back( temp.at(2 * i + 1) );
120 element [ 1 ].push_back( temp.at(2 * i + 2) );
121 }
122 }
123
124}
125
126void WeakPeriodicBoundaryCondition :: postInitialize()
127{
128 ActiveBoundaryCondition :: postInitialize();
129 if (g.isEmpty()) {
130 g.resize(this->domain->giveNumberOfSpatialDimensions());
131 g.zero();
132 }
133
134 if ( this->domain->giveNumberOfSpatialDimensions() == 2 ) {
135 ndof = (orderOfPolygon + 1) * dofids.giveSize();
136 tcount = (orderOfPolygon + 1);
137 } else if ( this->domain->giveNumberOfSpatialDimensions() == 3 ) {
138 ndof = 1;
139 for ( int i = 1; i <= orderOfPolygon; i++ ) {
140 ndof = ndof + ( i + 1 );
141 }
142 tcount = ndof;
143 ndof = ndof * ndofids;
144 }
145
146 // Create dofs for coefficients
147 bcID = this->giveNumber();
148 gamma_ids.clear();
149 for ( int i = 0; i < ndof; i++ ) {
150 int dofid = this->domain->giveNextFreeDofID();
151 gamma_ids.followedBy(dofid);
152 gammaDman->appendDof( new MasterDof( gammaDman.get(), ( DofIDItem )dofid ) );
153 }
154}
155void WeakPeriodicBoundaryCondition :: computeOrthogonalBasis()
156{
157 /* gsMatrix contains the coefficients for the orthogonal basis. The row represents the basis and the column the coefficients. */
158 gsMatrix.resize(ndof, ndof);
159 gsMatrix.zero();
160 gsMatrix.at(1, 1) = 1;
161
162 for ( int i = 2; i <= ndof; i++ ) { // Need ndof base functions. i indicates the row of gsMatrix, ie which polynomial is the current.
163 gsMatrix.at(i, i) = 1; // Copy from V
164
165 // remove projection of v_i on all previous base functions
166 for ( int j = 1; j < i; j++ ) {
167 FloatArray uTemp;
168 uTemp.resize(ndof);
169
170 for ( int k = 1; k <= ndof; uTemp.at(k) = gsMatrix.at(j, k), k++ ) {
171 ;
172 }
173
174 double thisValue = computeProjectionCoefficient(i, j);
175 uTemp.times(-thisValue);
176
177 for ( int k = 1; k <= ndof; gsMatrix.at(i, k) = gsMatrix.at(i, k) + uTemp.at(k), k++ ) {
178 ;
179 }
180
181 }
182 }
183}
184
185double WeakPeriodicBoundaryCondition :: computeProjectionCoefficient(int vIndex, int uIndex)
186{
187 /* Computes <v, u>/<u, u> where vIndex is the term in the polynomial and uIndex is the number of the base v being projected on. */
188 int thisSide = 0;
189
190 double value = 0.0, nom = 0.0, denom = 0.0;
191
192 int A, B, thisOrder;
193 getExponents(vIndex, A, B);
194 thisOrder = A + B;
195 getExponents(uIndex, A, B);
196 thisOrder = thisOrder + A + B;
197
198 // Loop over all elements
199 for ( size_t ielement = 0; ielement < element [ thisSide ].size(); ielement++ ) {
200 // Compute <v, u_i>/<u_i, u_i> on this element and store in nom/denom
201
202 Element *thisElement = this->domain->giveElement( element [ thisSide ].at(ielement) );
203 FEInterpolation *geoInterpolation = thisElement->giveInterpolation();
204
205 std :: unique_ptr< IntegrationRule >iRule(geoInterpolation->giveBoundaryIntegrationRule(thisOrder, side [ thisSide ].at(ielement), thisElement->giveGeometryType()));
206
207 for ( GaussPoint *gp: *iRule ) {
208
209 const FloatArray &lcoords = gp->giveNaturalCoordinates();
210 FloatArray gcoords;
211
212 geoInterpolation->boundaryLocal2Global( gcoords, side [ thisSide ].at(ielement), lcoords, FEIElementGeometryWrapper(thisElement) );
213 double detJ = fabs( geoInterpolation->boundaryGiveTransformationJacobian( side [ thisSide ].at(ielement), lcoords, FEIElementGeometryWrapper(thisElement) ) );
214
215 int a, b;
216 getExponents(vIndex, a, b);
217 double vVal = pow(gcoords.at( surfaceIndexes.at(1) ), a) * pow(gcoords.at( surfaceIndexes.at(2) ), b);
218
219 double uValue = 0.0;
220 for ( int k = 1; k < ndof; k++ ) {
221 int c, d;
222 getExponents(k, c, d);
223 uValue = uValue + gsMatrix.at(uIndex, k) * pow(gcoords.at( surfaceIndexes.at(1) ), c) * pow(gcoords.at( surfaceIndexes.at(2) ), d);
224 }
225
226 nom = nom + vVal *uValue *detJ *gp->giveWeight();
227 denom = denom + uValue *uValue *detJ *gp->giveWeight();
228 }
229 }
230
231 value = nom / denom;
232
233 return value;
234}
235
236void WeakPeriodicBoundaryCondition :: giveEdgeNormal(FloatArray &answer, int element, int side)
237{
238 FloatArray xi;
239
240 if ( this->domain->giveNumberOfSpatialDimensions() == 3 ) {
241 xi.resize(2);
242 xi(0) = 0.25;
243 xi(1) = 0.25;
244 } else {
245 xi.resize(1);
246 xi(0) = 0.5;
247 }
248
249 Element *thisElement = this->domain->giveElement(element);
250 FEInterpolation *interpolation = thisElement->giveInterpolation( ( DofIDItem ) dofids[0] );
251
252 interpolation->boundaryEvalNormal( answer, side, xi, FEIElementGeometryWrapper(thisElement) );
253}
254
255void WeakPeriodicBoundaryCondition :: updateDirection()
256{
257 // Check orientation for s
258 FloatArray normal;
259
260 if ( this->domain->giveNumberOfSpatialDimensions() == 2 ) {
261 surfaceIndexes.resize(1);
262 smin.resize(1);
263 smax.resize(1);
264 } else {
265 surfaceIndexes.resize(2);
266 smin.resize(2);
267 smax.resize(2);
268 }
269
270 giveEdgeNormal( normal, element [ 0 ].at(0), side [ 0 ].at(0) );
271
272 if ( fabs( normal.at(1) ) > 0.99999 ) { // Normal points in X direction
273 direction = 1;
274 if ( this->domain->giveNumberOfSpatialDimensions() == 2 ) {
275 surfaceIndexes.at(1) = 2;
276 } else {
277 surfaceIndexes.at(1) = 2;
278 surfaceIndexes.at(2) = 3;
279 }
280 } else if ( fabs( normal.at(2) ) > 0.99999 ) { // Normal points in Y direction
281 direction = 2;
282 if ( this->domain->giveNumberOfSpatialDimensions() == 2 ) {
283 surfaceIndexes.at(1) = 1;
284 } else {
285 surfaceIndexes.at(1) = 1;
286 surfaceIndexes.at(2) = 3;
287 }
288 } else if ( fabs( normal.at(3) ) > 0.99 ) { // Normal points in Z direction
289 direction = 3;
290 if ( this->domain->giveNumberOfSpatialDimensions() == 2 ) {
291 OOFEM_ERROR("3 dimensioal normal in a 2 dimensional problem.");
292 } else {
293 surfaceIndexes.at(1) = 1;
294 surfaceIndexes.at(2) = 2;
295 }
296 } else {
297 normal.printYourself();
298 Element *thisElement = this->giveDomain()->giveElement( element [ 0 ].at(0) );
299 OOFEM_ERROR("Only surfaces with normal in x, y or z direction supported. (el=%d, side=%d) \n", thisElement->giveLabel(), side [ 0 ].at(0) );
300 }
301}
302
303void WeakPeriodicBoundaryCondition :: updateSminmax()
304{
305 if ( doUpdateSminmax ) {
306 // If sets are used, now is the time to update lists of elements and sides since the sets are unknown in initializeFrom
307 if ( posSet != -1 ) {
308 IntArray posBoundary, negBoundary;
309
310 posBoundary = this->giveDomain()->giveSet(posSet)->giveBoundaryList();
311 for ( int i = 0; i < posBoundary.giveSize() / 2; i++ ) {
312 side [ 0 ].push_back( posBoundary.at(2 * i + 2) );
313 element [ 0 ].push_back( posBoundary.at(2 * i + 1) );
314 }
315
316 negBoundary = this->giveDomain()->giveSet(negSet)->giveBoundaryList();
317 for ( int i = 0; i < negBoundary.giveSize() / 2; i++ ) {
318 side [ 1 ].push_back( negBoundary.at(2 * i + 2) );
319 element [ 1 ].push_back( negBoundary.at(2 * i + 1) );
320 }
321 }
322
323 // Determine which is the positive and which is the negative side
324 FloatArray normal;
325 giveEdgeNormal( normal, element [ 0 ].at(0), side [ 0 ].at(0) );
326
327 double normalSum = -1;
328 ( this->giveDomain()->giveNumberOfSpatialDimensions() <= 2 ) ? normalSum = normal.at(1) + normal.at(2) : normalSum = normal.at(1) + normal.at(2) + normal.at(3);
329
330 if ( normalSum > -0.000001 ) { // No support for 3D yet
331 sideSign [ 0 ] = 1;
332 sideSign [ 1 ] = -1;
333 } else {
334 sideSign [ 0 ] = -1;
335 sideSign [ 1 ] = 1;
336 }
337
339
340 for ( int i = 1; i <= surfaceIndexes.giveSize(); i++ ) {
341 smin.at(i) = this->domain->giveDofManager(1)->giveCoordinate( surfaceIndexes.at(i) );
342 smax.at(i) = this->domain->giveDofManager(1)->giveCoordinate( surfaceIndexes.at(i) );
343
344 for ( int j = 1; j <= this->domain->giveNumberOfDofManagers(); j++ ) {
345 double sValue = this->domain->giveDofManager(j)->giveCoordinate( surfaceIndexes.at(i) );
346 smin.at(i) = std :: min(smin.at(i), sValue);
347 smax.at(i) = std :: max(smax.at(i), sValue);
348 }
349 }
350 doUpdateSminmax = false;
351
352 if ( this->useBasisType == legendre ) {
354 }
355 }
356}
357
358void WeakPeriodicBoundaryCondition :: addElementSide(int newElement, int newSide)
359{
360
361 FloatArray normalNew, normal0;
362 int addToList = 0;
363
364 if ( element [ 0 ].size() > 0 ) {
365 // If there are elements in the list, compare normals in order to determine which list to store them in
366 giveEdgeNormal(normalNew, newElement, newSide);
367 giveEdgeNormal( normal0, element [ 0 ].at(0), side [ 0 ].at(0) );
368 double d = sqrt( pow(normalNew.at(1) - normal0.at(1), 2) + pow(normalNew.at(2) - normal0.at(2), 2) );
369 if ( fabs(d) < 0.001 ) {
370 addToList = 0;
371 } else {
372 addToList = 1;
373 }
374 } else {
375 // Otherwise, check the normal in order to decide upon which direction the parameter runs (x or y)
376 giveEdgeNormal(normalNew, newElement, newSide);
377 if ( fabs(fabs( normalNew.at(1) ) - 1.) < 0.0001 ) { // Normal point in x direction, thus set direction to y
378 direction = 2;
379 } else {
380 direction = 1;
381 }
382 }
383
384 element [ addToList ].push_back(newElement);
385 side [ addToList ].push_back(newSide);
386}
387
388void
389WeakPeriodicBoundaryCondition :: computeDeformationGradient(FloatMatrix &answer, Element *e, FloatArray *lcoord, TimeStep *tStep)
390{
391
392 FloatArray F, u;
393 FloatMatrix dNdx, BH, Fmatrix, Finv;
394 FEInterpolation *interpolation = e->giveInterpolation( ( DofIDItem ) dofids[0] );
395
396 // Fetch displacements
397 e->computeVectorOf({1, 2, 3}, VM_Total, tStep, u);
398
399 // Compute dNdx on boundary.
400 interpolation->evaldNdx(dNdx, *lcoord, FEIElementGeometryWrapper (e) );
401
402 // Compute displcement gradient BH
403 BH.resize(9, dNdx.giveNumberOfRows() * 3);
404 BH.zero();
405
406 for ( int i = 1; i <= dNdx.giveNumberOfRows(); i++ ) {
407 BH.at(1, 3 * i - 2) = dNdx.at(i, 1); // du/dx
408 BH.at(2, 3 * i - 1) = dNdx.at(i, 2); // dv/dy
409 BH.at(3, 3 * i - 0) = dNdx.at(i, 3); // dw/dz
410 BH.at(4, 3 * i - 1) = dNdx.at(i, 3); // dv/dz
411 BH.at(7, 3 * i - 0) = dNdx.at(i, 2); // dw/dy
412 BH.at(5, 3 * i - 2) = dNdx.at(i, 3); // du/dz
413 BH.at(8, 3 * i - 0) = dNdx.at(i, 1); // dw/dx
414 BH.at(6, 3 * i - 2) = dNdx.at(i, 2); // du/dy
415 BH.at(9, 3 * i - 1) = dNdx.at(i, 1); // dv/dx
416 }
417
418 // Finally, compute deformation gradient F=BH*u+I
419 F.beProductOf(BH, u);
420 F.at(1)+=1.0;
421 F.at(2)+=1.0;
422 F.at(3)+=1.0;
423
424 Fmatrix.beMatrixForm(F);
425 Finv.beInverseOf(Fmatrix);
426 answer.beTranspositionOf(Finv);
427
428}
429
430void WeakPeriodicBoundaryCondition :: computeElementTangent(FloatMatrix &B, Element *e, int boundary, TimeStep *tStep)
431{
432
433 OOFEM_ERROR("Function obsolete");
434#if 0
435 FloatArray gcoords;
436
437 FEInterpolation *geoInterpolation = e->giveInterpolation();
438
439 // Use correct interpolation for the dofid on which the condition is applied
440 FEInterpolation *interpolation = e->giveInterpolation( ( DofIDItem ) dofids[0] );
441
442 auto bnodes = interpolation->boundaryGiveNodes(boundary, e->giveGeometryType());
443
444 B.resize(bnodes.giveSize(), ndof);
445 B.zero();
446
447 std :: unique_ptr< IntegrationRule >iRule(geoInterpolation->giveBoundaryIntegrationRule(orderOfPolygon, boundary, e->giveGeometryType()));
448
449 for ( GaussPoint *gp: *iRule ) {
450 const FloatArray &lcoords = gp->giveNaturalCoordinates();
451
453
454 // Find the value of parameter s which is the vert/horiz distance to 0
455 geoInterpolation->boundaryLocal2Global( gcoords, boundary, lcoords, FEIElementGeometryWrapper(e) );
456
457 FloatArray boundaryLocal;
458 interpolation->global2local( boundaryLocal, gcoords, FEIElementGeometryWrapper(e) );
459
460#if 0
461 FloatMatrix FinvT;
462 if (tStep->giveNumber()>0) {
463 if ( dynamic_cast <NLStructuralElement *> (e) != NULL ) { // If finite strains, compute deformation gradient
464 this->computeDeformationGradient(FinvT, e, &boundaryLocal, tStep);
465 FinvT.printYourself();
466 }
467 }
468
469#endif
470
471 // Compute base function values
472 interpolation->boundaryEvalN( N, boundary, lcoords, FEIElementGeometryWrapper(e) );
473 // Compute Jacobian
474 double detJ = fabs( geoInterpolation->boundaryGiveTransformationJacobian( boundary, lcoords, FEIElementGeometryWrapper(e) ) );
475
476 for ( int j = 0; j < B.giveNumberOfColumns(); j++ ) {
477
478 double fVal = computeBaseFunctionValue(j, gcoords);
479
480 for ( int k = 0; k < B.giveNumberOfRows(); k++ ) {
481 B(k, j) += N(k) * fVal * detJ * gp->giveWeight();
482 }
483 }
484 }
485#endif
486}
487
488void WeakPeriodicBoundaryCondition :: assemble(SparseMtrx &answer, TimeStep *tStep, CharType type, const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s, double scale, void* lock)
489{
490 if ( type != TangentStiffnessMatrix && type != StiffnessMatrix ) {
491 return;
492 }
493
494 IntArray c_loc, r_loc;
495 gammaDman->giveLocationArray(gamma_ids, r_loc, r_s);
496 gammaDman->giveLocationArray(gamma_ids, c_loc, c_s);
497
498 FloatMatrix B, BT;
499 int normalSign;
500
502
503 // Assemble each side
504 for ( int thisSide = 0; thisSide <= 1; thisSide++ ) {
505 normalSign = sideSign [ thisSide ];
506
507 for ( size_t ielement = 0; ielement < element [ thisSide ].size(); ielement++ ) { // Loop over each element on this edge
508 Element *thisElement = this->domain->giveElement( element [ thisSide ].at(ielement) );
509 int boundary = side [ thisSide ].at(ielement);
510
511 // Find dofs for this element side
512 IntArray r_sideLoc, c_sideLoc;
513
514 // Find dofs for this element which should be periodic
515 FEInterpolation *interpolation = thisElement->giveInterpolation( ( DofIDItem ) dofids[0] );
516 FEInterpolation *geoInterpolation = thisElement->giveInterpolation();
517
518 auto bNodes = interpolation->boundaryGiveNodes(side [ thisSide ].at(ielement), thisElement->giveGeometryType());
519
520 thisElement->giveBoundaryLocationArray(r_sideLoc, bNodes, dofids, r_s);
521 thisElement->giveBoundaryLocationArray(c_sideLoc, bNodes, dofids, c_s);
522
523 B.resize(bNodes.giveSize()*ndofids, ndofids*tcount);
524 B.zero();
525
526 std :: unique_ptr< IntegrationRule >iRule(geoInterpolation->giveBoundaryIntegrationRule(orderOfPolygon, boundary, thisElement->giveGeometryType()));
527
528 for ( auto &gp: *iRule ) {
529 auto const &lcoords = gp->giveNaturalCoordinates();
530 FloatArray N, gcoords;
531
532 geoInterpolation->boundaryLocal2Global( gcoords, boundary, lcoords, FEIElementGeometryWrapper(thisElement));
533
534 interpolation->boundaryEvalN(N, boundary, lcoords, FEIElementGeometryWrapper(thisElement));
535
536 double detJ = fabs( geoInterpolation->boundaryGiveTransformationJacobian( boundary, lcoords, FEIElementGeometryWrapper(thisElement) ) );
537
538 FloatMatrix Mbeta(ndofids, ndof), Mv(ndofids, bNodes.giveSize()*ndofids), NvTNbeta;
539
540 for (int i=0; i<tcount; i++) {
541 for (int j=0; j<ndofids; j++) {
542 Mbeta.at(j+1, ndofids*i+j+1) = computeBaseFunctionValue(i, gcoords);
543 }
544 }
545
546 for (int i=0; i<N.giveSize(); i++) {
547 for (int j=0; j<ndofids; j++) {
548 Mv.at(j+1, ndofids*i+j+1) = N.at(i+1);
549 }
550 }
551
552 FloatMatrix defNv, F, Finv;
553 double J=1.0;
554
555 if (nlgeo) {
556 FloatArray elocal;
557 geoInterpolation->global2local(elocal, gcoords, FEIElementGeometryWrapper(thisElement));
558 computeDeformationGradient(F, thisElement, &elocal, tStep);
559// J=F.giveDeterminant();
560 Finv.beInverseOf(F);
561 defNv.beProductOf(Finv, Mv);
562 } else {
563 defNv = Mv;
564 }
565
566 NvTNbeta.beTProductOf(defNv, Mbeta);
567
568 NvTNbeta.times(J * detJ * gp->giveWeight());
569 B.add(NvTNbeta);
570
571
572/* for (int i=0; i<ndof; i++) {
573 double fVal = computeBaseFunctionValue(i, gcoords);
574 for ( int k = 0; k < B.giveNumberOfRows(); k++ ) {
575 B(k, i) += N(k) * fVal * detJ * gp->giveWeight();
576 }
577 }*/
578
579
580 }
581
582 B.times(normalSign * scale);
583 BT.beTranspositionOf(B);
584
585#ifdef _OPENMP
586 if (lock)
587 omp_set_lock(static_cast<omp_lock_t*>(lock));
588#endif
589 answer.assemble(r_sideLoc, c_loc, B);
590 answer.assemble(r_loc, c_sideLoc, BT);
591#ifdef _OPENMP
592 if (lock)
593 omp_unset_lock(static_cast<omp_lock_t*>(lock));
594#endif
595 }
596 }
597
598}
599
600double
601WeakPeriodicBoundaryCondition :: computeBaseFunctionValue(int baseID, FloatArray coordinate)
602{
603 if (this->domain->giveNumberOfSpatialDimensions() == 2) {
604 return computeBaseFunctionValue1D(baseID, coordinate.at(surfaceIndexes.at(1)));
605 } else {
606 return computeBaseFunctionValue2D(baseID, Vec2(coordinate.at(surfaceIndexes.at(1)), coordinate.at(surfaceIndexes.at(2))));
607 }
608}
609
610double WeakPeriodicBoundaryCondition :: computeBaseFunctionValue2D(int baseID, FloatArray coordinate)
611{
612 double fVal = 0.0;
613
614 if ( useBasisType == monomial ) {
615 int a, b;
616 getExponents(baseID+1, a, b);
617 fVal = pow(coordinate.at(1), a) * pow(coordinate.at(2), b);
618 } else if ( useBasisType == legendre ) {
619 for ( int i = 1; i <= ndof; i++ ) {
620 int a, b;
621 getExponents(i, a, b);
622 fVal = fVal + gsMatrix.at(baseID+1, i) * pow(coordinate.at(1), a) * pow(coordinate.at(2), b);
623 }
624 }
625 // printf("Value for u_%u att coordinate %f, %f is %f\n", baseID, coordinate.at(1), coordinate.at(2), fVal);
626 return fVal;
627}
628
629double WeakPeriodicBoundaryCondition :: computeBaseFunctionValue1D(int baseID, double coordinate)
630{
631 double fVal = 0.0;
632 FloatArray sideLength;
633
634 // compute side lengths
635 sideLength.resize( smax.giveSize() );
636 for ( int i = 1; i <= smax.giveSize(); i++ ) {
637 sideLength.at(i) = smax.at(i) - smin.at(i);
638 }
639
640 if ( useBasisType == monomial ) {
641 fVal = pow(coordinate, baseID);
642 } else if ( useBasisType == trigonometric ) {
643 if ( baseID % 2 == 0 ) { // Even (does not yet work in 3D)
644 fVal = cos( ( ( double ) baseID ) / 2. * ( coordinate * 2. * M_PI / sideLength.at(1) ) );
645 } else {
646 fVal = sin( ( ( double ) baseID + 1 ) / 2. * ( coordinate * 2. * M_PI / sideLength.at(1) ) );
647 }
648 } else if ( useBasisType == legendre ) {
649 double n = ( double ) baseID;
650 coordinate = 2.0 * coordinate - 1.0;
651 for ( int k = 0; k <= baseID; k++ ) {
652 fVal = fVal + binomial(n, k) * binomial(-n - 1.0, k) * pow( ( 1.0 - coordinate ) / 2.0, ( double ) k );
653 }
654 }
655
656 return fVal;
657}
658
659void WeakPeriodicBoundaryCondition :: assembleVector(FloatArray &answer, TimeStep *tStep,
660 CharType type, ValueModeType mode,
661 const UnknownNumberingScheme &s, FloatArray *eNorms, void* lock)
662{
663 if ( type == InternalForcesVector ) {
664 giveInternalForcesVector(answer, tStep, type, mode, s, nullptr, lock);
665 } else if ( type == ExternalForcesVector ) {
666 giveExternalForcesVector(answer, tStep, type, mode, s, lock);
667 }
668
669}
670
671void
672WeakPeriodicBoundaryCondition :: giveInternalForcesVector(FloatArray &answer, TimeStep *tStep,
673 CharType type, ValueModeType mode,
674 const UnknownNumberingScheme &s, FloatArray *eNorms, void* lock)
675{
676 // Fetch unknowns of this boundary condition
677 IntArray gammaLoc;
678 FloatArray gamma;
679 gammaDman->giveUnknownVector(gamma, gamma_ids, mode, tStep);
680 gammaDman->giveLocationArray(gamma_ids, gammaLoc, s);
681
682 // Values from solution
683 FloatArray a;
684 // Find dofs for this element side
685 IntArray sideLocation, masterDofIDs;
686
687 FloatMatrix B;
688
689 int normalSign;
690
692
693 // Assemble each side
694 for ( int thisSide = 0; thisSide <= 1; thisSide++ ) {
695 normalSign = sideSign [ thisSide ];
696
697 for ( size_t ielement = 0; ielement < element [ thisSide ].size(); ielement++ ) { // Loop over each element on this edge
698 Element *thisElement = this->domain->giveElement( element [ thisSide ].at(ielement) );
699 int boundary = side [ thisSide ].at(ielement);
700
701 // Find dofs for this element which should be periodic
702 FEInterpolation *interpolation = thisElement->giveInterpolation( ( DofIDItem ) dofids[0] );
703 FEInterpolation *geoInterpolation = thisElement->giveInterpolation();
704
705 auto bNodes = interpolation->boundaryGiveNodes(boundary, thisElement->giveGeometryType());
706
707 thisElement->giveBoundaryLocationArray(sideLocation, bNodes, dofids, s, &masterDofIDs);
708 thisElement->computeBoundaryVectorOf(bNodes, dofids, VM_Total, tStep, a);
709
710 FloatArray vProd, gammaProd;
711
712 B.resize(bNodes.giveSize(), ndof);
713 B.zero();
714
715 std :: unique_ptr< IntegrationRule >iRule(geoInterpolation->giveBoundaryIntegrationRule(orderOfPolygon, boundary, thisElement->giveGeometryType()));
716
717 // Where we test with velocity
718 vProd.resize(bNodes.giveSize()*dofids.giveSize());
719 vProd.zero();
720
721 // Where we test with gamma
722 gammaProd.resize(ndof);
723 gammaProd.zero();
724
725 // For test:
726 FloatArray myProd(gammaProd.giveSize()), myProdGamma(vProd.giveSize());
727
728 for ( GaussPoint *gp: *iRule ) {
729 FloatArray lcoords = gp->giveNaturalCoordinates();
730 FloatArray N, gcoords;
731 FloatMatrix C, D, Nbeta, Nv;
732
733 geoInterpolation->boundaryLocal2Global( gcoords, boundary , lcoords, FEIElementGeometryWrapper(thisElement));
734 interpolation->boundaryEvalN(N, boundary, lcoords, FEIElementGeometryWrapper(thisElement));
735 double detJ = fabs( geoInterpolation->boundaryGiveTransformationJacobian( boundary, lcoords, FEIElementGeometryWrapper(thisElement) ) );
736
737 Nbeta.resize(ndofids, ndof);
738 Nbeta.zero();
739 for (int i=0; i<tcount; i++) {
740 double val = computeBaseFunctionValue(i, gcoords);
741 for (int j=0; j<ndofids; j++) {
742 Nbeta.at(j+1, i*ndofids+j+1) = val;
743 }
744 }
745
746 Nv.resize(ndofids, N.giveSize()*ndofids);
747 Nv.zero();
748 for (int i=0; i<ndofids; i++) {
749 for (int j=0; j<N.giveSize(); j++) {
750 Nv.at(i+1, ndofids*j+i+1) = N(j);
751 }
752 }
753
754 FloatMatrix defNv, F, Finv;
755 double J=1.0;
756
757 if (nlgeo) {
758 FloatArray elocal;
759 geoInterpolation->global2local(elocal, gcoords, FEIElementGeometryWrapper(thisElement));
760 computeDeformationGradient(F, thisElement, &elocal, tStep);
761// J = F.giveDeterminant();
762 Finv.beInverseOf(F);
763 defNv.beProductOf(Finv, Nv);
764 } else {
765 J=1.0;
766 defNv = Nv;
767 }
768
769 C.beTProductOf(Nbeta, defNv);
771
772 gammaProd.plusProduct(D, a, J*detJ*gp->giveWeight()*normalSign);
773 vProd.plusProduct(C, gamma, J*detJ*gp->giveWeight()*normalSign);
774
775 // Old:
776/* FloatArray BaseFunctionValues;
777 BaseFunctionValues.resize(ndof);
778 BaseFunctionValues.zero();
779 for (int i=0; i<ndof; i++) {
780 BaseFunctionValues.at(i+1) = computeBaseFunctionValue(i, gcoords);
781 }
782
783 C.beDyadicProductOf(N, BaseFunctionValues);
784 D.beTranspositionOf(C);
785
786 myProd.plusProduct(C, a, detJ*gp->giveWeight()*normalSign);
787 myProdGamma.plusProduct(D, gamma, detJ*gp->giveWeight()*normalSign); */
788
789 }
790#ifdef _OPENMP
791 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
792#endif
793 if ( eNorms ) {
794 eNorms->assembleSquared( vProd, gamma_ids );
795 eNorms->assembleSquared( gammaProd, masterDofIDs);
796 }
797
798 answer.assemble(gammaProd, gammaLoc);
799 answer.assemble(vProd, sideLocation);
800#ifdef _OPENMP
801 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
802#endif
803// answer.assemble(myProd, gammaLoc);
804// answer.assemble(myProdGamma, sideLocation);
805 }
806 }
807}
808
809void
810WeakPeriodicBoundaryCondition :: giveExternalForcesVector(FloatArray &answer, TimeStep *tStep,
811 CharType type, ValueModeType mode,
812 const UnknownNumberingScheme &s, void* lock)
813{
814
816
817 IntArray gammaLoc;
818 gammaDman->giveLocationArray(gamma_ids, gammaLoc, s);
819
820 FloatArray temp;
821 temp.resize(ndof);
822 temp.zero();
823
824 int normalSign;
825
826 for ( int thisSide = 0; thisSide <= 1; thisSide++ ) {
827 normalSign = sideSign [ thisSide ];
828 for ( size_t ielement = 0; ielement < element [ thisSide ].size(); ielement++ ) { // Loop over each element on this edge
829
830 Element *thisElement = this->domain->giveElement( element [ thisSide ].at(ielement) );
831
832 FEInterpolation *geoInterpolation = thisElement->giveInterpolation();
833
834 std :: unique_ptr< IntegrationRule >iRule(geoInterpolation->giveBoundaryIntegrationRule(orderOfPolygon, side [ thisSide ].at(ielement), thisElement->giveGeometryType() ));
835
836 for ( auto gp: *iRule ) {
837
838 FloatArray gcoords;
839 FloatArray lcoords = gp->giveNaturalCoordinates();
840
841 // Find the value of parameter s which is the vert/horiz distance to 0
842 geoInterpolation->boundaryLocal2Global( gcoords, side [ thisSide ].at(ielement), lcoords, FEIElementGeometryWrapper( thisElement ) );
843 // Compute Jacobian
844 double detJ = fabs( geoInterpolation->boundaryGiveTransformationJacobian( side [ thisSide ].at(ielement), lcoords, FEIElementGeometryWrapper(thisElement) ) );
845
846 for ( int j = 0; j < ndof; j++ ) {
847 FloatArray coord;
848
849 double fVal = computeBaseFunctionValue(j, gcoords);
850
851 temp.at(j+1) += normalSign*this->g.dotProduct(gcoords)*fVal*gp->giveWeight()*detJ;
852 }
853 }
854 }
855 }
856
857
858#ifdef _OPENMP
859 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
860#endif
861 answer.assemble(temp, gammaLoc);
862#ifdef _OPENMP
863 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
864#endif
865 // bp: can be a bug, answer changed after localization !
866 // Finally, compute value of loadtimefunction
867 double factor = this->giveTimeFunction()->evaluate(tStep, mode);
868 answer.times(factor);
869}
870
871int WeakPeriodicBoundaryCondition :: giveNumberOfInternalDofManagers()
872{
873 return 1;
874}
875
876DofManager *WeakPeriodicBoundaryCondition :: giveInternalDofManager(int i)
877{
878 if ( i == 1 ) {
879 return gammaDman.get();
880 } else {
881 return NULL;
882 }
883}
884
885double WeakPeriodicBoundaryCondition :: factorial(int n)
886{
887 int x = 1;
888 for ( int i = 1; i <= n; i++ ) {
889 x = x * i;
890 }
891 return x;
892}
893
894double WeakPeriodicBoundaryCondition :: binomial(double n, int k)
895{
896 double f = 1.0;
897 for ( int i = 1; i <= k; i++ ) {
898 f = f * ( n - ( k - i ) ) / i;
899 }
900 return f;
901}
902
903void WeakPeriodicBoundaryCondition :: getExponents(int term, int &i, int &j)
904{
905 bool doContinue = true;
906
907 // c is the number of the current term
908 int c = 0;
909
910 // n is the order of the current polynomial (row in Pascals triangle)
911 int n = 0;
912
913 while ( doContinue ) {
914 for ( int t = 0; t <= n; t++ ) {
915 c++;
916 if ( c == term ) {
917 i = n - t;
918 j = t;
919 doContinue = false;
920 break;
921 }
922 }
923 n++;
924 }
925}
926}
#define N(a, b)
#define REGISTER_BoundaryCondition(class)
ActiveBoundaryCondition(int n, Domain *d)
Definition activebc.h:71
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
void computeVectorOf(ValueModeType u, TimeStep *tStep, FloatArray &answer)
Definition element.C:103
void computeBoundaryVectorOf(const IntArray &bNodes, const IntArray &dofIDMask, ValueModeType u, TimeStep *tStep, FloatArray &answer, bool padding=false)
Definition element.C:163
int giveLabel() const
Definition element.h:1125
virtual Element_Geometry_Type giveGeometryType() const =0
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 int global2local(FloatArray &answer, const FloatArray &gcoords, const FEICellGeometry &cellgeo) const =0
virtual double boundaryGiveTransformationJacobian(int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
virtual void boundaryLocal2Global(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
virtual double evaldNdx(FloatMatrix &answer, 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
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
void plusProduct(const FloatMatrix &b, const FloatArray &s, double dV)
Definition floatarray.C:288
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
virtual void printYourself() const
Definition floatarray.C:762
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
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 times(double s)
Definition floatarray.C:834
void times(double f)
void add(const FloatMatrix &a)
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 beTranspositionOf(const FloatMatrix &src)
void zero()
Zeroes all coefficient of receiver.
bool beInverseOf(const FloatMatrix &src)
*Prints matrix to stdout Useful for debugging void printYourself() const
void beMatrixForm(const FloatArray &aArray)
int giveNumberOfRows() const
Returns number of rows of receiver.
double at(std::size_t i, std::size_t j) const
void beTProductOf(const FloatMatrix &a, const FloatMatrix &b)
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
virtual int assemble(const IntArray &loc, const FloatMatrix &mat)=0
int giveNumber()
Returns receiver's number.
Definition timestep.h:144
std ::unique_ptr< Node > gammaDman
void computeDeformationGradient(FloatMatrix &answer, Element *e, FloatArray *lcoord, TimeStep *tStep)
double computeProjectionCoefficient(int vIndex, int uIndex)
void giveInternalForcesVector(FloatArray &answer, TimeStep *tStep, CharType type, ValueModeType mode, const UnknownNumberingScheme &s, FloatArray *eNorm=nullptr, void *lock=nullptr)
double computeBaseFunctionValue(int baseID, FloatArray coordinate)
void giveEdgeNormal(FloatArray &answer, int element, int side)
void getExponents(int n, int &i, int &j)
void giveExternalForcesVector(FloatArray &answer, TimeStep *tStep, CharType type, ValueModeType mode, const UnknownNumberingScheme &s, void *lock=nullptr)
double computeBaseFunctionValue2D(int baseID, FloatArray coordinate)
double computeBaseFunctionValue1D(int baseID, double coordinate)
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Definition inputrecord.h:75
#define M_PI
Definition mathfem.h:52
static FloatArray Vec2(const double &a, const double &b)
Definition floatarray.h:606
@ trigonometric
#define _IFT_WeakPeriodicBoundaryCondition_nlgeo
#define _IFT_WeakPeriodicBoundaryCondition_elementSidesNegative
#define _IFT_WeakPeriodicBoundaryCondition_elementSidesPositiveSet
#define _IFT_WeakPeriodicBoundaryCondition_gradient
#define _IFT_WeakPeriodicBoundaryCondition_descritizationType
#define _IFT_WeakPeriodicBoundaryCondition_elementSidesPositive
#define _IFT_WeakPeriodicBoundaryCondition_order
#define _IFT_WeakPeriodicBoundaryCondition_dofids
#define _IFT_WeakPeriodicBoundaryCondition_elementSidesNegativeSet

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