OOFEM 3.0
Loading...
Searching...
No Matches
qclinearstatic.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
39#include "nummet.h"
40#include "timestep.h"
41#include "element.h"
42#include "sparsemtrx.h"
43#include "verbose.h"
44#include "classfactory.h"
45#include "datastream.h"
46#include "contextioerr.h"
47#include "classfactory.h"
48
49#include "qcnode.h"
50#include "domain.h"
51#include "dof.h"
52#include "crosssection.h"
53
58
60
61 #include "t3dinterface.h"
62#ifdef __T3D
63 #include "t3d.h"
64#endif
65
66#ifdef __MPI_PARALLEL_MODE
67 #include "problemcomm.h"
68 #include "communicator.h"
69#endif
70
71#include <typeinfo>
72
73namespace oofem {
75
76QClinearStatic :: QClinearStatic(int i, EngngModel *_master) : LinearStatic(i, _master), loadVector(), displacementVector()
77{
78}
79
80
81QClinearStatic :: ~QClinearStatic()
82{
83}
84
85
86void
87QClinearStatic :: initializeFrom(InputRecord &ir)
88{
89 LinearStatic :: initializeFrom(ir);
90
92
93 if ( qcApproach == 0 || qcApproach == 1 || qcApproach == 2 || qcApproach == 3 ) {
94 // approach A0 = full solved particle model
95 // A1 hanging nodes, interpolation only
96 // A2 global homogenization
97 // A3 individual homogenization
98 } else {
99 OOFEM_ERROR("Invalid input field \"qcApproach\". Value: %d is not supported", qcApproach);
100 }
101
102 if ( qcApproach > 0 ) { // apply qc
103 // Initialize Full-Solved Domain
105 this->Fullsolveddomain.initializeFrom(ir);
106
108 if ( qcApproach > 1 ) {
109 homogenizationMtrxType = 1; // isotropic is default
111 }
112
113
115
116 // Generate particles
119 if ( generateParticles == 0 ) { // 0 - defined in input file
120 } else if ( generateParticles == 1 ) { // 1 - generate + save
123 } else if ( generateParticles == 2 ) { // 2 - load
124 gg.loadParticles();
125 } else {
126 OOFEM_ERROR("Invalid input field \"genParticles\". Value: %d is not supported", generateParticles);
127 }
128
129 // Generate links
130 generateLinks = 0;
132 if ( generateLinks == 0 ) {} else if ( generateLinks == 1 ) { // generate + save
134 gg.generateLinks();
135 } else if ( generateLinks == 2 ) { // load
136 gg.loadLinks();
137 } else {
138 OOFEM_ERROR("Invalid input field \"genLinks\". Value: %d is not supported", generateLinks);
139 }
140
141 // Generate interpolation elements
144
148 } else if ( generateInterpolationElements == 1 ) {
151 } else if ( generateInterpolationElements == 2 ) {
153 } else {
154 OOFEM_ERROR("Invalid input field \"GenInterpElem\". Value: %d is not supported", generateInterpolationElements);
155 }
156
157 // test of combination of input geometry generating
158#if DEBUG
159 if ( generateParticles == 1 && generateLinks != 1 ) {
160 OOFEM_ERROR("Links cannot be set manualy if particles are generated automaticaly");
161 }
163 OOFEM_ERROR("Interpolation elements cannot be set manually if particles are generated automaticaly");
164 }
165#endif
166 } else { // if qcApproach == 0
168 generateLinks = 0;
170 }
171
172#ifdef __MPI_PARALLEL_MODE
173 if ( isParallel() ) {
175 communicator = new NodeCommunicator( this, commBuff, this->giveRank(),
176 this->giveNumberOfProcesses() );
177 }
178
179#endif
180}
181
182
183void
184QClinearStatic :: postInitialize()
185{
186 // checkout print of dof type before interpolation mesh is generated (1/2 = RN/HN)
187 /*
188 * for (int i=1; i<=this->giveDomain(1)->giveNumberOfDofManagers(); i++)
189 * {
190 * qcNode *n = dynamic_cast< qcNode * >( this->giveDomain(1)->giveDofManager(i) );
191 * OOFEM_LOG_INFO(" xxx: node %d type %d \n",n->giveGlobalNumber(),n->giveQcNodeType());
192 * }
193 */
194
196 qc.setNoDimensions( this->giveDomain(1) );
197
198 // interpolation mesh
200 if ( qcApproach > 0 ) {
206 }
207
208 // checkout print of dof type after interpolation mesh is generated (1/2 = RN/HN)
209 /*
210 * OOFEM_LOG_INFO(" xxx: --------------------- \n");
211 * for ( int i = 1; i <= this->giveDomain(1)->giveNumberOfDofManagers(); i++ ) {
212 * //qcNode *n = dynamic_cast< qcNode * >( this->giveDomain(1)->giveDofManager(i) );
213 * Node *n = this->giveDomain(1)->giveNode(i);
214 * OOFEM_LOG_INFO( " xxx: node %d type %d \n", n->giveGlobalNumber(), n->giveQcNodeType() );
215 * }
216 */
217
218 EngngModel :: postInitialize();
219
220 // apply QC
221
222 if ( qcApproach == 0 ) { //A0 - fully solved model
223 // all nodes nad elements are activated
224 this->activatedNodeList.resize(this->giveDomain(1)->giveNumberOfDofManagers(), true);
225 this->activatedElementList.resize(this->giveDomain(1)->giveNumberOfElements(), true);
226 } else if ( qcApproach == 1 ) { // A1 - hanging nodes
227 // all nodes nad elements are activated
228 this->activatedNodeList.resize(this->giveDomain(1)->giveNumberOfDofManagers(), true);
229 this->activatedElementList.resize(this->giveDomain(1)->giveNumberOfElements(), true);
230
231 qc.applyApproach1( this->giveDomain(1) );
232
233 // postinitialize interpolation elements // ??km?? TO DO: giveInterpolationElem...
234 // TO DO: in EngngModel::postInitialize() elements are postinitialized again
235 for ( auto &el : this->giveDomain(1)->giveElements() ) {
236 el->postInitialize();
237 }
238 } else if ( qcApproach == 2 ) { // A2 - global homogenization
239 // elements need to be postintialized before computation of volume.
240 // TO DO: in EngngModel::postInitialize() elements are postinitialized again
241 // postinitialize interpolation elements // ??km?? TO DO: giveInterpolationElem...
242 for ( auto &el : this->giveDomain(1)->giveElements() ) {
243 el->postInitialize();
244 }
245
246 double volumeOfInterpolationMesh = this->computeTotalVolumeOfInterpolationMesh( this->giveDomain(1) );
247 qc.applyApproach2(this->giveDomain(1), homogenizationMtrxType, volumeOfInterpolationMesh);
248 } else if ( qcApproach == 3 ) { // A3 - local homogenization
249 // elements need to be postintialized before computation of volume.
250 // TO DO: in EngngModel::postInitialize() elements are postinitialized again
251 // postinitialize interpolation elements // ??km?? TO DO: giveInterpolationElem...
252 for ( auto &el : this->giveDomain(1)->giveElements() ) {
253 el->postInitialize();
254 }
256 } else {
257 OOFEM_ERROR("unsupported qcApproach number");
258 }
259
260
261 // checkout print of activated elements
262 /*
263 * OOFEM_LOG_INFO(" xxx: --------------------- \n");
264 * for ( int i = 1; i <= ( int ) this->activatedElementList.size(); i++ ) {
265 * if ( this->activatedElementList.at(i - 1) ) {
266 * OOFEM_LOG_INFO(" active el %d d \n", i);
267 * }
268 * }
269 */
270}
271
272
273void QClinearStatic :: solveYourself()
274{
275 LinearStatic :: solveYourself();
276}
277
278
279void QClinearStatic :: solveYourselfAt(TimeStep *tStep)
280{
281 // initialize node eq numbering (for actived nodes only)
282 if ( !qcEquationNumbering.giveIsInitializedFlag() ) {
283 qcEquationNumbering.init2(this->giveDomain(1), activatedNodeList, tStep);
284 }
285 LinearStatic :: solveYourselfAt(tStep);
286}
287
288
289void
290QClinearStatic :: initializeFullSolvedDomain(InputRecord &ir)
291{
296 // check input format
297#ifdef DEBUG
298 if ( FullSolvedDomainRadius.giveSize() != 0 && FullSolvedDomainRadius.giveSize() % 4 != 0 ) {
299 OOFEM_ERROR("invalid format of FullSolvedDomainRadius");
300 }
301 if ( FullSolvedDomainBox.giveSize() != 0 && FullSolvedDomainBox.giveSize() % 6 != 0 ) {
302 OOFEM_ERROR("invalid format of FullSolvedDomainBox");
303 }
304#endif
305}
306
307
308bool
309QClinearStatic :: nodeInFullSolvedDomainTest(Node *n)
310{
311 const auto &coordinates = n->giveCoordinates();
312 // is tested node in FullSolvedDomainNodes
313 if ( FullSolvedDomainNodes.giveSize() != 0 ) {
314 for ( int i = 1; i <= FullSolvedDomainNodes.giveSize(); i++ ) {
315 if ( n->giveNumber() == FullSolvedDomainNodes.at(i) ) {
316 return true;
317 }
318 }
319 }
320
321 // is tested node in FullSolvedDomainElements
322 if ( FullSolvedDomainElements.giveSize() != 0 ) {
323 for ( int i = 1; i <= FullSolvedDomainElements.giveSize(); i++ ) {
324 OOFEM_ERROR("Definition of Full Solved Domain by list of interpolation element has not been implemented yet");
325 // ??km?? TO DO:
326 //if ( "node n is in element with number FullSolvedDomainElements.at(i)" ) {
327 // return true;
328 //}
329 }
330 }
331
332 // is tested node in FullSolvedDomainRadius
333 if ( FullSolvedDomainRadius.giveSize() != 0 ) {
334 for ( int i = 0; i <= FullSolvedDomainRadius.giveSize() / 4 - 1; i++ ) {
335 FloatArray vector;
336 vector.resize(3);
337 vector.at(1) = coordinates.at(1) - FullSolvedDomainRadius.at(4 * i + 1);
338 vector.at(2) = coordinates.at(2) - FullSolvedDomainRadius.at(4 * i + 2);
339 vector.at(3) = coordinates.at(3) - FullSolvedDomainRadius.at(4 * i + 3);
340 if ( vector.computeNorm() <= FullSolvedDomainRadius.at(4 * i + 4) ) {
341 return true;
342 }
343 }
344 }
345
346 // is tested node in FullSolvedDomainBox
347 if ( FullSolvedDomainBox.giveSize() != 0 ) {
348 for ( int i = 0; i <= FullSolvedDomainBox.giveSize() / 6 - 1; i++ ) {
349 FloatArray A(3), B(3);
350 // left bottom corner coords
351 A.at(1) = FullSolvedDomainBox.at(6 * i + 1);
352 A.at(2) = FullSolvedDomainBox.at(6 * i + 2);
353 A.at(3) = FullSolvedDomainBox.at(6 * i + 3);
354 // right top corner coords
355 B.at(1) = FullSolvedDomainBox.at(6 * i + 4);
356 B.at(2) = FullSolvedDomainBox.at(6 * i + 5);
357 B.at(3) = FullSolvedDomainBox.at(6 * i + 4);
358
359 if ( ( A.at(1) <= coordinates.at(1) ) && ( coordinates.at(1) <= B.at(1) ) && \
360 ( A.at(2) <= coordinates.at(2) ) && ( coordinates.at(2) <= B.at(2) ) && \
361 ( A.at(3) <= coordinates.at(3) ) && ( coordinates.at(3) <= B.at(3) ) ) {
362 return true;
363 }
364 }
365 }
366
367 return false;
368}
369
370
371void
372QClinearStatic :: setRepNodesInVerticesOfInterpolationMesh(Domain *d)
373{
374 int nol = 0; // number of links
375 int noe = d->giveNumberOfElements(); // number of all elements
376 for ( int i = 1; i <= noe; i++ ) { // over elements
377 int noen = d->giveElement(i)->giveNumberOfDofManagers(); // number of element nodes
378 if ( noen > 2 ) { // skip links with 2 nodes only
379 for ( int j = 1; j <= noen; j++ ) { // over element nodes
380 qcNode *n = dynamic_cast< qcNode * >( d->giveElement(i)->giveDofManager(j) );
381 if ( n ) {
382 n->setAsRepnode();
383 } else {
384 OOFEM_WARNING( "Node %d of interpolation element %d is not \"qcNode\", quasicontinuum is not applied in this node", d->giveElement(i)->giveGlobalNumber(), d->giveElement(i)->giveInternalDofManager(j)->giveGlobalNumber() );
385 }
386 }
387 } else if ( noen == 2 ) {
388 nol++;
389 }
390 }
391 // here we assume that in input file, interpolation elements ale listed continuously in the end of element list (after links )
393}
394
395
396void
397QClinearStatic :: setQCNodeType(Domain *d)
398{
399 for ( int i = 1; i <= d->giveNumberOfDofManagers(); i++ ) {
400 qcNode *n = dynamic_cast< qcNode * >( d->giveDofManager(i) );
401 if ( n ) {
402 if ( !this->nodeInFullSolvedDomainTest(n) ) {
403 n->setAsHanging();
404 }
405 } else {
406 //OOFEM_ERROR("Node %d: Only \"qcNode\" type is supported in quasicontinuum simulation", i);
407 OOFEM_WARNING("Node %d is not \"qcNode\", quasicontinuum is not applied in this node", i);
408 }
409 }
410}
411
412
413void
414QClinearStatic :: updateNodeTypes(Domain *d)
415{
416 for ( int i = 1; i <= d->giveNumberOfDofManagers(); i++ ) {
417 // for ( Dof *dof: *this ) {
418 //for ( qcNode *n: *this ) {
419 qcNode *n = dynamic_cast< qcNode * >( d->giveDofManager(i) );
420 if ( n ) {
421 if ( this->nodeInFullSolvedDomainTest(n) ) {
422 n->setAsRepnode();
423 } else {
424 n->setAsHanging();
425 }
426 } else {
427 //OOFEM_ERROR("Node %d: Only \"qcNode\" type is supported in quasicontinuum simulation", i);
428 OOFEM_WARNING("Node %d is not \"qcNode\", quasicontinuum is not applied in this node", i);
429 }
430 }
431}
432
433
434void
435QClinearStatic :: createInterpolationMeshNodes(Domain *d)
436{
437 // interpolation mesh
439 // interpolation mesh is defined in input file - elements with material number qcMatNumber
440 } else if ( generateInterpolationElements == 1 ) {
442 } else if ( generateInterpolationElements == 2 ) {
444 }
445}
446
447
448std :: vector< IntArray >
449QClinearStatic :: generateInterpolationMesh(Domain *d)
450{
451 std :: vector< IntArray >newMeshNodes;
452#ifdef __T3D
453 T3DInterface *t3dInterface( this->giveDomain(1) );
454#endif
455 std :: vector< FloatArray >nodeCoords;
456 std :: vector< IntArray >meshNodes;
457 IntArray cellTypes;
458
459 char options_string [ 128 ] = "";
460 const char *t3dInFile; //char *t3dInFile = "interpolationMesh_t3d.in";
461 const char *t3dOutFile; //char *t3dOutFile = "interpolationMesh_t3d.out";
462
463 std :: string temp;
464 temp = t3dFileName;
465 temp.append(".oofem.t3d.out");
466 t3dOutFile = temp.c_str();
467 t3dInFile = t3dFileName.c_str();
468 sprintf(options_string, "-i %s -o %s -S -u %f -Q -W", t3dInFile, t3dOutFile, defaultT3DMeshSize);
469
470#ifdef __T3D
472 /* run T3D to generate mesh */
473 try {
474 t3d_main(NULL, options_string);
475 } catch(int exit_code) {
476 fprintf(stderr, "T3d was prematuraly terminated with error code %d\n\n", exit_code);
477 }
478 }
479#else
480 OOFEM_ERROR("OOFEM is NOT compiled with T3D option but T3D in needed");
481#endif
482
484 // create interpolation mesh from t3d output file
485#ifdef __T3D
486 t3dInterface.createQCInterpolationMesh(t3dOutFile, nodeCoords, meshNodes, cellTypes);
487#endif
488
489 // map mesh to position of particles
490 newMeshNodes = this->transformMeshToParticles(this->giveDomain(1), nodeCoords, meshNodes);
491
492 // degenerated elements have been removed
493 // check if mesh is consistent after removal. ??km?? TO DO ?? How to check it?
494 }
495 return newMeshNodes;
496}
497
498
499std :: vector< IntArray >
500QClinearStatic :: loadInterpolationMesh(Domain *d)
501{
502 std :: vector< IntArray >newMeshNodes;
503 //#ifdef __T3D
504 T3DInterface t3dInterface( this->giveDomain(1) );
505 //#endif
506 std :: vector< FloatArray >nodeCoords;
507 std :: vector< IntArray >meshNodes;
508 IntArray cellTypes;
509
510 const char *t3dOutFile; //char *t3dOutFile = "interpolationMesh_t3d.out";
511
512 t3dOutFile = t3dFileName.c_str();
513
514 // create interpolation mesh from given t3d output file
515 //#ifdef __T3D
516 t3dInterface.createQCInterpolationMesh(t3dOutFile, nodeCoords, meshNodes, cellTypes);
517 //#endif
518
519 // map mesh to position of particles
520 newMeshNodes = this->transformMeshToParticles(this->giveDomain(1), nodeCoords, meshNodes);
521
522 // degenerated elements have been removed
523 // check if mesh is consistent after removal. ??km?? TO DO ?? How to check it?
524 return newMeshNodes;
525}
526
527
528std :: vector< IntArray >
529QClinearStatic :: transformMeshToParticles(Domain *d, std :: vector< FloatArray > &nodeCoords, std :: vector< IntArray > &meshNodes)
530// all nodes in meshNodes are shifted to the position of neares particle (i.e. node in domain)
531// this node is set as repnode
532// elements degenerated (by the shift of two vertexes into the same particle) are removed from the list
533//
534{
535 // number of particles (nodes in domain)
536 //int nop = this->giveDomain(1)->giveNumberOfDofManagers() ; // TO DO we assume that all DofManagers all nodes (particles)
537 // number of (mesh) nodes
538 int nomn = (int) nodeCoords.size();
539 // number of (mesh) element
540 int nome = (int) meshNodes.size();
541
542 //newMeshNodes=meshNodes;
543 std :: vector< IntArray >newMeshNodes;
544 newMeshNodes.clear();
545 //particleOfMeshNode=zeros(1,nomn);
546 IntArray newNodeNumbers;
547 newNodeNumbers.resize(nomn);
548
549 // loop over all nodes of mesh elments
550 for ( int i = 1; i <= nomn; i++ ) {
551 // ??km?? TO DO: use octree in "findNearestParticle", now it is not effective
552 // find nearest node and set him as repnode (is neares node QCnode?)
553 qcNode *nearestParticle = dynamic_cast< qcNode * >( findNearestParticle(d, nodeCoords [ i - 1 ]) );
554 if ( nearestParticle ) {
555 if ( nearestParticle->giveQcNodeType() != 1 ) { // if nearest node is not repnode
556 nearestParticle->setAsRepnode();
557 }
558 } else {
559 OOFEM_ERROR("Vertex of interpolation mesh is shifted to node which is not \"qcNode\"");
560 // ??km?? TO DO: add combination of qcNode and normal node in one input. Then not necessarily qcNode is needed.
561 // Test if node "nearestParticle" has independet DOFs should be enough.
562 // OOFEM_WARNING(" ");
563 }
564
565 nodeCoords [ i - 1 ] = nearestParticle->giveCoordinates();
566 newNodeNumbers [ i - 1 ] = nearestParticle->giveNumber();
567 }
568
569 //
570 // check and remove degenerated elements
571 //
572
573
574 // for 2D triangles
575 if ( meshNodes [ 0 ].giveSize() == 3 ) {
576 // TO DO: how to do not consider interpolation elements in user define area
577 // ??km?? for example in FSD it is better without interpolation elements
578 // check if two or more vertexes were shifted to the same particle -- element degeneration
579 for ( int i = 1; i <= nome; i++ ) {
580 int n1 = meshNodes [ i - 1 ].at(1); // node numbers
581 int n2 = meshNodes [ i - 1 ].at(2);
582 int n3 = meshNodes [ i - 1 ].at(3);
583 if ( newNodeNumbers.at(n1) == newNodeNumbers.at(n2) || \
584 newNodeNumbers.at(n1) == newNodeNumbers.at(n3) || \
585 newNodeNumbers.at(n2) == newNodeNumbers.at(n3) ) {
586 continue; // skip degenerate element
587 } else { // check degeneration to negative volume
588 // ??km?? TO DO: how to check negative volume in 2D
589 // overlaping elements may cause problems in homogenization
590 double detJ = 1.0;
591 if ( detJ <= 0 ) {
592 OOFEM_WARNING("%d-th interpolation element degenerates to negative volume", i);
593 } else { // element is ok and will be saved
594 IntArray OkmeshNodes(3);
595 OkmeshNodes.at(1) = newNodeNumbers.at(n1);
596 OkmeshNodes.at(2) = newNodeNumbers.at(n2);
597 OkmeshNodes.at(3) = newNodeNumbers.at(n3);
598 newMeshNodes.push_back(OkmeshNodes);
599 }
600 }
601 } // over elements in 2D
602
603 // for 3D tetras
604 } else {
605 for ( int i = 1; i <= nome; i++ ) {
606 // TO DO: how to do not consider interpolation elements in user define area
607 // ??km?? for example in FSD it is better without interpolation elements
608
609 // check if two or more vertexes were shifted to the same particle -- element degeneration
610 int n1 = meshNodes [ i - 1 ].at(1); // node numbers
611 int n2 = meshNodes [ i - 1 ].at(2);
612 int n3 = meshNodes [ i - 1 ].at(3);
613 int n4 = meshNodes [ i - 1 ].at(4);
614 if ( newNodeNumbers.at(n1) == newNodeNumbers.at(n2) || \
615 newNodeNumbers.at(n1) == newNodeNumbers.at(n3) || \
616 newNodeNumbers.at(n1) == newNodeNumbers.at(n4) || \
617 newNodeNumbers.at(n2) == newNodeNumbers.at(n3) || \
618 newNodeNumbers.at(n2) == newNodeNumbers.at(n4) || \
619 newNodeNumbers.at(n3) == newNodeNumbers.at(n4) ) {
620 continue; // skip degenerate element
621 } else { // check degeneration to negative volume
622 double x1 = d->giveDofManager( newNodeNumbers.at(n1) )->giveCoordinate(1);
623 double y1 = d->giveDofManager( newNodeNumbers.at(n1) )->giveCoordinate(2);
624 double z1 = d->giveDofManager( newNodeNumbers.at(n1) )->giveCoordinate(3);
625 double x2 = d->giveDofManager( newNodeNumbers.at(n2) )->giveCoordinate(1);
626 double y2 = d->giveDofManager( newNodeNumbers.at(n2) )->giveCoordinate(2);
627 double z2 = d->giveDofManager( newNodeNumbers.at(n2) )->giveCoordinate(3);
628 double x3 = d->giveDofManager( newNodeNumbers.at(n3) )->giveCoordinate(1);
629 double y3 = d->giveDofManager( newNodeNumbers.at(n3) )->giveCoordinate(2);
630 double z3 = d->giveDofManager( newNodeNumbers.at(n3) )->giveCoordinate(3);
631 double x4 = d->giveDofManager( newNodeNumbers.at(n4) )->giveCoordinate(1);
632 double y4 = d->giveDofManager( newNodeNumbers.at(n4) )->giveCoordinate(2);
633 double z4 = d->giveDofManager( newNodeNumbers.at(n4) )->giveCoordinate(3);
634 double detJ = ( x4 - x1 ) * ( y2 - y1 ) * ( z3 - z1 ) - ( x4 - x1 ) * ( y3 - y1 ) * ( z2 - z1 ) + ( x3 - x1 ) * ( y4 - y1 ) * ( z2 - z1 ) - ( x2 - x1 ) * ( y4 - y1 ) * ( z3 - z1 ) + ( x2 - x1 ) * ( y3 - y1 ) * ( z4 - z1 ) - ( x3 - x1 ) * ( y2 - y1 ) * ( z4 - z1 );
635 if ( detJ <= 0 ) {
636 OOFEM_WARNING("%d-th interpolation element degenerates to negative volume", i);
637 continue;
638 } else { // element is ok and will be saved
639 IntArray OkmeshNodes(4);
640 OkmeshNodes.at(1) = newNodeNumbers.at(n1);
641 OkmeshNodes.at(2) = newNodeNumbers.at(n2);
642 OkmeshNodes.at(3) = newNodeNumbers.at(n3);
643 OkmeshNodes.at(4) = newNodeNumbers.at(n4);
644 newMeshNodes.push_back(OkmeshNodes);
645 }
646 }
647 } // over elements
648 } // in 3D
649
650 return newMeshNodes;
651}
652
653
654double
655QClinearStatic :: computeTotalVolumeOfInterpolationMesh(Domain *d)
656// TO DO: computeVolumeAreaOrLength() is not working
657{
658 int dim = d->giveNumberOfSpatialDimensions();
659 // loop ovel all elements
660 double volume = 0.;
661 double totalVolume = 0.;
662
663 if ( dim == 2 ) {
664 double th;
665
666 for ( int i = 1; i <= d->giveNumberOfElements(); i++ ) {
667 // skip links with 2 nodes
668 // ??KM?? TO DO: use only list of interpolation elements
669 if ( d->giveElement(i)->giveNumberOfDofManagers() > 2 ) {
670 volume = d->giveElement(i)->computeVolumeAreaOrLength();
671 th = d->giveElement(i)->giveCrossSection()->give(CS_Thickness, NULL);
672 totalVolume += volume / th;
673 }
674 }
675 } else if ( dim == 3 ) {
676 for ( int i = 1; i <= d->giveNumberOfElements(); i++ ) {
677 // skip links with 2 nodes
678 // ??KM?? TO DO: use only list of interpolation elements
679 if ( d->giveElement(i)->giveNumberOfDofManagers() > 2 ) {
680 volume = d->giveElement(i)->computeVolumeAreaOrLength();
681 totalVolume += volume;
682 }
683 }
684 } else {
685 OOFEM_ERROR("Invalid number of dimensions. Only 2d and 3d domains are supported in QC simulation. \n");
686 }
687
688 return totalVolume;
689}
690
691
693QClinearStatic :: findNearestParticle(Domain *d, FloatArray coords)
694{
695 // TO DO: use octree here
696 double minDistance = 1.0e100;
697 DofManager *p = nullptr;
698 // loop over all particles (nodes in existing domain)
699 for ( int i = 1; i <= d->giveNumberOfDofManagers(); i++ ) {
700 double dist = distance(coords, d->giveDofManager(i)->giveCoordinates() );
701 if ( dist < minDistance ) {
702 minDistance = dist;
703 p = d->giveDofManager(i);
704 }
705 }
706 if ( p ) {
707 return p;
708 } else {
709 OOFEM_ERROR( "Neares particle for point [%f, %f] not found", coords.at(1), coords.at(2) );
710 return nullptr;
711 }
712}
713
714
716QClinearStatic :: giveFullSolvedDomain()
717{
718 return &Fullsolveddomain;
719}
720
721
722void
723QClinearStatic :: setActivatedNodeList(IntArray nodeList, Domain *d)
724{
725 this->activatedNodeList.clear();
726 this->activatedNodeList.resize(nodeList.giveSize(), false);
727 for ( int i = 1; i <= nodeList.giveSize(); i++ ) {
728 // if node is activated or master node
729 if ( ( nodeList.at(i) == 1 ) || ( d->giveNode(i)->giveQcNodeType() == 1 ) ) {
730 this->activatedNodeList [ i - 1 ] = true;
731 }
732 }
733}
734
735
736void
737QClinearStatic :: setActivatedElementList(IntArray elemList)
738{
739 this->activatedElementList.clear();
740 this->activatedElementList.resize(elemList.giveSize(), false);
741 for ( int i = 1; i <= elemList.giveSize(); i++ ) {
742 // if element is activated
743 if ( elemList.at(i) == 1 ) {
744 this->activatedElementList [ i - 1 ] = true;
745 }
746 }
747}
748
749} // end namespace oofem
#define REGISTER_EngngModel(class)
virtual double give(CrossSectionProperty a, GaussPoint *gp) const
int giveGlobalNumber() const
Definition dofmanager.h:515
double giveCoordinate(int i) const
Definition dofmanager.h:383
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
int giveNumberOfElements() const
Returns number of elements in domain.
Definition domain.h:463
int giveNumberOfDofManagers() const
Returns number of dof managers in domain.
Definition domain.h:461
DofManager * giveDofManager(int n)
Definition domain.C:317
Element * giveElement(int n)
Definition domain.C:165
int giveNumberOfSpatialDimensions()
Returns number of spatial dimensions.
Definition domain.C:1137
Node * giveNode(int n)
Definition domain.h:398
int giveGlobalNumber() const
Definition element.h:1129
virtual double computeVolumeAreaOrLength()
Computes the volume, area or length of the element depending on its spatial dimension.
Definition element.C:1081
virtual DofManager * giveInternalDofManager(int i) const
Definition element.h:249
virtual int giveNumberOfDofManagers() const
Definition element.h:695
CrossSection * giveCrossSection()
Definition element.C:534
int giveNumberOfProcesses() const
Returns the number of collaborating processes.
Definition engngm.h:1156
int giveRank() const
Returns domain rank in a group of collaborating processes (0..groupSize-1).
Definition engngm.h:1154
ProblemCommunicator * communicator
Communicator.
Definition engngm.h:315
Domain * giveDomain(int n)
Definition engngm.C:1936
CommunicatorBuff * commBuff
Common Communicator buffer.
Definition engngm.h:313
bool isParallel() const
Returns true if receiver in parallel mode.
Definition engngm.h:1152
int giveNumber() const
Definition femcmpnn.h:104
double computeNorm() const
Definition floatarray.C:861
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
void initializeLinkGenerator(InputRecord &ir)
void initializeParticleGenerator(InputRecord &ir)
void resize(int n)
Definition intarray.C:73
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
LinearStatic(int i, EngngModel *master=nullptr)
virtual int giveQcNodeType()
Definition node.h:177
FloatArray FullSolvedDomainNodes
virtual double computeTotalVolumeOfInterpolationMesh(Domain *d)
std::vector< bool > activatedElementList
virtual std::vector< IntArray > transformMeshToParticles(Domain *d, std::vector< FloatArray > &nodeCoords, std::vector< IntArray > &meshNodes)
virtual std::vector< IntArray > loadInterpolationMesh(Domain *d)
QuasicontinuumNumberingscheme qcEquationNumbering
virtual bool nodeInFullSolvedDomainTest(Node *n)
FloatArray FullSolvedDomainRadius
std::vector< bool > activatedNodeList
FloatArray FullSolvedDomainElements
QCFullsolveddomain Fullsolveddomain
virtual void initializeFullSolvedDomain(InputRecord &ir)
virtual void setRepNodesInVerticesOfInterpolationMesh(Domain *d)
virtual std::vector< IntArray > generateInterpolationMesh(Domain *d)
virtual DofManager * findNearestParticle(Domain *d, FloatArray coords)
std::vector< IntArray > interpolationMeshNodes
virtual void createInterpolationMeshNodes(Domain *d)
FloatArray displacementVector
void createInterpolationElements(Domain *d)
void applyApproach1(Domain *d)
void applyApproach3(Domain *d, int homMtrxType)
void setNoDimensions(Domain *d)
void setupInterpolationMesh(Domain *d, int generateInterpolationElements, int interpolationElementsMaterialNumber, std::vector< IntArray > &newMeshNodes)
void applyApproach2(Domain *d, int homMtrxType, double volumeOfInterpolationMesh)
void addCrosssectionToInterpolationElements(Domain *d)
int createQCInterpolationMesh(const char *t3dOutFile, std::vector< FloatArray > &nodeCoords, std::vector< IntArray > &cellNodes, IntArray &cellTypes)
virtual void setAsHanging()
Definition qcnode.C:263
int giveQcNodeType() override
Definition qcnode.h:102
virtual void setAsRepnode()
Definition qcnode.C:255
#define OOFEM_WARNING(...)
Definition error.h:80
#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
@ CS_Thickness
Thickness.
double distance(const FloatArray &x, const FloatArray &y)
#define _IFT_FullSolvedDomain_box
#define _IFT_QuasiContinuum_t3d_File_Name
#define _IFT_QuasiContinuum_generate_Particles
#define _IFT_QuasiContinuum_T3D_Interpolation_Mesh_size
#define _IFT_QuasiContinuum_mtrx_type
#define _IFT_QuasiContinuum_generate_Links
#define _IFT_FullSolvedDomain_elements
#define _IFT_FullSolvedDomain_nodes
#define _IFT_QuasiContinuum_approach
#define _IFT_QuasiContinuum_interp_Mat_Number
#define _IFT_QuasiContinuum_generate_Interpolation_Elements
#define _IFT_FullSolvedDomain_radius

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