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

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Tue Jan 2 2018 20:07:28 for OOFEM by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2011