OOFEM 3.0
Loading...
Searching...
No Matches
feibspline.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 "floatarray.h"
36#include "floatmatrix.h"
37#include "iga.h"
38#include "feibspline.h"
39#include "mathfem.h"
40#include "parametermanager.h"
41#include "paramkey.h"
42
43namespace oofem {
44
52
53
54
55void
56BSplineInterpolation :: initializeFrom(InputRecord &ir, ParameterManager&pm, int elnum, int priority)
57{
58 bool flag;
59 IntArray degree_tmp;
60 PM_UPDATE_PARAMETER_AND_REPORT(degree_tmp, pm, ir, elnum, IPK_BSplineInterpolation_degree, priority, flag);
61 if (flag) {
62 if ( degree_tmp.giveSize() != nsd ) {
63 throw ValueInputException(ir, _IFT_BSplineInterpolation_degree, "degree size mismatch");
64 }
65
66 for ( int i = 0; i < nsd; i++ ) {
67 degree [ i ] = degree_tmp.at(i + 1);
68 }
69 }
72
73 if (nsd>1) {
76 }
77
78 if (nsd >2) {
81 }
82
83}
84
85void
87{
88 ParamKey* IPK_knotVector [ 3 ] = {
92 };
93
94 ParamKey* IPK_knotMultiplicity [ 3 ] = {
98 };
99
100 for ( int n = 0; n < nsd; n++ ) {
101 //IR_GIVE_FIELD(ir, knotValues [ n ], IFT_knotVector [ n ]);
102 int size = knotValues [ n ].giveSize();
103 if ( size < 2 ) {
104 throw ComponentInputException(IPK_knotVector[n]->getName(), ComponentInputException::ComponentType::ctElement, elnum, "invalid size of knot vector");
105 }
106
107 // check for monotonicity of knot vector without multiplicity
108 double knotVal = knotValues [ n ].at(1);
109 for ( int i = 1; i < size; i++ ) {
110 if ( knotValues [ n ].at(i + 1) <= knotVal ) {
111 throw ComponentInputException(IPK_knotVector [ n ]->getName(), ComponentInputException::ComponentType::ctElement, elnum, "knot vector is not monotonic");
112 }
113
114 knotVal = knotValues [ n ].at(i + 1);
115 }
116
117 // transform knot vector to interval <0;1>
118 double span = knotVal - knotValues [ n ].at(1);
119 for ( int i = 1; i <= size; i++ ) {
120 knotValues [ n ].at(i) /= span;
121 }
122
123 //IR_GIVE_OPTIONAL_FIELD(ir, knotMultiplicity [ n ], IFT_knotMultiplicity [ n ]);
124 if ( knotMultiplicity [ n ].giveSize() == 0 ) {
125 // default multiplicity
126 knotMultiplicity [ n ].resize(size);
127 // skip the first and last one
128 for ( int i = 1; i < size - 1; i++ ) {
129 knotMultiplicity [ n ].at(i + 1) = 1;
130 }
131 } else {
132 if ( knotMultiplicity [ n ].giveSize() != size ) {
133 throw ComponentInputException(IPK_knotMultiplicity [ n ]->getName(), ComponentInputException::ComponentType::ctElement, elnum, "knot multiplicity size mismatch");
134 }
135
136 // check for multiplicity range (skip the first and last one)
137 for ( int i = 1; i < size - 1; i++ ) {
138 if ( knotMultiplicity [ n ].at(i + 1) < 1 || knotMultiplicity [ n ].at(i + 1) > degree [ n ] ) {
139 throw ComponentInputException(IPK_knotMultiplicity [ n ]->getName(), ComponentInputException::ComponentType::ctElement, elnum, "knot multiplicity out of range");
140 }
141 }
142
143 // check for multiplicity of the first and last one
144 if ( knotMultiplicity [ n ].at(1) != degree [ n ] + 1 ) {
145 OOFEM_LOG_RELEVANT("Multiplicity of the first knot in knot vector %s changed to %d\n", IPK_knotVector [ n ]->getNameCStr(), degree [ n ] + 1);
146 }
147
148 if ( knotMultiplicity [ n ].at(size) != degree [ n ] + 1 ) {
149 OOFEM_LOG_RELEVANT("Multiplicity of the last knot in knot vector %s changed to %d\n", IPK_knotVector [ n ]->getNameCStr(), degree [ n ] + 1);
150 }
151 }
152
153 // multiplicity of the 1st and last knot set to degree + 1
154 knotMultiplicity [ n ].at(1) = knotMultiplicity [ n ].at(size) = degree [ n ] + 1;
155
156 // sum the size of knot vector with multiplicity values
157 int sum = 0;
158 for ( int i = 0; i < size; i++ ) {
159 sum += knotMultiplicity [ n ][i];
160 }
161
162 knotVector [ n ].resize( sum );
163
164 // fill knot vector including multiplicity values
165 int pos = 0;
166 for ( int i = 0; i < size; i++ ) {
167 for ( int j = 0; j < knotMultiplicity [ n ].at(i + 1); j++ ) {
168 knotVector [ n ] [ pos++ ] = knotValues [ n ].at(i + 1);
169 }
170 }
171
172 numberOfKnotSpans [ n ] = size - 1;
173 numberOfControlPoints [ n ] = sum - degree [ n ] - 1;
174 }
175}
176void BSplineInterpolation :: evalN(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
177{
178 const FEIIGAElementGeometryWrapper &gw = static_cast< const FEIIGAElementGeometryWrapper& >(cellgeo);
179 IntArray span(nsd);
180 int c = 1;
181 std :: vector< FloatArray > N(nsd);
182
183 if ( gw.knotSpan ) {
184 span = * gw.knotSpan;
185 } else {
186 for ( int i = 0; i < nsd; i++ ) {
187 span[i] = this->findSpan(numberOfControlPoints [ i ], degree [ i ], lcoords[i], knotVector [ i ]);
188 }
189 }
190
191 for ( int i = 0; i < nsd; i++ ) {
192 this->basisFuns(N [ i ], span[i], lcoords[i], degree [ i ], knotVector [ i ]);
193 }
194
196
197 if ( nsd == 1 ) {
198 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
199 answer.at(c++) = N [ 0 ][k];
200 }
201 } else if ( nsd == 2 ) {
202 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
203 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
204 answer.at(c++) = N [ 0 ][k] * N [ 1 ][l];
205 }
206 }
207 } else if ( nsd == 3 ) {
208 for ( int m = 0; m <= degree [ 2 ]; m++ ) {
209 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
210 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
211 answer.at(c++) = N [ 0 ][k] * N [ 1 ][l] * N [ 2 ][m];
212 }
213 }
214 }
215 } else {
216 OOFEM_ERROR("evalN not implemented for nsd = %d", nsd);
217 }
218}
219
220
221double BSplineInterpolation :: evaldNdx(FloatMatrix &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
222{
223 const FEIIGAElementGeometryWrapper &gw = static_cast< const FEIIGAElementGeometryWrapper& >(cellgeo);
224 FloatMatrix jacobian(nsd, nsd);
225 IntArray span(nsd);
226 double Jacob = 0.;
227 std :: vector< FloatMatrix > ders(nsd);
228
229 if ( gw.knotSpan ) {
230 span = * gw.knotSpan;
231 } else {
232 for ( int i = 0; i < nsd; i++ ) {
233 span[i] = this->findSpan(numberOfControlPoints [ i ], degree [ i ], lcoords[i], knotVector [ i ]);
234 }
235 }
236
237 for ( int i = 0; i < nsd; i++ ) {
238 this->dersBasisFuns(1, lcoords[i], span[i], degree [ i ], knotVector [ i ], ders [ i ]);
239 }
240
241 int count = giveNumberOfKnotSpanBasisFunctions(span);
242 answer.resize(count, nsd);
243 jacobian.zero();
244
245 if ( nsd == 1 ) {
246 int uind = span[0] - degree [ 0 ];
247 int ind = uind + 1;
248 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
249 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
250 jacobian(0, 0) += ders [ 0 ](1, k) * vertexCoords[0]; // dx/du=sum(dNu/du*x)
251 }
252
253 Jacob = jacobian.giveDeterminant();
254
255 if ( fabs(Jacob) < 1.0e-10 ) {
256 OOFEM_ERROR("evaldNdx - zero Jacobian");
257 }
258
259 int cnt = 0;
260 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
261 answer(cnt, 0) = ders [ 0 ](1, k) / Jacob; // dN/dx=dN/du / dx/du
262 cnt++;
263 }
264 } else if ( nsd == 2 ) {
265 FloatArray tmp1(nsd), tmp2(nsd);
266
267 int uind = span[0] - degree [ 0 ];
268 int vind = span[1] - degree [ 1 ];
269 int ind = vind * numberOfControlPoints [ 0 ] + uind + 1;
270 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
271 tmp1.zero();
272 tmp2.zero();
273 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
274 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
275
276 tmp1[0] += ders [ 0 ](1, k) * vertexCoords[0]; // sum(dNu/du*x)
277 tmp1[1] += ders [ 0 ](1, k) * vertexCoords[1]; // sum(dNu/du*y)
278
279 tmp2[0] += ders [ 0 ](0, k) * vertexCoords[0]; // sum(Nu*x)
280 tmp2[1] += ders [ 0 ](0, k) * vertexCoords[1]; // sum(Nu*y)
281 }
282
283 ind += numberOfControlPoints [ 0 ];
284
285 jacobian(0, 0) += ders [ 1 ](0, l) * tmp1[0]; // dx/du=sum(Nv*sum(dNu/du*x))
286 jacobian(0, 1) += ders [ 1 ](0, l) * tmp1[1]; // dy/du=sum(Nv*sum(dNu/du*y))
287
288 jacobian(1, 0) += ders [ 1 ](1, l) * tmp2[0]; // dx/dv=sum(dNv/dv*sum(Nu*x))
289 jacobian(1, 1) += ders [ 1 ](1, l) * tmp2[1]; // dy/dv=sum(dNv/dv*sum(Nu*y))
290 }
291
292 Jacob = jacobian.giveDeterminant();
293
294 if ( fabs(Jacob) < 1.0e-10 ) {
295 OOFEM_ERROR("evaldNdx - zero Jacobian");
296 }
297
298 int cnt = 0;
299 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
300 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
301 tmp1[0] = ders [ 0 ](1, k) * ders [ 1 ](0, l); // dN/du=dNu/du*Nv
302 tmp1[1] = ders [ 0 ](0, k) * ders [ 1 ](1, l); // dN/dv=Nu*dNv/dv
303 answer(cnt, 0) = ( +jacobian(1, 1) * tmp1[0] - jacobian(0, 1) * tmp1[1] ) / Jacob; // dN/dx
304 answer(cnt, 1) = ( -jacobian(1, 0) * tmp1[0] + jacobian(0, 0) * tmp1[1] ) / Jacob; // dN/dy
305 cnt++;
306 }
307 }
308 } else if ( nsd == 3 ) {
309 FloatArray tmp1(nsd), tmp2(nsd);
310 FloatArray temp1(nsd), temp2(nsd), temp3(nsd);
311
312 int uind = span[0] - degree [ 0 ];
313 int vind = span[1] - degree [ 1 ];
314 int tind = span[2] - degree [ 2 ];
315 int ind = tind * numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ] + vind * numberOfControlPoints [ 0 ] + uind + 1;
316 for ( int m = 0; m <= degree [ 2 ]; m++ ) {
317 temp1.zero();
318 temp2.zero();
319 temp3.zero();
320 int indx = ind;
321 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
322 tmp1.zero();
323 tmp2.zero();
324 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
325 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
326
327 tmp1[0] += ders [ 0 ](1, k) * vertexCoords[0]; // sum(dNu/du*x)
328 tmp1[1] += ders [ 0 ](1, k) * vertexCoords[1]; // sum(dNu/du*y)
329 tmp1[2] += ders [ 0 ](1, k) * vertexCoords[2]; // sum(dNu/du*z)
330
331 tmp2[0] += ders [ 0 ](0, k) * vertexCoords[0]; // sum(Nu*x)
332 tmp2[1] += ders [ 0 ](0, k) * vertexCoords[1]; // sum(Nu*y)
333 tmp2[2] += ders [ 0 ](0, k) * vertexCoords[2]; // sum(Nu*y)
334 }
335
336 ind += numberOfControlPoints [ 0 ];
337
338 temp1[0] += ders [ 1 ](0, l) * tmp1[0]; // sum(Nv*sum(dNu/du*x))
339 temp1[1] += ders [ 1 ](0, l) * tmp1[1]; // sum(Nv*sum(dNu/du*y))
340 temp1[2] += ders [ 1 ](0, l) * tmp1[2]; // sum(Nv*sum(dNu/du*z))
341
342 temp2[0] += ders [ 1 ](1, l) * tmp2[0]; // sum(dNv/dv*sum(Nu*x))
343 temp2[1] += ders [ 1 ](1, l) * tmp2[1]; // sum(dNv/dv*sum(Nu*y))
344 temp2[2] += ders [ 1 ](1, l) * tmp2[1]; // sum(dNv/dv*sum(Nu*z))
345
346 temp3[0] += ders [ 1 ](0, l) * tmp2[0]; // sum(Nv*sum(Nu*x))
347 temp3[1] += ders [ 1 ](0, l) * tmp2[1]; // sum(Nv*sum(Nu*y))
348 temp3[2] += ders [ 1 ](0, l) * tmp2[1]; // sum(Nv*sum(Nu*z))
349 }
350
351 ind = indx + numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ];
352
353 jacobian(0, 0) += ders [ 2 ](0, m) * temp1[0]; // dx/du=sum(Nt*sum(Nv*sum(dNu/du*x)))
354 jacobian(0, 1) += ders [ 2 ](0, m) * temp1[1]; // dy/du=sum(Nt*sum(Nv*sum(dNu/du*y)))
355 jacobian(0, 2) += ders [ 2 ](0, m) * temp1[2]; // dz/du=sum(Nt*sum(Nv*sum(dNu/du*z)))
356
357 jacobian(1, 0) += ders [ 2 ](0, m) * temp2[0]; // dx/dv=sum(Nt*sum(dNv/dv*sum(Nu*x)))
358 jacobian(1, 1) += ders [ 2 ](0, m) * temp2[1]; // dy/dv=sum(Nt*sum(dNv/dv*sum(Nu*y)))
359 jacobian(1, 2) += ders [ 2 ](0, m) * temp2[2]; // dz/dv=sum(Nt*sum(dNv/dv*sum(Nu*z)))
360
361 jacobian(2, 0) += ders [ 2 ](1, m) * temp3[0]; // dx/dt=sum(dNt/dt*sum(Nv*sum(Nu*x)))
362 jacobian(2, 1) += ders [ 2 ](1, m) * temp3[1]; // dy/dt=sum(dNt/dt*sum(Nv*sum(Nu*y)))
363 jacobian(2, 2) += ders [ 2 ](1, m) * temp3[2]; // dz/dt=sum(dNt/dt*sum(Nv*sum(Nu*z)))
364 }
365
366 Jacob = jacobian.giveDeterminant();
367
368 if ( fabs(Jacob) < 1.0e-10 ) {
369 OOFEM_ERROR("evaldNdx - zero Jacobian");
370 }
371
372 int cnt = 0;
373 for ( int m = 0; m <= degree [ 2 ]; m++ ) {
374 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
375 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
376 tmp1[0] = ders [ 0 ](1, k) * ders [ 1 ](0, l) * ders [ 2 ](0, m); // dN/du=dNu/du*Nv*Nt
377 tmp1[1] = ders [ 0 ](0, k) * ders [ 1 ](1, l) * ders [ 2 ](0, m); // dN/dv=Nu*dNv/dv*Nt
378 tmp1[2] = ders [ 0 ](0, k) * ders [ 1 ](0, l) * ders [ 2 ](1, m); // dN/dt=Nu*Nv*dNt/dt
379 answer(cnt, 0) = ( ( jacobian(1, 1) * jacobian(2, 2) - jacobian(1, 2) * jacobian(2, 1) ) * tmp1[0] +
380 ( jacobian(0, 2) * jacobian(2, 1) - jacobian(0, 1) * jacobian(2, 2) ) * tmp1[1] +
381 ( jacobian(0, 1) * jacobian(1, 2) - jacobian(0, 2) * jacobian(1, 1) ) * tmp1[2] ) / Jacob; // dN/dx
382 answer(cnt, 1) = ( ( jacobian(1, 2) * jacobian(2, 0) - jacobian(1, 0) * jacobian(2, 2) ) * tmp1[0] +
383 ( jacobian(0, 0) * jacobian(2, 2) - jacobian(0, 2) * jacobian(2, 0) ) * tmp1[1] +
384 ( jacobian(0, 2) * jacobian(1, 0) - jacobian(0, 0) * jacobian(1, 2) ) * tmp1[2] ) / Jacob; // dN/dy
385 answer(cnt, 2) = ( ( jacobian(1, 0) * jacobian(2, 1) - jacobian(1, 1) * jacobian(2, 0) ) * tmp1[0] +
386 ( jacobian(0, 1) * jacobian(2, 0) - jacobian(0, 0) * jacobian(2, 1) ) * tmp1[1] +
387 ( jacobian(0, 0) * jacobian(1, 1) - jacobian(0, 1) * jacobian(1, 0) ) * tmp1[2] ) / Jacob; // dN/dz
388 cnt++;
389 }
390 }
391 }
392 } else {
393 OOFEM_ERROR("evaldNdx not implemented for nsd = %d", nsd);
394 }
395
396 return Jacob;
397}
398
399
400void BSplineInterpolation :: local2global(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
401{
402 /* Based on SurfacePoint A3.5 implementation*/
403 const FEIIGAElementGeometryWrapper &gw = static_cast< const FEIIGAElementGeometryWrapper& >(cellgeo);
404 IntArray span(nsd);
405 std :: vector< FloatArray > N(nsd);
406
407
408 if ( gw.knotSpan ) {
409 span = * gw.knotSpan;
410 } else {
411 for ( int i = 0; i < nsd; i++ ) {
412 span[i] = this->findSpan(numberOfControlPoints [ i ], degree [ i ], lcoords[i], knotVector [ i ]);
413 }
414 }
415
416 for ( int i = 0; i < nsd; i++ ) {
417 this->basisFuns(N [ i ], span[i], lcoords[i], degree [ i ], knotVector [ i ]);
418 }
419
420 answer.resize(nsd);
421 answer.zero();
422
423 if ( nsd == 1 ) {
424 int uind = span[0] - degree [ 0 ];
425 int ind = uind + 1;
426 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
427 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
428 answer[0] += N [ 0 ][k] * vertexCoords[0];
429 }
430 } else if ( nsd == 2 ) {
431 FloatArray tmp(nsd);
432
433 int uind = span[0] - degree [ 0 ];
434 int vind = span[1] - degree [ 1 ];
435 int ind = vind * numberOfControlPoints [ 0 ] + uind + 1;
436 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
437 tmp.zero();
438 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
439 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
440
441 tmp[0] += N [ 0 ][k] * vertexCoords[0];
442 tmp[1] += N [ 0 ][k] * vertexCoords[1];
443 }
444
445 ind += numberOfControlPoints [ 0 ];
446
447 answer[0] += N [ 1 ][l] * tmp[0];
448 answer[1] += N [ 1 ][l] * tmp[1];
449 }
450 } else if ( nsd == 3 ) {
451 FloatArray tmp(nsd), temp(nsd);
452
453 int uind = span[0] - degree [ 0 ];
454 int vind = span[1] - degree [ 1 ];
455 int tind = span[2] - degree [ 2 ];
456 int ind = tind * numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ] + vind * numberOfControlPoints [ 0 ] + uind + 1;
457 for ( int m = 0; m <= degree [ 2 ]; m++ ) {
458 temp.zero();
459 int indx = ind;
460 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
461 tmp.zero();
462 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
463 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
464 tmp.add(N [ 0 ][k], vertexCoords);
465 }
466
467 ind += numberOfControlPoints [ 0 ];
468
469 temp.add(N [ 1 ][l], tmp);
470 }
471
472 ind = indx + numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ];
473
474 answer.add(N [ 2 ][m], temp);
475 }
476 } else {
477 OOFEM_ERROR("local2global not implemented for nsd = %d", nsd);
478 }
479}
480
481
482void BSplineInterpolation :: giveJacobianMatrixAt(FloatMatrix &jacobian, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const
483{
484 const FEIIGAElementGeometryWrapper &gw = static_cast< const FEIIGAElementGeometryWrapper& >(cellgeo);
485 IntArray span(nsd);
486 std :: vector< FloatMatrix > ders(nsd);
487 jacobian.resize(nsd, nsd);
488
489 if ( gw.knotSpan ) {
490 span = * gw.knotSpan;
491 } else {
492 for ( int i = 0; i < nsd; i++ ) {
493 span[i] = this->findSpan(numberOfControlPoints [ i ], degree [ i ], lcoords[i], knotVector [ i ]);
494 }
495 }
496
497 for ( int i = 0; i < nsd; i++ ) {
498 this->dersBasisFuns(1, lcoords[i], span[i], degree [ i ], knotVector [ i ], ders [ i ]);
499 }
500
501 jacobian.zero();
502
503 if ( nsd == 1 ) {
504 int uind = span[0] - degree [ 0 ];
505 int ind = uind + 1;
506 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
507 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
508 jacobian(0, 0) += ders [ 0 ](1, k) * vertexCoords[0]; // dx/du=sum(dNu/du*x)
509 }
510 } else if ( nsd == 2 ) {
511 FloatArray tmp1(nsd), tmp2(nsd);
512
513 int uind = span[0] - degree [ 0 ];
514 int vind = span[1] - degree [ 1 ];
515 int ind = vind * numberOfControlPoints [ 0 ] + uind + 1;
516 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
517 tmp1.zero();
518 tmp2.zero();
519 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
520 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
521
522 tmp1[0] += ders [ 0 ](1, k) * vertexCoords[0]; // sum(dNu/du*x)
523 tmp1[1] += ders [ 0 ](1, k) * vertexCoords[1]; // sum(dNu/du*y)
524
525 tmp2[0] += ders [ 0 ](0, k) * vertexCoords[0]; // sum(Nu*x)
526 tmp2[1] += ders [ 0 ](0, k) * vertexCoords[1]; // sum(Nu*y)
527 }
528
529 ind += numberOfControlPoints [ 0 ];
530
531 jacobian(0, 0) += ders [ 1 ](0, l) * tmp1[0]; // dx/du=sum(Nv*sum(dNu/du*x))
532 jacobian(0, 1) += ders [ 1 ](0, l) * tmp1[1]; // dy/du=sum(Nv*sum(dNu/du*y))
533
534 jacobian(1, 0) += ders [ 1 ](1, l) * tmp2[0]; // dx/dv=sum(dNv/dv*sum(Nu*x))
535 jacobian(1, 1) += ders [ 1 ](1, l) * tmp2[1]; // dy/dv=sum(dNv/dv*sum(Nu*y))
536 }
537 } else if ( nsd == 3 ) {
538 FloatArray tmp1(nsd), tmp2(nsd);
539 FloatArray temp1(nsd), temp2(nsd), temp3(nsd);
540
541 int uind = span[0] - degree [ 0 ];
542 int vind = span[1] - degree [ 1 ];
543 int tind = span[2] - degree [ 2 ];
544 int ind = tind * numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ] + vind * numberOfControlPoints [ 0 ] + uind + 1;
545 for ( int m = 0; m <= degree [ 2 ]; m++ ) {
546 temp1.zero();
547 temp2.zero();
548 temp3.zero();
549 int indx = ind;
550 for ( int l = 0; l <= degree [ 1 ]; l++ ) {
551 tmp1.zero();
552 tmp2.zero();
553 for ( int k = 0; k <= degree [ 0 ]; k++ ) {
554 const auto &vertexCoords = cellgeo.giveVertexCoordinates(ind + k);
555
556 tmp1.add(ders [ 0 ](1, k), vertexCoords); // sum(dNu/du*x)
557 tmp2.add(ders [ 0 ](0, k), vertexCoords); // sum(Nu*x)
558 }
559
560 ind += numberOfControlPoints [ 0 ];
561
562 temp1.add(ders [ 1 ](0, l), tmp1); // sum(Nv*sum(dNu/du*x)
563 temp2.add(ders [ 1 ](1, l), tmp2); // sum(dNv/dv*sum(Nu*x)
564 temp3.add(ders [ 1 ](0, l), tmp2); // sum(Nv*sum(Nu*x)
565 }
566
567 ind = indx + numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ];
568
569 jacobian(0, 0) += ders [ 2 ](0, m) * temp1[0]; // dx/du=sum(Nt*sum(Nv*sum(dNu/du*x)))
570 jacobian(0, 1) += ders [ 2 ](0, m) * temp1[1]; // dy/du=sum(Nt*sum(Nv*sum(dNu/du*y)))
571 jacobian(0, 2) += ders [ 2 ](0, m) * temp1[2]; // dz/du=sum(Nt*sum(Nv*sum(dNu/du*z)))
572
573 jacobian(1, 0) += ders [ 2 ](0, m) * temp2[0]; // dx/dv=sum(Nt*sum(dNv/dv*sum(Nu*x)))
574 jacobian(1, 1) += ders [ 2 ](0, m) * temp2[1]; // dy/dv=sum(Nt*sum(dNv/dv*sum(Nu*y)))
575 jacobian(1, 2) += ders [ 2 ](0, m) * temp2[2]; // dz/dv=sum(Nt*sum(dNv/dv*sum(Nu*z)))
576
577 jacobian(2, 0) += ders [ 2 ](1, m) * temp3[0]; // dx/dt=sum(dNt/dt*sum(Nv*sum(Nu*x)))
578 jacobian(2, 1) += ders [ 2 ](1, m) * temp3[1]; // dy/dt=sum(dNt/dt*sum(Nv*sum(Nu*y)))
579 jacobian(2, 2) += ders [ 2 ](1, m) * temp3[2]; // dz/dt=sum(dNt/dt*sum(Nv*sum(Nu*z)))
580 }
581 } else {
582 OOFEM_ERROR("giveTransformationJacobian not implemented for nsd = %d", nsd);
583 }
584}
585
586
587int BSplineInterpolation :: giveKnotSpanBasisFuncMask(const IntArray &knotSpan, IntArray &mask) const
588{
589 int c = 1;
590 int size = giveNumberOfKnotSpanBasisFunctions(knotSpan);
591 mask.resize(size);
592
593 if ( nsd == 1 ) {
594 for ( int i = 0; i <= degree [ 0 ]; i++ ) {
595 int iindx = ( i + knotSpan[0] - degree [ 0 ] );
596 mask.at(c++) = iindx + 1;
597 }
598 } else if ( nsd == 2 ) {
599 for ( int j = 0; j <= degree [ 1 ]; j++ ) {
600 int jindx = ( j + knotSpan[1] - degree [ 1 ] );
601 for ( int i = 0; i <= degree [ 0 ]; i++ ) {
602 int iindx = ( i + knotSpan[0] - degree [ 0 ] );
603 mask.at(c++) = jindx * numberOfControlPoints [ 0 ] + iindx + 1;
604 }
605 }
606 } else if ( nsd == 3 ) {
607 for ( int k = 0; k <= degree [ 2 ]; k++ ) {
608 int kindx = ( k + knotSpan[2] - degree [ 2 ] );
609 for ( int j = 0; j <= degree [ 1 ]; j++ ) {
610 int jindx = ( j + knotSpan[1] - degree [ 1 ] );
611 for ( int i = 0; i <= degree [ 0 ]; i++ ) {
612 int iindx = ( i + knotSpan[0] - degree [ 0 ] );
613 mask.at(c++) = kindx * numberOfControlPoints [ 0 ] * numberOfControlPoints [ 1 ] + jindx * numberOfControlPoints [ 0 ] + iindx + 1;
614 }
615 }
616 }
617 } else {
618 OOFEM_ERROR("not implemented for nsd = %d", nsd);
619 }
620 return 1;
621}
622
623
624// for pure Bspline the number of nonzero basis functions is the same for each knot span
625int BSplineInterpolation :: giveNumberOfKnotSpanBasisFunctions(const IntArray &knotSpan) const
626{
627 int answer = 1;
628 // there are always degree+1 nonzero basis functions on each knot span
630 for ( int i = 0; i < nsd; i++ ) {
631 answer *= ( degree [ i ] + 1 );
632 }
633
634 return answer;
635}
636
637
638// generally it is redundant to pass p and U as these data are part of BSplineInterpolation
639// and can be retrieved for given spatial dimension;
640// however in such a case this function could not be used for calculation on local knot vector of TSpline;
641// it is also redundant to pass the span which can be calculated
642// but we want to profit from knowing the span a priori
643
644void BSplineInterpolation :: basisFuns(FloatArray &N, int span, double u, int p, const FloatArray &U) const
645{
646 //
647 // Based on Algorithm A2.2 (p. 70)
648 //
649 FloatArray right(p + 1);
650 FloatArray left(p + 1);
651
652 N.resize(p + 1);
653 N[0] = 1.0;
654 for ( int j = 1; j <= p; j++ ) {
655 left[j] = u - U [ span + 1 - j ];
656 right[j] = U [ span + j ] - u;
657 double saved = 0.0;
658 for ( int r = 0; r < j; r++ ) {
659 double temp = N[r] / ( right(r + 1) + left(j - r) );
660 N[r] = saved + right(r + 1) * temp;
661 saved = left(j - r) * temp;
662 }
663
664 N[j] = saved;
665 }
666}
667
668
669// generally it is redundant to pass p and U as these data are part of BSplineInterpolation
670// and can be retrieved for given spatial dimension;
671// however in such a case this function could not be used for calculation on local knot vector of TSpline;
672// it is also redundant to pass the span which can be calculated
673// but we want to profit from knowing the span a priori
674
675void BSplineInterpolation :: dersBasisFuns(int n, double u, int span, int p, const FloatArray &U, FloatMatrix &ders) const
676{
677 //
678 // Based on Algorithm A2.3 (p. 72)
679 //
680 FloatArray left(p + 1);
681 FloatArray right(p + 1);
682 FloatMatrix ndu(p + 1, p + 1);
683
684 ders.resize(n + 1, p + 1);
685
686 ndu(0, 0) = 1.0;
687 for ( int j = 1; j <= p; j++ ) {
688 left[j] = u - U [ span + 1 - j ];
689 right[j] = U [ span + j ] - u;
690 double saved = 0.0;
691
692 for ( int r = 0; r < j; r++ ) {
693 // Lower triangle
694 ndu(j, r) = right(r + 1) + left(j - r);
695 double temp = ndu(r, j - 1) / ndu(j, r);
696 // Upper triangle
697 ndu(r, j) = saved + right(r + 1) * temp;
698 saved = left(j - r) * temp;
699 }
700
701 ndu(j, j) = saved;
702 }
703
704 for ( int j = 0; j <= p; j++ ) {
705 ders(0, j) = ndu(j, p);
706 }
707
708 // Compute the derivatives
709 FloatMatrix a(2, p + 1);
710 for ( int r = 0; r <= p; r++ ) {
711 int s1, s2;
712 s1 = 0;
713 s2 = 1; // alternate rows in array a
714 a(0, 0) = 1.0;
715 // Compute the kth derivative
716 for ( int k = 1; k <= n; k++ ) {
717 double d;
718 int rk, pk, j1, j2;
719 d = 0.0;
720 rk = r - k;
721 pk = p - k;
722
723 if ( r >= k ) {
724 a(s2, 0) = a(s1, 0) / ndu(pk + 1, rk);
725 d = a(s2, 0) * ndu(rk, pk);
726 }
727
728 if ( rk >= -1 ) {
729 j1 = 1;
730 } else {
731 j1 = -rk;
732 }
733
734 if ( r - 1 <= pk ) {
735 j2 = k - 1;
736 } else {
737 j2 = p - r;
738 }
739
740 for ( int j = j1; j <= j2; j++ ) {
741 a(s2, j) = ( a(s1, j) - a(s1, j - 1) ) / ndu(pk + 1, rk + j);
742 d += a(s2, j) * ndu(rk + j, pk);
743 }
744
745 if ( r <= pk ) {
746 a(s2, k) = -a(s1, k - 1) / ndu(pk + 1, r);
747 d += a(s2, k) * ndu(r, pk);
748 }
749
750 ders(k, r) = d;
751 std :: swap(s1, s2); // Switch rows
752 }
753 }
754
755 // Multiply through by the correct factors
756 int r = p;
757 for ( int k = 1; k <= n; k++ ) {
758 for ( int j = 0; j <= p; j++ ) {
759 ders(k, j) *= r;
760 }
761
762 r *= p - k;
763 }
764}
765
766
767
768// generally it is redundant to pass n, p and U as these data are part of BSplineInterpolation
769// and can be retrieved for given spatial dimension;
770// however in such a case this function could not be used for span localization in local knot vector of TSpline
771
772// jaky ma vyznam const = ve funkci se objekt nesmi zmenit
773
774int BSplineInterpolation :: findSpan(int n, int p, double u, const FloatArray &U) const
775{
776 if ( u == U [ n + 1 ] ) {
777 return n;
778 }
779
780 int low = p;
781 int high = n + 1;
782 int mid = ( low + high ) / 2;
783
784 while ( u < U [ mid ] || u >= U [ mid + 1 ] ) {
785 if ( u < U [ mid ] ) {
786 high = mid;
787 } else {
788 low = mid;
789 }
790
791 mid = ( low + high ) / 2;
792 }
793
794 return mid;
795}
796} // end namespace oofem
#define N(a, b)
void postInitialize(ParameterManager &pm, int elnum) override
Definition feibspline.C:86
std::array< int, 3 > numberOfKnotSpans
Nonzero spans in each directions [nsd].
Definition feibspline.h:82
static ParamKey IPK_BSplineInterpolation_degree
Definition feibspline.h:84
std::array< int, 3 > degree
Degree in each direction.
Definition feibspline.h:68
std::array< FloatArray, 3 > knotVector
Knot vectors [nsd][knot_vector_size].
Definition feibspline.h:80
std::array< int, 3 > numberOfControlPoints
numberOfControlPoints[nsd]
Definition feibspline.h:78
static ParamKey IPK_BSplineInterpolation_knotMultiplicityV
Definition feibspline.h:89
static ParamKey IPK_BSplineInterpolation_knotVectorV
Definition feibspline.h:86
int giveNumberOfKnotSpanBasisFunctions(const IntArray &knotSpan) const override
Definition feibspline.C:625
static ParamKey IPK_BSplineInterpolation_knotVectorW
Definition feibspline.h:87
static ParamKey IPK_BSplineInterpolation_knotVectorU
Definition feibspline.h:85
void basisFuns(FloatArray &N, int span, double u, int p, const FloatArray &U) const
Definition feibspline.C:644
int findSpan(int n, int p, double u, const FloatArray &U) const
Definition feibspline.C:774
std::array< IntArray, 3 > knotMultiplicity
Knot multiplicity [nsd].
Definition feibspline.h:72
void dersBasisFuns(int n, double u, int span, int p, const FloatArray &U, FloatMatrix &ders) const
Definition feibspline.C:675
static ParamKey IPK_BSplineInterpolation_knotMultiplicityW
Definition feibspline.h:90
static ParamKey IPK_BSplineInterpolation_knotMultiplicityU
Definition feibspline.h:88
int nsd
Number of spatial directions.
Definition feibspline.h:66
std::array< FloatArray, 3 > knotValues
Knot values [nsd].
Definition feibspline.h:70
virtual const FloatArray giveVertexCoordinates(int i) const =0
const IntArray * knotSpan
Definition iga.h:60
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
void add(const FloatArray &src)
Definition floatarray.C:218
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
void zero()
Zeroes all coefficient of receiver.
double giveDeterminant() const
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
#define OOFEM_ERROR(...)
Definition error.h:79
#define _IFT_BSplineInterpolation_degree
Definition feibspline.h:44
#define OOFEM_LOG_RELEVANT(...)
Definition logger.h:142
double sum(const FloatArray &x)
#define PM_UPDATE_PARAMETER_AND_REPORT(_val, _pm, _ir, _componentnum, _paramkey, _prio, _flag)
#define PM_UPDATE_PARAMETER(_val, _pm, _ir, _componentnum, _paramkey, _prio)

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