1
// $Id: FunctionSpace.cpp,v 1.4 2008-03-20 11:44:09 geuzaine Exp $
3
// Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
5
// This program is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 2 of the License, or
8
// (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
// GNU General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20
// Please report all bugs and problems to <gmsh@geuz.org>.
23
#include "FunctionSpace.h"
24
#include "GmshDefines.h"
26
Double_Matrix generatePascalTriangle(int order)
28
Double_Matrix monomials((order + 1) * (order + 2) / 2, 2);
30
for (int i = 0; i <= order; i++) {
31
for (int j = 0; j <= i; j++) {
32
monomials(index, 0) = i - j;
33
monomials(index, 1) = j;
40
// generate the exterior hull of the Pascal triangle for Serendipity element
42
Double_Matrix generatePascalSerendipityTriangle(int order)
44
Double_Matrix monomials(3 * order, 2);
50
for (int i = 1; i <= order; i++) {
52
for (int j = 0; j <= i; j++) {
53
monomials(index, 0) = i - j;
54
monomials(index, 1) = j;
59
monomials(index, 0) = i;
60
monomials(index, 1) = 0;
62
monomials(index, 0) = 0;
63
monomials(index, 1) = i;
70
// generate the monomials subspace of all monomials of order exactly == p
72
Double_Matrix generateMonomialSubspace(int dim, int p)
74
Double_Matrix monomials;
78
monomials = Double_Matrix(1, 1);
82
monomials = Double_Matrix(p + 1, 2);
83
for (int k = 0; k <= p; k++) {
84
monomials(k, 0) = p - k;
89
monomials = Double_Matrix((p + 1) * (p + 2) / 2, 3);
91
for (int i = 0; i <= p; i++) {
92
for (int k = 0; k <= p - i; k++) {
93
monomials(index, 0) = p - i - k;
94
monomials(index, 1) = k;
95
monomials(index, 2) = i;
104
// generate external hull of the Pascal tetrahedron
106
Double_Matrix generatePascalSerendipityTetrahedron(int order)
108
int nbMonomials = 4 + 6 * std::max(0, order - 1) +
109
4 * std::max(0, (order - 2) * (order - 1) / 2);
110
Double_Matrix monomials(nbMonomials, 3);
114
monomials.set_all(0);
121
for (int p = 1; p < order; p++) {
122
for (int i = 0; i < 3; i++) {
125
for (int ii = 0; ii < p; ii++) {
126
monomials(index, i) = p - ii;
127
monomials(index, j) = ii;
128
monomials(index, k) = 0;
133
Double_Matrix monomialsMaxOrder = generateMonomialSubspace(3, order);
134
int nbMaxOrder = monomialsMaxOrder.size1();
136
Double_Matrix(monomials.touchSubmatrix(index, nbMaxOrder, 0, 3)).memcpy(monomialsMaxOrder);
140
// generate Pascal tetrahedron
142
Double_Matrix generatePascalTetrahedron(int order)
144
int nbMonomials = (order + 1) * (order + 2) * (order + 3) / 6;
146
Double_Matrix monomials(nbMonomials, 3);
149
for (int p = 0; p <= order; p++) {
150
Double_Matrix monOrder = generateMonomialSubspace(3, p);
151
int nb = monOrder.size1();
152
Double_Matrix(monomials.touchSubmatrix(index, nb, 0, 3)).memcpy(monOrder);
159
int nbdoftriangle(int order) { return (order + 1) * (order + 2) / 2; }
160
int nbdoftriangleserendip(int order) { return 3 * order; }
162
void nodepositionface0(int order, double *u, double *v, double *w)
164
int ndofT = nbdoftriangle(order);
165
if (order == 0) { u[0] = 0.; v[0] = 0.; return; }
167
u[0]= 0.; v[0]= 0.; w[0] = 0.;
168
u[1]= order; v[1]= 0; w[1] = 0.;
169
u[2]= 0.; v[2]= order; w[2] = 0.;
172
for (int k = 0; k < (order - 1); k++){
177
u[3 + order - 1 + k] = order - 1 - k ;
178
v[3 + order - 1 + k] = k + 1;
179
w[3 + order - 1 + k] = 0.;
181
u[3 + 2 * (order - 1) + k] = 0.;
182
v[3 + 2 * (order - 1) + k] = order - 1 - k;
183
w[3 + 2 * (order - 1) + k] = 0.;
186
int nbdoftemp = nbdoftriangle(order - 3);
187
nodepositionface0(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order - 1)],
188
&w[3 + 3* (order - 1)]);
189
for (int k = 0; k < nbdoftemp; k++){
190
u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
191
v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
192
w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3);
195
for (int k = 0; k < ndofT; k++){
202
void nodepositionface1(int order, double *u, double *v, double *w)
204
int ndofT = nbdoftriangle(order);
205
if (order == 0) { u[0] = 0.; v[0] = 0.; return; }
207
u[0]= 0.; v[0]= 0.; w[0] = 0.;
208
u[1]= order; v[1]= 0; w[1] = 0.;
209
u[2]= 0.; v[2]= 0.; w[2] = order;
211
for (int k = 0; k < (order - 1); k++){
216
u[3 + order - 1 + k] = order - 1 - k;
217
v[3 + order - 1 + k] = 0.;
218
w[3 + order - 1+ k ] = k + 1;
220
u[3 + 2 * (order - 1) + k] = 0. ;
221
v[3 + 2 * (order - 1) + k] = 0.;
222
w[3 + 2 * (order - 1) + k] = order - 1 - k;
225
int nbdoftemp = nbdoftriangle(order - 3);
226
nodepositionface1(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order -1 )],
227
&w[3 + 3 * (order - 1)]);
228
for (int k = 0; k < nbdoftemp; k++){
229
u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
230
v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3);
231
w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
234
for (int k = 0; k < ndofT; k++){
241
void nodepositionface2(int order, double *u, double *v, double *w)
243
int ndofT = nbdoftriangle(order);
244
if (order == 0) { u[0] = 0.; v[0] = 0.; return; }
246
u[0]= order; v[0]= 0.; w[0] = 0.;
247
u[1]= 0.; v[1]= order; w[1] = 0.;
248
u[2]= 0.; v[2]= 0.; w[2] = order;
250
for (int k = 0; k < (order - 1); k++){
251
u[3 + k] = order - 1 - k;
255
u[3 + order - 1 + k] = 0.;
256
v[3 + order - 1 + k] = order - 1 - k;
257
w[3 + order - 1 + k] = k + 1;
259
u[3 + 2 * (order - 1) + k] = k + 1;
260
v[3 + 2 * (order - 1) + k] = 0.;
261
w[3 + 2 * (order - 1) + k] = order - 1 - k;
264
int nbdoftemp = nbdoftriangle(order - 3);
265
nodepositionface2(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order - 1)],
266
&w[3 + 3 * (order - 1)]);
267
for (int k = 0; k < nbdoftemp; k++){
268
u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
269
v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
270
w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
273
for (int k = 0; k < ndofT; k++){
280
void nodepositionface3(int order, double *u, double *v, double *w)
282
int ndofT = nbdoftriangle(order);
283
if (order == 0) { u[0] = 0.; v[0] = 0.; return; }
285
u[0]= 0.; v[0]= 0.; w[0] = 0.;
286
u[1]= 0.; v[1]= order; w[1] = 0.;
287
u[2]= 0.; v[2]= 0.; w[2] = order;
289
for (int k = 0; k < (order - 1); k++){
294
u[3 + order - 1 + k] = 0.;
295
v[3 + order - 1 + k] = order - 1 - k;
296
w[3 + order - 1 + k] = k + 1;
298
u[3 + 2 * (order - 1) + k] = 0.;
299
v[3 + 2 * (order - 1) + k] = 0.;
300
w[3 + 2 * (order - 1) + k] = order - 1 - k;
303
int nbdoftemp = nbdoftriangle(order - 3);
304
nodepositionface3(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order - 1)],
305
&w[3 + 3 * (order - 1)]);
306
for (int k = 0; k < nbdoftemp; k++){
307
u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3);
308
v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
309
w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
312
for (int k = 0; k < ndofT; k++){
319
Double_Matrix gmshGeneratePointsTetrahedron(int order, bool serendip)
323
4 + 6 * std::max(0, order - 1) + 4 * std::max(0, (order - 2) * (order - 1) / 2) :
324
(order + 1) * (order + 2) * (order + 3) / 6);
326
Double_Matrix point(nbPoints, 3);
328
double overOrder = 1. / order;
348
for (int k = 0; k < (order - 1); k++) {
349
point(4 + k, 0) = k + 1;
350
point(4 + order - 1 + k, 0) = order - 1 - k;
351
point(4 + 2 * (order - 1) + k, 0) = 0.;
352
point(4 + 3 * (order - 1) + k, 0) = 0.;
353
point(4 + 4 * (order - 1) + k, 0) = order - 1 - k;
354
point(4 + 5 * (order - 1) + k, 0) = 0.;
356
point(4 + k, 1) = 0.;
357
point(4 + order - 1 + k, 1) = k + 1;
358
point(4 + 2 * (order - 1) + k, 1) = order - 1 - k;
359
point(4 + 3 * (order - 1) + k, 1) = 0.;
360
point(4 + 4 * (order - 1) + k, 1) = 0.;
361
point(4 + 5 * (order - 1) + k, 1) = order - 1 - k;
363
point(4 + k, 2) = 0.;
364
point(4 + order - 1 + k, 2) = 0.;
365
point(4 + 2 * (order - 1) + k, 2) = 0.;
366
point(4 + 3 * (order - 1) + k, 2) = k + 1;
367
point(4 + 4 * (order - 1) + k, 2) = k + 1;
368
point(4 + 5 * (order - 1) + k, 2) = k + 1;
372
int ns = 4 + 6 * (order - 1);
373
int nbdofface = nbdoftriangle(order - 3);
375
double *u = new double[nbdofface];
376
double *v = new double[nbdofface];
377
double *w = new double[nbdofface];
379
nodepositionface0(order - 3, u, v, w);
381
for (int i = 0; i < nbdofface; i++){
382
point(ns + i, 0) = u[i] * (order - 3) + 1.;
383
point(ns + i, 1) = v[i] * (order - 3) + 1.;
384
point(ns + i, 2) = w[i] * (order - 3);
389
nodepositionface1(order - 3, u, v, w);
391
for (int i=0; i < nbdofface; i++){
392
point(ns + i, 0) = u[i] * (order - 3) + 1.;
393
point(ns + i, 1) = v[i] * (order - 3) ;
394
point(ns + i, 2) = w[i] * (order - 3) + 1.;
399
nodepositionface2(order - 3, u, v, w);
401
for (int i = 0; i < nbdofface; i++){
402
point(ns + i, 0) = u[i] * (order - 3) + 1.;
403
point(ns + i, 1) = v[i] * (order - 3) + 1.;
404
point(ns + i, 2) = w[i] * (order - 3) + 1.;
409
nodepositionface3(order - 3, u, v, w);
411
for (int i = 0; i < nbdofface; i++){
412
point(ns + i, 0) = u[i] * (order - 3);
413
point(ns + i, 1) = v[i] * (order - 3) + 1.;
414
point(ns + i, 2) = w[i] * (order - 3) + 1.;
423
if (!serendip && order > 3) {
425
Double_Matrix interior = gmshGeneratePointsTetrahedron(order - 4, false);
426
for (int k = 0; k < interior.size1(); k++) {
427
point(ns + k, 0) = 1. + interior(k, 0) * (order - 4);
428
point(ns + k, 1) = 1. + interior(k, 1) * (order - 4);
429
point(ns + k, 2) = 1. + interior(k, 2) * (order - 4);
436
point.scale(overOrder);
440
Double_Matrix gmshGeneratePointsTriangle(int order, bool serendip)
442
int nbPoints = serendip ? 3 * order : (order + 1) * (order + 2) / 2;
443
Double_Matrix point(nbPoints, 2);
448
double dd = 1. / order;
463
for (int i = 0; i < order - 1; i++, index++) {
465
point(index, 0) = ksi;
466
point(index, 1) = eta;
471
for (int i = 0; i < order - 1; i++, index++) {
474
point(index, 0) = ksi;
475
point(index, 1) = eta;
481
for (int i = 0; i < order - 1; i++, index++) {
483
point(index, 0) = ksi;
484
point(index, 1) = eta;
487
if (order > 2 && !serendip) {
488
Double_Matrix inner = gmshGeneratePointsTriangle(order - 3, serendip);
489
inner.scale(1. - 3. * dd);
491
Double_Matrix(point.touchSubmatrix(index, nbPoints - index, 0, 2)).memcpy(inner);
498
Double_Matrix generateLagrangeMonomialCoefficients(const Double_Matrix& monomial,
499
const Double_Matrix& point)
501
if (monomial.size1() != point.size1()) throw;
502
if (monomial.size2() != point.size2()) throw;
504
int ndofs = monomial.size1();
505
int dim = monomial.size2();
507
Double_Matrix Vandermonde(ndofs, ndofs);
509
for (int i = 0; i < ndofs; i++) {
510
for (int j = 0; j < ndofs; j++) {
512
for (int k = 0; k < dim; k++) dd *= pow(point(i, k), monomial(j, k));
513
Vandermonde(i, j) = dd;
517
// check for independence
519
double det = Vandermonde.determinant();
521
if (det == 0.0) throw;
523
Double_Matrix coefficient(ndofs, ndofs);
525
for (int i = 0; i < ndofs; i++) {
526
for (int j = 0; j < ndofs; j++) {
527
int f = (i + j) % 2 == 0 ? 1 : -1;
528
Double_Matrix cofactor = Vandermonde.cofactor(i, j);
529
coefficient(i, j) = f * cofactor.determinant() / det;
533
Vandermonde.set_all(0.);
535
for (int i = 0; i < ndofs; i++) {
536
for (int j = 0; j < ndofs; j++) {
538
for (int k = 0; k < dim; k++) dd *= pow(point(i, k), monomial(j, k));
539
for (int k = 0; k < ndofs; k++) {
540
Vandermonde(i, k) += coefficient(k, j) * dd;
547
std::map<int, gmshFunctionSpace> gmshFunctionSpaces::fs;
549
const gmshFunctionSpace &gmshFunctionSpaces::find(int tag)
551
std::map<int,gmshFunctionSpace>::const_iterator it = fs.find(tag);
552
if (it != fs.end()) return it->second;
558
F.monomials = generatePascalTriangle(1);
559
F.points = gmshGeneratePointsTriangle(1, false);
562
F.monomials = generatePascalTriangle(2);
563
F.points = gmshGeneratePointsTriangle(2, false);
566
F.monomials = generatePascalSerendipityTriangle(3);
567
F.points = gmshGeneratePointsTriangle(3, true);
570
F.monomials = generatePascalTriangle(3);
571
F.points = gmshGeneratePointsTriangle(3, false);
574
F.monomials = generatePascalSerendipityTriangle(4);
575
F.points = gmshGeneratePointsTriangle(4, true);
578
F.monomials = generatePascalTriangle(4);
579
F.points = gmshGeneratePointsTriangle(4, false);
582
F.monomials = generatePascalSerendipityTriangle(5);
583
F.points = gmshGeneratePointsTriangle(5, true);
586
F.monomials = generatePascalTriangle(5);
587
F.points = gmshGeneratePointsTriangle(5, false);
592
F.coefficients = generateLagrangeMonomialCoefficients(F.monomials, F.points);
593
fs.insert(std::make_pair(tag, F));