OOFEM 3.0
Loading...
Searching...
No Matches
fei2dquadlin.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 "fei2dquadlin.h"
36#include "mathfem.h"
37#include "floatmatrix.h"
38#include "floatarray.h"
39#include "floatmatrixf.h"
40#include "floatarrayf.h"
42
43namespace oofem {
44double
45FEI2dQuadLin :: giveArea(const FEICellGeometry &cellgeo) const
46{
47 const auto &node1 = cellgeo.giveVertexCoordinates(1);
48 const auto &node2 = cellgeo.giveVertexCoordinates(2);
49 const auto &node3 = cellgeo.giveVertexCoordinates(3);
50 const auto &node4 = cellgeo.giveVertexCoordinates(4);
51
52 double x13 = node1.at(xind) - node3.at(xind);
53 double y13 = node1.at(yind) - node3.at(yind);
54 double x24 = node2.at(xind) - node4.at(xind);
55 double y24 = node2.at(yind) - node4.at(yind);
56
57 return fabs( 0.5 * ( x13 * y24 - x24 * y13 ) );
58}
59
61FEI2dQuadLin :: evalN(const FloatArrayF<2> &lcoords)
62{
63 double ksi = lcoords[0];
64 double eta = lcoords[1];
65
66 return {
67 ( 1. + ksi ) * ( 1. + eta ) * 0.25,
68 ( 1. - ksi ) * ( 1. + eta ) * 0.25,
69 ( 1. - ksi ) * ( 1. - eta ) * 0.25,
70 ( 1. + ksi ) * ( 1. - eta ) * 0.25
71 };
72}
73
74void
75FEI2dQuadLin :: evalN(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
76{
77 answer = evalN({lcoords[0], lcoords[1]});
78}
79
80std::pair<double, FloatMatrixF<2,4>>
81FEI2dQuadLin :: evaldNdx(const FloatArrayF<2> &lcoords, const FEICellGeometry &cellgeo) const
82{
83 auto dndu = this->evaldNdxi(lcoords);
84
86 for ( std::size_t i = 0; i < dndu.cols(); i++ ) {
87 double x = cellgeo.giveVertexCoordinates(i+1).at(xind);
88 double y = cellgeo.giveVertexCoordinates(i+1).at(yind);
89
90 jacT(0, 0) += dndu(0, i) * x;
91 jacT(0, 1) += dndu(0, i) * y;
92 jacT(1, 0) += dndu(1, i) * x;
93 jacT(1, 1) += dndu(1, i) * y;
94 }
95 return {det(jacT), dot(inv(jacT), dndu)};
96}
97
98double
99FEI2dQuadLin :: evaldNdx(FloatMatrix &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
100{
101 auto tmp = evaldNdx(lcoords, cellgeo);
102 answer = transpose(tmp.second);
103 return tmp.first;
104}
105
106void
107FEI2dQuadLin :: local2global(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
108{
109 double ksi = lcoords.at(1);
110 double eta = lcoords.at(2);
111
112 double n1 = ( 1. + ksi ) * ( 1. + eta ) * 0.25;
113 double n2 = ( 1. - ksi ) * ( 1. + eta ) * 0.25;
114 double n3 = ( 1. - ksi ) * ( 1. - eta ) * 0.25;
115 double n4 = ( 1. + ksi ) * ( 1. - eta ) * 0.25;
116
117 const auto &p1 = cellgeo.giveVertexCoordinates(1);
118 const auto &p2 = cellgeo.giveVertexCoordinates(2);
119 const auto &p3 = cellgeo.giveVertexCoordinates(3);
120 const auto &p4 = cellgeo.giveVertexCoordinates(4);
121
122 answer = Vec2(n1 * p1.at(xind) + n2 * p2.at(xind) +
123 n3 * p3.at(xind) + n4 * p4.at(xind),
124 n1 * p1.at(yind) + n2 * p2.at(yind) +
125 n3 * p3.at(yind) + n4 * p4.at(yind));
126}
127
128#define POINT_TOL 1.e-6
129
130int
131FEI2dQuadLin :: global2local(FloatArray &answer, const FloatArray &coords, const FEICellGeometry &cellgeo) const
132{
133 double x1, x2, x3, x4, y1, y2, y3, y4, a1, a2, a3, a4, b1, b2, b3, b4;
134 double a, b, c, ksi1, ksi2, ksi3, eta1 = 0.0, eta2 = 0.0, denom;
135 int nroot;
136
137 answer.resize(2);
138
139 x1 = cellgeo.giveVertexCoordinates(1).at(xind);
140 x2 = cellgeo.giveVertexCoordinates(2).at(xind);
141 x3 = cellgeo.giveVertexCoordinates(3).at(xind);
142 x4 = cellgeo.giveVertexCoordinates(4).at(xind);
143
144 y1 = cellgeo.giveVertexCoordinates(1).at(yind);
145 y2 = cellgeo.giveVertexCoordinates(2).at(yind);
146 y3 = cellgeo.giveVertexCoordinates(3).at(yind);
147 y4 = cellgeo.giveVertexCoordinates(4).at(yind);
148
149 a1 = x1 + x2 + x3 + x4;
150 a2 = x1 - x2 - x3 + x4;
151 a3 = x1 + x2 - x3 - x4;
152 a4 = x1 - x2 + x3 - x4;
153
154 b1 = y1 + y2 + y3 + y4;
155 b2 = y1 - y2 - y3 + y4;
156 b3 = y1 + y2 - y3 - y4;
157 b4 = y1 - y2 + y3 - y4;
158
159 a = a2 * b4 - b2 * a4;
160 b = a1 * b4 + a2 * b3 - a3 * b2 - b1 * a4 - b4 * 4.0 * coords.at(xind) + a4 * 4.0 * coords.at(yind);
161 c = a1 * b3 - a3 * b1 - 4.0 * coords.at(xind) * b3 + 4.0 * coords.at(yind) * a3;
162
163 // solve quadratic equation for ksi
164 cubic(0.0, a, b, c, & ksi1, & ksi2, & ksi3, & nroot);
165
166 if ( nroot == 0 ) {
167 answer.zero();
168 return false;
169 }
170
171 if ( nroot ) {
172 denom = ( b3 + ksi1 * b4 );
173 if ( fabs(denom) <= 1.0e-10 ) {
174 eta1 = ( 4.0 * coords.at(xind) - a1 - ksi1 * a2 ) / ( a3 + ksi1 * a4 );
175 } else {
176 eta1 = ( 4.0 * coords.at(yind) - b1 - ksi1 * b2 ) / denom;
177 }
178 }
179
180 if ( nroot > 1 ) {
181 double diff_ksi1, diff_eta1, diff_ksi2, diff_eta2, diff1, diff2;
182
183 denom = b3 + ksi2 * b4;
184 if ( fabs(denom) <= 1.0e-10 ) {
185 eta2 = ( 4.0 * coords.at(xind) - a1 - ksi2 * a2 ) / ( a3 + ksi2 * a4 );
186 } else {
187 eta2 = ( 4.0 * coords.at(yind) - b1 - ksi2 * b2 ) / denom;
188 }
189
190 // choose the one which seems to be closer to the parametric space (square <-1;1>x<-1;1>)
191 diff_ksi1 = 0.0;
192 if ( ksi1 > 1.0 ) {
193 diff_ksi1 = ksi1 - 1.0;
194 }
195
196 if ( ksi1 < -1.0 ) {
197 diff_ksi1 = ksi1 + 1.0;
198 }
199
200 diff_eta1 = 0.0;
201 if ( eta1 > 1.0 ) {
202 diff_eta1 = eta1 - 1.0;
203 }
204
205 if ( eta1 < -1.0 ) {
206 diff_eta1 = eta1 + 1.0;
207 }
208
209 diff_ksi2 = 0.0;
210 if ( ksi2 > 1.0 ) {
211 diff_ksi2 = ksi2 - 1.0;
212 }
213
214 if ( ksi2 < -1.0 ) {
215 diff_ksi2 = ksi2 + 1.0;
216 }
217
218 diff_eta2 = 0.0;
219 if ( eta2 > 1.0 ) {
220 diff_eta2 = eta2 - 1.0;
221 }
222
223 if ( eta2 < -1.0 ) {
224 diff_eta2 = eta2 + 1.0;
225 }
226
227 diff1 = diff_ksi1 * diff_ksi1 + diff_eta1 * diff_eta1;
228 diff2 = diff_ksi2 * diff_ksi2 + diff_eta2 * diff_eta2;
229
230 // ksi2, eta2 seems to be closer
231 if ( diff1 > diff2 ) {
232 ksi1 = ksi2;
233 eta1 = eta2;
234 }
235 }
236
237 answer.at(1) = ksi1;
238 answer.at(2) = eta1;
239
240 // test if inside
241 bool inside = true;
242 for ( int i = 1; i <= 2; i++ ) {
243 if ( answer.at(i) < ( -1. - POINT_TOL ) ) {
244 answer.at(i) = -1.;
245 inside = false;
246 } else if ( answer.at(i) > ( 1. + POINT_TOL ) ) {
247 answer.at(i) = 1.;
248 inside = false;
249 }
250 }
251
252 return inside;
253}
254
255void
256FEI2dQuadLin :: edgeEvalN(FloatArray &answer, int iedge, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
257{
258 double ksi = lcoords.at(1);
259 answer = Vec2( ( 1. - ksi ) * 0.5, ( 1. + ksi ) * 0.5 );
260}
261
262double
263FEI2dQuadLin :: edgeEvalNormal(FloatArray &answer, int iedge, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
264{
265 const auto &edgeNodes = this->computeLocalEdgeMapping(iedge);
266 int nodeA = edgeNodes.at(1);
267 int nodeB = edgeNodes.at(2);
268
269 answer = Vec2(
270 cellgeo.giveVertexCoordinates(nodeB).at(yind) - cellgeo.giveVertexCoordinates(nodeA).at(yind),
271 cellgeo.giveVertexCoordinates(nodeA).at(xind) - cellgeo.giveVertexCoordinates(nodeB).at(xind)
272 );
273 return answer.normalize_giveNorm() * 0.5;
274}
275
276void
277FEI2dQuadLin :: edgeEvaldNds(FloatArray &answer, int iedge,
278 const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
279{
280 const auto &edgeNodes = this->computeLocalEdgeMapping(iedge);
281 double l = this->edgeComputeLength(edgeNodes, cellgeo);
282
283 answer = Vec2( -1.0 / l, 1.0 / l );
284}
285
286void
287FEI2dQuadLin :: edgeLocal2global(FloatArray &answer, int iedge,
288 const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
289{
290 FloatArray n;
291 const auto &edgeNodes = this->computeLocalEdgeMapping(iedge);
292 this->edgeEvalN(n, iedge, lcoords, cellgeo);
293
294 answer.resize(2);
295 answer.at(1) = n.at(1) * cellgeo.giveVertexCoordinates( edgeNodes.at(1) ).at(xind) +
296 n.at(2) * cellgeo.giveVertexCoordinates( edgeNodes.at(2) ).at(xind);
297 answer.at(2) = n.at(1) * cellgeo.giveVertexCoordinates( edgeNodes.at(1) ).at(yind) +
298 n.at(2) * cellgeo.giveVertexCoordinates( edgeNodes.at(2) ).at(yind);
299}
300
302FEI2dQuadLin :: computeLocalEdgeMapping(int iedge) const
303{
304 if ( iedge == 1 ) { // edge between nodes 1 2
305 return {1, 2};
306 } else if ( iedge == 2 ) { // edge between nodes 2 3
307 return {2, 3};
308 } else if ( iedge == 3 ) { // edge between nodes 3 4
309 return {3, 4};
310 } else if ( iedge == 4 ) { // edge between nodes 4 1
311 return {4, 1};
312 } else {
313 throw std::range_error("invalid edge number");
314 //return {};
315 }
316}
317
318double
319FEI2dQuadLin :: edgeComputeLength(const IntArray &edgeNodes, const FEICellGeometry &cellgeo) const
320{
321 int nodeA = edgeNodes.at(1);
322 int nodeB = edgeNodes.at(2);
323
324 double dx = cellgeo.giveVertexCoordinates(nodeB).at(xind) - cellgeo.giveVertexCoordinates(nodeA).at(xind);
325 double dy = cellgeo.giveVertexCoordinates(nodeB).at(yind) - cellgeo.giveVertexCoordinates(nodeA).at(yind);
326 return sqrt(dx * dx + dy * dy);
327}
328
329
330bool FEI2dQuadLin :: inside(const FloatArray &lcoords) const
331{
332 const double point_tol = 1.0e-3;
333 bool inside = true;
334 for ( int i = 1; i <= 2; i++ ) {
335 if ( lcoords.at(i) < ( -1. - point_tol ) ) {
336 inside = false;
337 } else if ( lcoords.at(i) > ( 1. + point_tol ) ) {
338 inside = false;
339 }
340 }
341
342 return inside;
343}
344
345FloatMatrixF<2,4> FEI2dQuadLin :: evaldNdxi(const FloatArrayF<2> &lcoords)
346{
347 const double &ksi = lcoords[0];
348 const double &eta = lcoords[1];
349
350 FloatMatrixF<2,4> answer;
351 // dn/dxi
352 answer.at(1, 1) = 0.25 * ( 1. + eta );
353 answer.at(1, 2) = -0.25 * ( 1. + eta );
354 answer.at(1, 3) = -0.25 * ( 1. - eta );
355 answer.at(1, 4) = 0.25 * ( 1. - eta );
356
357 // dn/deta
358 answer.at(2, 1) = 0.25 * ( 1. + ksi );
359 answer.at(2, 2) = 0.25 * ( 1. - ksi );
360 answer.at(2, 3) = -0.25 * ( 1. - ksi );
361 answer.at(2, 4) = -0.25 * ( 1. + ksi );
362 return answer;
363}
364
365void FEI2dQuadLin :: evaldNdxi(FloatMatrix &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
366{
367 answer = transpose(evaldNdxi({lcoords[0], lcoords[1]}));
368}
369
370double FEI2dQuadLin :: evalNXIntegral(int iEdge, const FEICellGeometry &cellgeo) const
371{
372 const auto &eNodes = this->computeLocalEdgeMapping(iEdge);
373
374 const auto &node1 = cellgeo.giveVertexCoordinates( eNodes.at(1) );
375 double x1 = node1.at(xind);
376 double y1 = node1.at(yind);
377
378 const auto &node2 = cellgeo.giveVertexCoordinates( eNodes.at(2) );
379 double x2 = node2.at(xind);
380 double y2 = node2.at(yind);
381
382 return -( x2 * y1 - x1 * y2 );
383}
384
385std::unique_ptr<IntegrationRule>
386FEI2dQuadLin :: giveIntegrationRule(int order, Element_Geometry_Type egt) const
387{
388 auto iRule = std::make_unique<GaussIntegrationRule>(1, nullptr);
389 int points = iRule->getRequiredNumberOfIntegrationPoints(_Square, order + 2);
390 iRule->SetUpPointsOnSquare(points, _Unknown);
391 return std::move(iRule);
392}
393
394
395/*
396 * FEI2dQuadlinAxi element
397 */
398double
399FEI2dQuadLinAxi :: giveTransformationJacobian(const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
400{
402 this->evalN( N, lcoords, cellgeo);
403
404 double r = 0.0;
405 for ( int i = 1; i <= 4; i++ ) {
406 double x = cellgeo.giveVertexCoordinates(i).at(1);
407 r += x * N.at(i);
408 }
409
410 return r * FEI2dQuadLin::giveTransformationJacobian(lcoords, cellgeo);
411}
412
413double
415 const FEICellGeometry &cellgeo) const
416{
417 FloatArray n;
418 const auto &edgeNodes = this->computeLocalEdgeMapping(iedge);
419 this->edgeEvalN(n, iedge, lcoords, cellgeo);
420
421 double r = n.at(1)*cellgeo.giveVertexCoordinates(edgeNodes.at(1)).at(1) + n.at(2)*cellgeo.giveVertexCoordinates(edgeNodes.at(2)).at(1);
422 return r * FEI2dQuadLin::edgeGiveTransformationJacobian(iedge, lcoords, cellgeo);
423}
424
425double
427{
428 return this->edgeGiveTransformationJacobian(boundary, lcoords, cellgeo);
429}
430
431double
432FEI2dQuadLinAxi::boundaryGiveTransformationJacobian(int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
433{
434 return this->edgeGiveTransformationJacobian(boundary, lcoords, cellgeo);
435}
436
437} // end namespace oofem
#define N(a, b)
double boundaryEdgeGiveTransformationJacobian(int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
double edgeGiveTransformationJacobian(int iedge, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
double boundaryGiveTransformationJacobian(int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
std::pair< double, FloatMatrixF< 2, 4 > > evaldNdx(const FloatArrayF< 2 > &lcoords, const FEICellGeometry &cellgeo) const
double edgeComputeLength(const IntArray &edgeNodes, const FEICellGeometry &cellgeo) const
static FloatMatrixF< 2, 4 > evaldNdxi(const FloatArrayF< 2 > &lcoords)
static FloatArrayF< 4 > evalN(const FloatArrayF< 2 > &lcoords)
bool inside(const FloatArray &lcoords) const override
IntArray computeLocalEdgeMapping(int iedge) const override
void edgeEvalN(FloatArray &answer, int iedge, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const override
virtual const FloatArray giveVertexCoordinates(int i) const =0
virtual double edgeGiveTransformationJacobian(int iedge, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
virtual double giveTransformationJacobian(const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
Definition feinterpol.C:81
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
double normalize_giveNorm()
Definition floatarray.C:850
double at(std::size_t i, std::size_t j) const
int & at(std::size_t i)
Definition intarray.h:104
#define POINT_TOL
static FloatArray Vec2(const double &a, const double &b)
Definition floatarray.h:606
FloatMatrixF< M, N > transpose(const FloatMatrixF< N, M > &mat)
Constructs transposed matrix.
double det(const FloatMatrixF< 2, 2 > &mat)
Computes the determinant.
double dot(const FloatArray &x, const FloatArray &y)
void cubic(double a, double b, double c, double d, double *r1, double *r2, double *r3, int *num)
Definition mathfem.C:43
FloatMatrixF< N, N > inv(const FloatMatrixF< N, N > &mat, double zeropiv=1e-24)
Computes the inverse.

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