Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/post/src/elements/math.c
3203 views
1
/*****************************************************************************
2
*
3
* Elmer, A Finite Element Software for Multiphysical Problems
4
*
5
* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
*
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program (in file fem/GPL-2); if not, write to the
19
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
* Boston, MA 02110-1301, USA.
21
*
22
*****************************************************************************/
23
24
/*******************************************************************************
25
*
26
* Main module for element model descriptions & utility routines.
27
*
28
*******************************************************************************
29
*
30
* Author: Juha Ruokolainen
31
*
32
* Address: CSC - IT Center for Science Ltd.
33
* Keilaranta 14, P.O. BOX 405
34
* 02101 Espoo, Finland
35
* Tel. +358 0 457 2723
36
* Telefax: +358 0 457 2302
37
* EMail: [email protected]
38
*
39
* Date: 12 Apr 1996
40
*
41
* Modification history:
42
*
43
* 12 Apr 1996,
44
* Juha R
45
*
46
*
47
******************************************************************************/
48
49
#define MODULE_ELEMENT_MATH
50
51
#include "../elmerpost.h"
52
#include "elements.h"
53
54
55
/*******************************************************************************
56
*
57
* Name: elm_element_gradient_2D
58
*
59
* Purpose: Compute elementwise gradient vector of given quantity for
60
* surface elements.
61
*
62
* Parameters:
63
*
64
* Input: (element_t *) structure describing the element
65
* (double *) node values of the quantity.
66
*
67
* Output: Gradient vector (double *)GX
68
* (double *)GY
69
* (double *)GZ at nodes.
70
*
71
* Return value: FALSE if element is degenerated, TRUE otherwise.
72
*
73
******************************************************************************/
74
int elm_element_gradient_2D( element_model_t *model, element_t *elm, double *F,
75
double *GX, double *GY, double *GZ, int NPoints, double *NU, double *NV )
76
{
77
static double X[ELM_MAX_ELEMENT_NODES];
78
static double Y[ELM_MAX_ELEMENT_NODES];
79
static double Z[ELM_MAX_ELEMENT_NODES];
80
81
int i,n;
82
83
double u,v,a,detA,Auv,Avu,Auu,Avv,dXdU,dYdU,dXdV,dYdV,dZdU,dZdV,dFdU,dFdV;
84
85
element_type_t *elmt = elm->ElementType;
86
87
double (*dNdU)() = elmt->PartialU;
88
double (*dNdV)() = elmt->PartialV;
89
90
for( i=0; i<elmt->NumberOfNodes; i++ )
91
{
92
n = elm->Topology[i];
93
X[i] = model->NodeArray[n];
94
Y[i] = model->NodeArray[model->NofNodes+n];
95
Z[i] = model->NodeArray[2*model->NofNodes+n];
96
}
97
98
for( i=0; i<NPoints; i++ )
99
{
100
u = NU[i];
101
v = NV[i];
102
103
dXdU = (*dNdU)(X,u,v);
104
dYdU = (*dNdU)(Y,u,v);
105
dZdU = (*dNdU)(Z,u,v);
106
dFdU = (*dNdU)(F,u,v);
107
108
dXdV = (*dNdV)(X,u,v);
109
dYdV = (*dNdV)(Y,u,v);
110
dZdV = (*dNdV)(Z,u,v);
111
dFdV = (*dNdV)(F,u,v);
112
113
#if 0
114
Avv = dXdU*dXdU + dYdU*dYdU + dZdU*dZdU; /* surface metric a */
115
Auv = dXdU*dXdV + dYdU*dYdV + dZdU*dZdV; /* ij */
116
Auu = dXdV*dXdV + dYdV*dYdV + dZdV*dZdV;
117
118
detA = Auu*Avv - Auv*Auv;
119
if ( ABS(detA) < AEPS ) return FALSE;
120
121
Auv = -Auv / detA; /* ij */
122
Auu = Auu / detA; /* a */
123
Avv = Avv / detA;
124
125
a = dFdU;
126
dFdU = Auu*a + Auv*dFdV; /* raise index of the surface */
127
dFdV = Auv*a + Avv*dFdV; /* vector (@f/@u,@f/@v) */
128
129
/* transform to global cartesian frame */
130
GX[i] = dXdU*dFdU + dXdV*dFdV;
131
GY[i] = dYdU*dFdU + dYdV*dFdV;
132
GZ[i] = dZdU*dFdU + dZdV*dFdV;
133
#else
134
Auu = dYdV;
135
Auv = dYdU;
136
Avu = dXdV;
137
Avv = dXdU;
138
detA = Auu*Avv - Auv*Avu;
139
140
Auu = Auu / detA;
141
Auv = -Auv / detA;
142
Avu = -Avu / detA;
143
Avv = Avv / detA;
144
145
GX[i] = Auu*dFdU + Auv*dFdV;
146
GY[i] = Avu*dFdU + Avv*dFdV;
147
GZ[i] = 0.0;
148
#endif
149
}
150
151
return TRUE;
152
}
153
154
/*******************************************************************************
155
*
156
* Name: elm_element_gradient_3D
157
*
158
* Purpose: Compute elementwise gradient vector of given quantity
159
* for volume elements.
160
*
161
* Parameters:
162
*
163
* Input: (element_t *) structure describing the element
164
* (double *) node values of the quantity.
165
*
166
* Output: Gradient vector (double *)GX
167
* (double *)GY
168
* (double *)GZ at nodes.
169
*
170
* Return value: FALSE if element is degenerated, TRUE otherwise.
171
*
172
******************************************************************************/
173
int elm_element_gradient_3D( element_model_t *model, element_t *elm, double *F,
174
double *GX, double *GY, double *GZ, int NPoints, double *NU, double *NV, double *NW )
175
{
176
static double X[ELM_MAX_ELEMENT_NODES];
177
static double Y[ELM_MAX_ELEMENT_NODES];
178
static double Z[ELM_MAX_ELEMENT_NODES];
179
180
double u,v,w,a,detJ;
181
182
double Jux,Juy,Juz,Jvx,Jvy,Jvz,Jwx,Jwy,Jwz;
183
double Kxu,Kxv,Kxw,Kyu,Kyv,Kyw,Kzu,Kzv,Kzw;
184
double dFdU, dFdV, dFdW;
185
186
int i,n;
187
188
element_type_t *elmt = elm->ElementType;
189
190
double (*dNdU)() = elmt->PartialU;
191
double (*dNdV)() = elmt->PartialV;
192
double (*dNdW)() = elmt->PartialW;
193
194
for( i=0; i<elmt->NumberOfNodes; i++ )
195
{
196
n = elm->Topology[i];
197
X[i] = model->NodeArray[n];
198
Y[i] = model->NodeArray[model->NofNodes+n];
199
Z[i] = model->NodeArray[2*model->NofNodes+n];
200
}
201
202
for( i=0; i<NPoints; i++ )
203
{
204
u = NU[i];
205
v = NV[i];
206
w = NW[i];
207
208
Jux = (*dNdU)( X,u,v,w );
209
Juy = (*dNdU)( Y,u,v,w );
210
Juz = (*dNdU)( Z,u,v,w );
211
dFdU = (*dNdU)( F,u,v,w );
212
213
Jvx = (*dNdV)( X,u,v,w );
214
Jvy = (*dNdV)( Y,u,v,w );
215
Jvz = (*dNdV)( Z,u,v,w );
216
dFdV = (*dNdV)( F,u,v,w );
217
218
Jwx = (*dNdW)( X,u,v,w );
219
Jwy = (*dNdW)( Y,u,v,w );
220
Jwz = (*dNdW)( Z,u,v,w );
221
dFdW = (*dNdW)( F,u,v,w );
222
223
detJ = Jux*(Jvy*Jwz - Jvz*Jwy);
224
detJ += Juy*(Jvz*Jwx - Jvx*Jwz);
225
detJ += Juz*(Jvx*Jwy - Jvy*Jwx);
226
if ( ABS(detJ) < AEPS ) return FALSE;
227
detJ = 1 / detJ;
228
229
Kxu = (Jvy*Jwz - Jvz*Jwy)*detJ;
230
Kyu = (Jvz*Jwx - Jvx*Jwz)*detJ;
231
Kzu = (Jvx*Jwy - Jvy*Jwx)*detJ;
232
233
Kxv = (Jwy*Juz - Juy*Jwz)*detJ;
234
Kyv = (Jux*Jwz - Jwx*Juz)*detJ;
235
Kzv = (Juy*Jwx - Jux*Jwy)*detJ;
236
237
Kxw = (Juy*Jvz - Jvy*Juz)*detJ;
238
Kyw = (Jvx*Juz - Jux*Jvz)*detJ;
239
Kzw = (Jux*Jvy - Jvx*Juy)*detJ;
240
241
/* transform to global cartesian frame */
242
GX[i] = Kxu*dFdU + Kxv*dFdV + Kxw*dFdW;
243
GY[i] = Kyu*dFdU + Kyv*dFdV + Kyw*dFdW;
244
GZ[i] = Kzu*dFdU + Kzv*dFdV + Kzw*dFdW;
245
}
246
247
return TRUE;
248
}
249
250
/*******************************************************************************
251
*
252
* Name: elm_gradient
253
*
254
* Purpose: Compute gradient vector of given quantity.
255
*
256
* Parameters:
257
*
258
* Input:
259
*
260
* Output:
261
*
262
* Return value: void
263
*
264
******************************************************************************/
265
VARIABLE *elm_gradient( VARIABLE *A )
266
{
267
static double dFdX[ELM_MAX_ELEMENT_NODES];
268
static double dFdY[ELM_MAX_ELEMENT_NODES];
269
static double dFdZ[ELM_MAX_ELEMENT_NODES];
270
static double F[ELM_MAX_ELEMENT_NODES];
271
272
element_type_t *elmt;
273
element_t *elm;
274
275
element_model_t *model = CurrentObject->ElementModel; /*** TODO: FIX ***/
276
277
unsigned char *References = (unsigned char *)malloc( model->NofNodes*sizeof(unsigned char) );
278
279
double *af = MATR( A );
280
281
int i,j,k,n,status,dim, cols;
282
283
VARIABLE *res;
284
285
double *rx, *ry, *rz;
286
287
cols = NCOL(A) / model->NofNodes;
288
if ( NROW(A) != 1 )
289
{
290
free( References );
291
error( "I can only compute the gradient of a scalar variable\n" );
292
}
293
294
res = (VARIABLE *)var_temp_new( TYPE_DOUBLE, 3, cols*model->NofNodes );
295
rx = &M(res,0,0);
296
ry = &M(res,1,0);
297
rz = &M(res,2,0);
298
299
dim = 1;
300
for( k=0; k<model->NofElements; k++ )
301
if ( model->Elements[k].ElementType->ElementCode>=500 ) {
302
dim=3;
303
break;
304
} else if ( model->Elements[k].ElementType->ElementCode>=300 )
305
dim=2;
306
307
for( k=0; k<cols; k++ )
308
{
309
for( j=0; j<model->NofNodes; j++ )
310
{
311
n = k*model->NofNodes + j;
312
rx[n] = 0.0;
313
ry[n] = 0.0;
314
rz[n] = 0.0;
315
References[j] = 0;
316
}
317
318
for( i=0; i<model->NofElements; i++ )
319
{
320
elm = &model->Elements[i];
321
elmt = elm->ElementType;
322
323
for( j=0; j<elmt->NumberOfNodes; j++ )
324
{
325
n = k*model->NofNodes + elm->Topology[j];
326
F[j] = af[n];
327
dFdX[j] = af[n];
328
dFdY[j] = af[n];
329
dFdZ[j] = af[n];
330
}
331
if ( dim==3 && elmt->PartialW )
332
status = elm_element_gradient_3D(
333
model, elm,F,dFdX,dFdY,dFdZ,elmt->NumberOfNodes,elmt->NodeU,elmt->NodeV,elmt->NodeW
334
);
335
else if ( dim==2 && elmt->PartialV )
336
status = elm_element_gradient_2D(
337
model, elm,F,dFdX,dFdY,dFdZ,elmt->NumberOfNodes,elmt->NodeU,elmt->NodeV
338
);
339
else continue;
340
341
if ( !status )
342
{
343
fprintf( stderr, "ELEMENT [%d]: Jacobian is singular.\n",i );
344
continue;
345
}
346
347
for( j=0; j<elmt->NumberOfNodes; j++ )
348
{
349
n = elm->Topology[j];
350
References[n]++;
351
352
n += k*model->NofNodes;
353
rx[n] += dFdX[j];
354
ry[n] += dFdY[j];
355
rz[n] += dFdZ[j];
356
}
357
}
358
359
for( j=0; j<model->NofNodes; j++ )
360
{
361
if ( References[j] != 0 )
362
{
363
n = k*model->NofNodes + j;
364
rx[n] /= References[j];
365
ry[n] /= References[j];
366
rz[n] /= References[j];
367
}
368
}
369
}
370
371
free( References );
372
return res;
373
}
374
375
/*******************************************************************************
376
*
377
* Name: elm_element_rotor_2D
378
*
379
* Purpose: Compute elementwise rotor of given quantity for a surface
380
* element.
381
*
382
* Parameters:
383
*
384
* Input: (element_t *)elm structure describing the element
385
* (double *)FX node values of vector x component.
386
* (double *)FY node values of vector x component.
387
* (double *)FZ node values of vector x component.
388
*
389
* Output: Rotor (double *)R
390
*
391
* Return value: FALSE if element is degenerated, TRUE otherwise.
392
*
393
******************************************************************************/
394
int elm_element_rotor_2D
395
(
396
element_model_t *model, element_t *elm, double *FX, double *FY, double *FZ, double *R
397
)
398
{
399
static double X[ELM_MAX_ELEMENT_NODES];
400
static double Y[ELM_MAX_ELEMENT_NODES];
401
static double Z[ELM_MAX_ELEMENT_NODES];
402
403
static double Fu[ELM_MAX_ELEMENT_NODES];
404
static double Fv[ELM_MAX_ELEMENT_NODES];
405
406
double u,v,w,a,detA;
407
408
double Auu,Auv,Avu,Avv;
409
double dXdU,dYdU,dZdU;
410
double dXdV,dYdV,dZdV;
411
412
double dFudU, dFudV;
413
double dFvdU, dFvdV;
414
double dFwdU, dFwdV;
415
416
int i,n;
417
418
element_type_t *elmt = elm->ElementType;
419
420
double *NodeU = elmt->NodeU;
421
double *NodeV = elmt->NodeV;
422
423
double (*dNdU)() = elmt->PartialU;
424
double (*dNdV)() = elmt->PartialV;
425
426
for( i=0; i<elmt->NumberOfNodes; i++ )
427
{
428
n = elm->Topology[i];
429
X[i] = model->NodeArray[n];
430
Y[i] = model->NodeArray[model->NofNodes+n];
431
Z[i] = model->NodeArray[2*model->NofNodes+n];
432
}
433
434
for( i=0; i<elmt->NumberOfNodes; i++ )
435
{
436
u = NodeU[i];
437
v = NodeV[i];
438
439
dXdU = (*dNdU)( X,u,v );
440
dYdU = (*dNdU)( Y,u,v );
441
dZdU = (*dNdU)( Z,u,v );
442
443
dXdV = (*dNdV)( X,u,v );
444
dYdV = (*dNdV)( Y,u,v );
445
dZdV = (*dNdV)( Z,u,v );
446
447
Fu[i] = FX[i]*dXdU + FY[i]*dYdU + FZ[i]*dZdU;
448
Fv[i] = FX[i]*dXdV + FY[i]*dYdV + FZ[i]*dZdV;
449
}
450
451
for( i=0; i<elmt->NumberOfNodes; i++ )
452
{
453
u = NodeU[i];
454
v = NodeV[i];
455
456
dXdU = (*dNdU)( X,u,v );
457
dYdU = (*dNdU)( Y,u,v );
458
dZdU = (*dNdU)( Z,u,v );
459
460
dXdV = (*dNdV)( X,u,v );
461
dYdV = (*dNdV)( Y,u,v );
462
dZdV = (*dNdV)( Z,u,v );
463
464
dFvdU = (*dNdU)( Fv,u,v );
465
dFudV = (*dNdV)( Fu,u,v );
466
467
Auu = dXdU*dXdU + dYdU*dYdU + dZdU*dZdU;
468
Auv = dXdU*dXdV + dYdU*dYdV + dZdU*dZdV;
469
Avu = dXdV*dXdU + dYdV*dYdU + dZdV*dZdU;
470
Avv = dXdV*dXdV + dYdV*dYdV + dZdV*dZdV;
471
472
detA = Auu*Avv - Auv*Avu;
473
474
if ( ABS(detA) < AEPS ) return FALSE;
475
476
R[i] = (dFvdU - dFudV) / sqrt( detA );
477
}
478
479
return TRUE;
480
}
481
482
/*******************************************************************************
483
*
484
* Name: elm_rotor_2D
485
*
486
* Purpose: Compute rotor of given quantity for surface elements.
487
*
488
* Parameters:
489
*
490
* Input:
491
*
492
* Output:
493
*
494
* Return value: void
495
*
496
******************************************************************************/
497
VARIABLE *elm_rotor_2D( VARIABLE *A )
498
{
499
static double FX[ELM_MAX_ELEMENT_NODES];
500
static double FY[ELM_MAX_ELEMENT_NODES];
501
static double FZ[ELM_MAX_ELEMENT_NODES];
502
503
static double R[ELM_MAX_ELEMENT_NODES];
504
505
element_type_t *elmt;
506
element_t *elm;
507
508
element_model_t *model = CurrentObject->ElementModel; /*** TODO: FIX ***/
509
510
unsigned char *References = (unsigned char *)malloc( model->NofNodes*sizeof(unsigned char) );
511
512
int i,j,k,n,cols;
513
514
double *ax = &M(A,0,0);
515
double *ay = &M(A,1,0);
516
double *az = &M(A,2,0);
517
518
VARIABLE *res;
519
double *rf;
520
521
cols = NCOL(A) / model->NofNodes;
522
if ( NROW(A) != 3 )
523
{
524
free( References );
525
error( "curl 2D: vector variable needed as input.\n" );
526
}
527
528
res = var_temp_new( TYPE_DOUBLE, 1, cols*model->NofNodes );
529
rf = MATR(res);
530
531
for( k=0; k<cols; k++ )
532
{
533
for( j=0; j<model->NofNodes; j++ )
534
{
535
rf[k*model->NofNodes+j] = 0.0;
536
References[j] = 0;
537
}
538
539
for( i=0; i<model->NofElements; i++ )
540
{
541
elm = &model->Elements[i];
542
elmt = elm->ElementType;
543
544
if ( elmt->ElementCode < 300 || elmt->ElementCode > 500 ) continue;
545
546
for( j=0; j<elmt->NumberOfNodes; j++ )
547
{
548
n = k*model->NofNodes + elm->Topology[j];
549
FX[j] = ax[n];
550
FY[j] = ay[n];
551
FZ[j] = az[n];
552
}
553
554
if ( !elm_element_rotor_2D( model,elm,FX,FY,FZ,R ) )
555
{
556
fprintf( stderr, "ELEMENT [%d]: Jacobian is singular.\n",i );
557
continue;
558
}
559
560
for( j=0; j<elmt->NumberOfNodes; j++ )
561
{
562
n = elm->Topology[j];
563
References[n]++;
564
565
rf[k*model->NofNodes+n] += R[j];
566
}
567
}
568
569
for( j=0; j<model->NofNodes; j++ )
570
{
571
if ( References[j] != 0 )
572
{
573
n = k*model->NofNodes + j;
574
rf[n] /= References[j];
575
}
576
}
577
}
578
579
free( References );
580
return res;
581
}
582
583
/*******************************************************************************
584
*
585
* Name: elm_element_rotor_3D
586
*
587
* Purpose: Compute elementwise rotor of given quantity for a volume
588
* element.
589
*
590
* Parameters:
591
*
592
* Input: (element_t *)elm structure describing the element
593
* (double *)FX node values of vector x component.
594
* (double *)FY node values of vector y component.
595
* (double *)FZ node values of vector z component.
596
*
597
* Output: Rotor vector at nodes (double *)RX
598
* (double *)RY
599
* (double *)RZ
600
*
601
* Return value: FALSE if element is degenerated, TRUE otherwise.
602
*
603
******************************************************************************/
604
int elm_element_rotor_3D( element_model_t *model, element_t *elm,
605
double *FX, double *FY, double *FZ,
606
double *RX, double *RY, double *RZ )
607
{
608
static double Fu[ELM_MAX_ELEMENT_NODES];
609
static double Fv[ELM_MAX_ELEMENT_NODES];
610
static double Fw[ELM_MAX_ELEMENT_NODES];
611
612
static double X[ELM_MAX_ELEMENT_NODES];
613
static double Y[ELM_MAX_ELEMENT_NODES];
614
static double Z[ELM_MAX_ELEMENT_NODES];
615
616
double u,v,w,a,detA;
617
618
double Auu,Auv,Auw,Avu,Avv,Avw,Awu,Awv,Aww;
619
double dXdU,dYdU,dZdU;
620
double dXdV,dYdV,dZdV;
621
double dXdW,dYdW,dZdW;
622
623
double dFudU, dFudV, dFudW;
624
double dFvdU, dFvdV, dFvdW;
625
double dFwdU, dFwdV, dFwdW;
626
627
int i,n;
628
629
element_type_t *elmt = elm->ElementType;
630
631
double *NodeU = elmt->NodeU;
632
double *NodeV = elmt->NodeV;
633
double *NodeW = elmt->NodeW;
634
635
double (*dNdU)() = elmt->PartialU;
636
double (*dNdV)() = elmt->PartialV;
637
double (*dNdW)() = elmt->PartialW;
638
639
for( i=0; i<elmt->NumberOfNodes; i++ )
640
{
641
n = elm->Topology[i];
642
X[i] = model->NodeArray[n];
643
Y[i] = model->NodeArray[model->NofNodes+n];
644
Z[i] = model->NodeArray[2*model->NofNodes+n];
645
}
646
647
for( i=0; i<elmt->NumberOfNodes; i++ )
648
{
649
u = NodeU[i];
650
v = NodeV[i];
651
w = NodeW[i];
652
653
dXdU = (*dNdU)( X,u,v,w );
654
dYdU = (*dNdU)( Y,u,v,w );
655
dZdU = (*dNdU)( Z,u,v,w );
656
657
dXdV = (*dNdV)( X,u,v,w );
658
dYdV = (*dNdV)( Y,u,v,w );
659
dZdV = (*dNdV)( Z,u,v,w );
660
661
dXdW = (*dNdW)( X,u,v,w );
662
dYdW = (*dNdW)( Y,u,v,w );
663
dZdW = (*dNdW)( Z,u,v,w );
664
665
Fu[i] = FX[i]*dXdU + FY[i]*dYdU + FZ[i]*dZdU;
666
Fv[i] = FX[i]*dXdV + FY[i]*dYdV + FZ[i]*dZdV;
667
Fw[i] = FX[i]*dXdW + FY[i]*dYdW + FZ[i]*dZdW;
668
}
669
670
for( i=0; i<elmt->NumberOfNodes; i++ )
671
{
672
u = NodeU[i];
673
v = NodeV[i];
674
w = NodeW[i];
675
676
dXdU = (*dNdU)( X,u,v,w );
677
dYdU = (*dNdU)( Y,u,v,w );
678
dZdU = (*dNdU)( Z,u,v,w );
679
680
dFudU = (*dNdU)( Fu,u,v,w );
681
dFvdU = (*dNdU)( Fv,u,v,w );
682
dFwdU = (*dNdU)( Fw,u,v,w );
683
684
dXdV = (*dNdV)( X,u,v,w );
685
dYdV = (*dNdV)( Y,u,v,w );
686
dZdV = (*dNdV)( Z,u,v,w );
687
688
dFudV = (*dNdV)( Fu,u,v,w );
689
dFvdV = (*dNdV)( Fv,u,v,w );
690
dFwdV = (*dNdV)( Fw,u,v,w );
691
692
dXdW = (*dNdW)( X,u,v,w );
693
dYdW = (*dNdW)( Y,u,v,w );
694
dZdW = (*dNdW)( Z,u,v,w );
695
696
dFudW = (*dNdW)( Fu,u,v,w );
697
dFvdW = (*dNdW)( Fv,u,v,w );
698
dFwdW = (*dNdW)( Fw,u,v,w );
699
700
Auu = dXdU*dXdU + dYdU*dYdU + dZdU*dZdU;
701
Auv = dXdU*dXdV + dYdU*dYdV + dZdU*dZdV;
702
Auw = dXdU*dXdW + dYdU*dYdW + dZdU*dZdW;
703
Avu = dXdV*dXdU + dYdV*dYdU + dZdV*dZdU;
704
Avv = dXdV*dXdV + dYdV*dYdV + dZdV*dZdV;
705
Avw = dXdV*dXdW + dYdV*dYdW + dZdV*dZdW;
706
Awu = dXdW*dXdU + dYdW*dYdU + dZdW*dZdU;
707
Awv = dXdW*dXdV + dYdW*dYdV + dZdW*dZdV;
708
Aww = dXdW*dXdW + dYdW*dYdW + dZdW*dZdW;
709
710
detA = Auu*(Avv*Aww - Avw*Awv);
711
detA += Auv*(Avw*Awu - Avu*Aww);
712
detA += Auw*(Avu*Awv - Avv*Awu);
713
714
if ( ABS(detA) < AEPS ) return FALSE;
715
716
u = (dFwdV - dFvdW) / sqrt( detA );
717
v = (dFudW - dFwdU) / sqrt( detA );
718
w = (dFvdU - dFudV) / sqrt( detA );
719
720
RX[i] = u*dXdU + v*dXdV + w*dXdW;
721
RY[i] = u*dYdU + v*dYdV + w*dYdW;
722
RZ[i] = u*dZdU + v*dZdV + w*dZdW;
723
}
724
725
return TRUE;
726
}
727
728
/*******************************************************************************
729
*
730
* Name: elm_rotor_3D
731
*
732
* Purpose: Compute rotor of given quantity for volume elements.
733
*
734
* Parameters:
735
*
736
* Input:
737
*
738
* Output:
739
*
740
* Return value: void
741
*
742
******************************************************************************/
743
VARIABLE *elm_rotor_3D( VARIABLE *A )
744
{
745
static double RotorX[ELM_MAX_ELEMENT_NODES];
746
static double RotorY[ELM_MAX_ELEMENT_NODES];
747
static double RotorZ[ELM_MAX_ELEMENT_NODES];
748
749
static double FX[ELM_MAX_ELEMENT_NODES];
750
static double FY[ELM_MAX_ELEMENT_NODES];
751
static double FZ[ELM_MAX_ELEMENT_NODES];
752
753
element_type_t *elmt;
754
element_t *elm;
755
element_model_t *model = CurrentObject->ElementModel; /*** TODO: FIX ***/
756
757
unsigned char *References = (unsigned char *)malloc( model->NofNodes*sizeof(unsigned char) );
758
759
int i,j,k,n, cols;
760
761
double *ax = &M(A,0,0);
762
double *ay = &M(A,1,0);
763
double *az = &M(A,2,0);
764
765
VARIABLE *res;
766
767
double *rx, *ry, *rz;
768
769
cols = NCOL(A) / model->NofNodes;
770
if ( NROW(A) != 3 )
771
{
772
free( References );
773
error( "curl: vector variable needed as input.\n" );
774
}
775
776
res = var_temp_new( TYPE_DOUBLE, 3, cols*model->NofNodes );
777
rx = &M(res,0,0);
778
ry = &M(res,1,0);
779
rz = &M(res,2,0);
780
781
for( k=0; k<cols; k++ )
782
{
783
for( j=0; j<model->NofNodes; j++ )
784
{
785
n = k*model->NofNodes + j;
786
rx[n] = 0.0;
787
ry[n] = 0.0;
788
rz[n] = 0.0;
789
References[j] = 0;
790
}
791
792
for( i=0; i<model->NofElements; i++ )
793
{
794
elm = &model->Elements[i];
795
elmt = elm->ElementType;
796
797
if ( elmt->ElementCode <500 ) continue;
798
799
for( j=0; j<elmt->NumberOfNodes; j++ )
800
{
801
n = k*model->NofNodes + elm->Topology[j];
802
FX[j] = ax[n];
803
FY[j] = ay[n];
804
FZ[j] = az[n];
805
}
806
807
if ( !elm_element_rotor_3D( model,elm,FX,FY,FZ,RotorX,RotorY,RotorZ ) )
808
{
809
fprintf( stderr, "ELEMENT [%d]: Jacobian is singular.\n",i );
810
continue;
811
}
812
813
for( j=0; j<elmt->NumberOfNodes; j++ )
814
{
815
n = elm->Topology[j];
816
References[n]++;
817
818
n += k*model->NofNodes;
819
rx[n] += RotorX[j];
820
ry[n] += RotorY[j];
821
rz[n] += RotorZ[j];
822
}
823
}
824
825
for( j=0; j<model->NofNodes; j++ )
826
{
827
if ( References[j] != 0 )
828
{
829
n = k*model->NofNodes + j;
830
rx[n] /= References[j];
831
ry[n] /= References[j];
832
rz[n] /= References[j];
833
}
834
}
835
}
836
837
free( References );
838
return res;
839
}
840
841
/*******************************************************************************
842
*
843
* Name: elm_element_divergence_2D
844
*
845
* Purpose: Compute elementwise divergence of given quantity for a surface
846
* element.
847
*
848
* Parameters:
849
*
850
* Input: (element_t *)elm structure describing the element
851
* (double *)FX node values of vector x component.
852
* (double *)FY node values of vector x component.
853
* (double *)FZ node values of vector x component.
854
*
855
* Output: Rotor (double *)D
856
*
857
* Return value: FALSE if element is degenerated, TRUE otherwise.
858
*
859
******************************************************************************/
860
int elm_element_divergence_2D
861
(
862
element_model_t *model, element_t *elm, double *FX, double *FY, double *FZ, double *D
863
)
864
{
865
static double X[ELM_MAX_ELEMENT_NODES];
866
static double Y[ELM_MAX_ELEMENT_NODES];
867
static double Z[ELM_MAX_ELEMENT_NODES];
868
869
static double Fu[ELM_MAX_ELEMENT_NODES];
870
static double Fv[ELM_MAX_ELEMENT_NODES];
871
872
static double s,detA[ELM_MAX_ELEMENT_NODES];
873
874
double u,v,w,a;
875
876
double Auu,Auv,Avu,Avv;
877
double Buu,Buv,Bvu,Bvv;
878
879
double dXdU,dYdU,dZdU;
880
double dXdV,dYdV,dZdV;
881
882
double dFudU, dFudV;
883
double dFvdU, dFvdV;
884
double dFwdU, dFwdV;
885
886
int i,n;
887
888
element_type_t *elmt = elm->ElementType;
889
890
double *NodeU = elmt->NodeU;
891
double *NodeV = elmt->NodeV;
892
893
double (*dNdU)() = elmt->PartialU;
894
double (*dNdV)() = elmt->PartialV;
895
896
for( i=0; i<elmt->NumberOfNodes; i++ )
897
{
898
n = elm->Topology[i];
899
X[i] = model->NodeArray[n];
900
Y[i] = model->NodeArray[model->NofNodes+n];
901
Z[i] = model->NodeArray[2*model->NofNodes+n];
902
}
903
904
for( i=0; i<elmt->NumberOfNodes; i++ )
905
{
906
u = NodeU[i];
907
v = NodeV[i];
908
909
dXdU = (*dNdU)( X,u,v );
910
dYdU = (*dNdU)( Y,u,v );
911
dZdU = (*dNdU)( Z,u,v );
912
913
dXdV = (*dNdV)( X,u,v );
914
dYdV = (*dNdV)( Y,u,v );
915
dZdV = (*dNdV)( Z,u,v );
916
917
Auu = dXdU*dXdU + dYdU*dYdU + dZdU*dZdU;
918
Auv = dXdU*dXdV + dYdU*dYdV + dZdU*dZdV;
919
Avu = dXdV*dXdU + dYdV*dYdU + dZdV*dZdU;
920
Avv = dXdV*dXdV + dYdV*dYdV + dZdV*dZdV;
921
922
s = Auu*Avv - Auv*Avu;
923
if ( ABS(s) < AEPS ) return FALSE;
924
925
s = 1 / s;
926
927
Buu = Avv * s;
928
Buv = -Auv * s;
929
Bvu = -Avu * s;
930
Bvv = Auu * s;
931
932
u = FX[i]*dXdU + FY[i]*dYdU + FZ[i]*dZdU;
933
v = FX[i]*dXdV + FY[i]*dYdV + FZ[i]*dZdV;
934
935
s = detA[i] = sqrt( s );
936
Fu[i] = (Buu*u + Buv*v) / s;
937
Fv[i] = (Bvu*u + Bvv*v) / s;
938
}
939
940
for( i=0; i<elmt->NumberOfNodes; i++ )
941
{
942
u = NodeU[i];
943
v = NodeV[i];
944
945
dFudU = (*dNdU)( Fu,u,v );
946
dFvdV = (*dNdV)( Fv,u,v );
947
948
D[i] = (dFudU + dFvdV) * detA[i];
949
}
950
951
return TRUE;
952
}
953
954
/*******************************************************************************
955
*
956
* Name: elm_element_divergence_3D
957
*
958
* Purpose: Compute elementwise divergence of given quantity for a volume
959
* element.
960
*
961
* Parameters:
962
*
963
* Input: (element_t *)elm structure describing the element
964
* (double *)FX node values of vector x component.
965
* (double *)FY node values of vector x component.
966
* (double *)FZ node values of vector x component.
967
*
968
* Output: Rotor (double *)D
969
*
970
* Return value: FALSE if element is degenerated, TRUE otherwise.
971
*
972
******************************************************************************/
973
int elm_element_divergence_3D
974
(
975
element_model_t *model, element_t *elm, double *FX, double *FY, double *FZ, double *D
976
)
977
{
978
static double X[ELM_MAX_ELEMENT_NODES];
979
static double Y[ELM_MAX_ELEMENT_NODES];
980
static double Z[ELM_MAX_ELEMENT_NODES];
981
982
static double Fu[ELM_MAX_ELEMENT_NODES];
983
static double Fv[ELM_MAX_ELEMENT_NODES];
984
static double Fw[ELM_MAX_ELEMENT_NODES];
985
static double s,detA[ELM_MAX_ELEMENT_NODES];
986
987
double u,v,w,a;
988
989
double Auu,Auv,Auw,Avu,Avv,Avw,Awu,Awv,Aww;
990
double Buu,Buv,Buw,Bvu,Bvv,Bvw,Bwu,Bwv,Bww;
991
992
double dXdU,dXdV,dXdW;
993
double dYdU,dYdV,dYdW;
994
double dZdU,dZdV,dZdW;
995
996
double dFudU, dFvdV, dFwdW;
997
998
int i,n;
999
1000
element_type_t *elmt = elm->ElementType;
1001
1002
double *NodeU = elmt->NodeU;
1003
double *NodeV = elmt->NodeV;
1004
double *NodeW = elmt->NodeW;
1005
1006
double (*dNdU)() = elmt->PartialU;
1007
double (*dNdV)() = elmt->PartialV;
1008
double (*dNdW)() = elmt->PartialW;
1009
1010
for( i=0; i<elmt->NumberOfNodes; i++ )
1011
{
1012
n = elm->Topology[i];
1013
X[i] = model->NodeArray[n];
1014
Y[i] = model->NodeArray[model->NofNodes+n];
1015
Z[i] = model->NodeArray[2*model->NofNodes+n];
1016
}
1017
1018
for( i=0; i<elmt->NumberOfNodes; i++ )
1019
{
1020
u = NodeU[i];
1021
v = NodeV[i];
1022
w = NodeW[i];
1023
1024
dXdU = (*dNdU)( X,u,v,w );
1025
dYdU = (*dNdU)( Y,u,v,w );
1026
dZdU = (*dNdU)( Z,u,v,w );
1027
1028
dXdV = (*dNdV)( X,u,v,w );
1029
dYdV = (*dNdV)( Y,u,v,w );
1030
dZdV = (*dNdV)( Z,u,v,w );
1031
1032
dXdW = (*dNdW)( X,u,v,w );
1033
dYdW = (*dNdW)( Y,u,v,w );
1034
dZdW = (*dNdW)( Z,u,v,w );
1035
1036
Auu = dXdU*dXdU + dYdU*dYdU + dZdU*dZdU;
1037
Auv = dXdU*dXdV + dYdU*dYdV + dZdU*dZdV;
1038
Auw = dXdU*dXdW + dYdU*dYdW + dZdU*dZdW;
1039
1040
Avu = dXdV*dXdU + dYdV*dYdU + dZdV*dZdU;
1041
Avv = dXdV*dXdV + dYdV*dYdV + dZdV*dZdV;
1042
Avw = dXdV*dXdW + dYdV*dYdW + dZdV*dZdW;
1043
1044
Awu = dXdW*dXdU + dYdW*dYdU + dZdW*dZdU;
1045
Awv = dXdW*dXdV + dYdW*dYdV + dZdW*dZdV;
1046
Aww = dXdW*dXdW + dYdW*dYdW + dZdW*dZdW;
1047
1048
s = Auu*(Avv*Aww - Avw*Awv);
1049
s += Auv*(Avw*Awu - Avu*Aww);
1050
s += Auw*(Avu*Awv - Avv*Awu);
1051
if ( ABS(s) < AEPS ) return FALSE;
1052
1053
s = 1 / s;
1054
1055
Buu = (Avv*Aww - Avw*Awv) * s;
1056
Bvu = (Avw*Awu - Avu*Aww) * s;
1057
Bwu = (Avu*Awv - Avv*Awu) * s;
1058
1059
Buv = (Awv*Auw - Auv*Aww) * s;
1060
Bvv = (Auu*Aww - Awu*Auw) * s;
1061
Bwv = (Auv*Awu - Auu*Awv) * s;
1062
1063
Buw = (Auv*Avw - Avv*Auw) * s;
1064
Bvw = (Avu*Auw - Auu*Avw) * s;
1065
Bww = (Auu*Avv - Avu*Auv) * s;
1066
1067
u = FX[i]*dXdU + FY[i]*dYdU + FZ[i]*dZdU;
1068
v = FX[i]*dXdV + FY[i]*dYdV + FZ[i]*dZdV;
1069
w = FX[i]*dXdW + FY[i]*dYdW + FZ[i]*dZdV;
1070
1071
s = detA[i] = sqrt( s );
1072
Fu[i] = (Buu*u + Buv*v + Buw*w) / s;
1073
Fv[i] = (Bvu*u + Bvv*v + Bvw*w) / s;
1074
Fw[i] = (Bwu*u + Bwv*v + Bww*w) / s;
1075
}
1076
1077
for( i=0; i<elmt->NumberOfNodes; i++ )
1078
{
1079
u = NodeU[i];
1080
v = NodeV[i];
1081
w = NodeV[i];
1082
1083
D[i] = (*dNdU)( Fu,u,v,w );
1084
D[i] += (*dNdV)( Fv,u,v,w );
1085
D[i] += (*dNdW)( Fw,u,v,w );
1086
D[i] *= detA[i];
1087
}
1088
1089
return TRUE;
1090
}
1091
1092
/*******************************************************************************
1093
*
1094
* Name: elm_divergence
1095
*
1096
* Purpose: Compute divergence of given quantity.
1097
*
1098
* Parameters:
1099
*
1100
* Input:
1101
*
1102
* Output:
1103
*
1104
* Return value: void
1105
*
1106
******************************************************************************/
1107
VARIABLE *elm_divergence( VARIABLE *A )
1108
{
1109
static double FX[ELM_MAX_ELEMENT_NODES];
1110
static double FY[ELM_MAX_ELEMENT_NODES];
1111
static double FZ[ELM_MAX_ELEMENT_NODES];
1112
1113
static double D[ELM_MAX_ELEMENT_NODES];
1114
1115
element_type_t *elmt;
1116
element_t *elm;
1117
element_model_t *model = CurrentObject->ElementModel; /*** TODO: FIX ***/
1118
1119
unsigned char *References = (unsigned char *)malloc( model->NofNodes*sizeof(unsigned char) );
1120
1121
int i,j,k,n,status,dim,cols;
1122
1123
double *ax = &M(A,0,0);
1124
double *ay = &M(A,1,0);
1125
double *az = &M(A,2,0);
1126
1127
VARIABLE *res;
1128
double *rf;
1129
1130
cols = NCOL(A) / model->NofNodes;
1131
if ( NROW(A) != 3 )
1132
{
1133
free( References );
1134
error( "div: vector variable needed as input.\n" );
1135
}
1136
1137
dim = 1;
1138
for( k=0; k<model->NofElements; k++ )
1139
if ( model->Elements[k].ElementType->ElementCode>=500 ) {
1140
dim=3;
1141
break;
1142
} else if ( model->Elements[k].ElementType->ElementCode>=300 )
1143
dim=2;
1144
1145
res = var_temp_new( TYPE_DOUBLE, 1, model->NofNodes*cols );
1146
rf = MATR(res);
1147
1148
for( k=0; k<cols; k++ )
1149
{
1150
for( j=0; j<model->NofNodes; j++ )
1151
{
1152
rf[k*model->NofNodes+j] = 0.0;
1153
References[j] = 0;
1154
}
1155
1156
for( i=0; i<model->NofElements; i++ )
1157
{
1158
elm = &model->Elements[i];
1159
elmt = elm->ElementType;
1160
1161
for( j=0; j<elmt->NumberOfNodes; j++ )
1162
{
1163
n = k*model->NofNodes + elm->Topology[j];
1164
FX[j] = ax[n];
1165
FY[j] = ay[n];
1166
FZ[j] = az[n];
1167
}
1168
1169
if ( dim==3 && elmt->PartialW )
1170
status = elm_element_divergence_3D( model,elm,FX,FY,FZ,D );
1171
else if ( dim==2 && elmt->PartialV )
1172
status = elm_element_divergence_2D( model,elm,FX,FY,FZ,D );
1173
else continue;
1174
1175
if ( !status )
1176
{
1177
fprintf( stderr, "ELEMENT [%d]: Jacobian is singular.\n",i );
1178
continue;
1179
}
1180
1181
for( j=0; j<elmt->NumberOfNodes; j++ )
1182
{
1183
n = elm->Topology[j];
1184
References[n]++;
1185
rf[k*model->NofNodes + n] += D[j];
1186
}
1187
}
1188
1189
for( j=0; j<model->NofNodes; j++ )
1190
{
1191
if ( References[j] != 0 )
1192
{
1193
n = k*model->NofNodes + j;
1194
rf[n] /= References[j];
1195
}
1196
}
1197
}
1198
1199
free( References );
1200
return res;
1201
}
1202
1203
1204
/*******************************************************************************
1205
*
1206
* Name: elm_element_ddx_2D
1207
*
1208
* Purpose: Compute elementwise matrix of second partial derivates
1209
* for surface elements at given point u,v.
1210
*
1211
* Parameters:
1212
*
1213
* Input: (element_t *) structure describing the element
1214
* (double *) F nodel values of the quantity
1215
* (double *) u,v point at which to evaluate
1216
*
1217
* Output: 3x3 matrix of partial derivates
1218
*
1219
* Return value: FALSE if element is degenerated, TRUE otherwise.
1220
*
1221
******************************************************************************/
1222
int elm_element_ddx_2D(
1223
element_model_t *model, element_t *elm, double *F,
1224
double u,double v,double *Values
1225
)
1226
{
1227
static double X[ELM_MAX_ELEMENT_NODES];
1228
static double Y[ELM_MAX_ELEMENT_NODES];
1229
static double Z[ELM_MAX_ELEMENT_NODES];
1230
1231
static double partials[4];
1232
1233
int i,n;
1234
1235
double ddfddx,ddfddy,ddfddz,ddfdxdy,ddfdxdz,ddfdydz;
1236
double ddfddu,ddfddv,ddfdudv,dfdu,dfdv, Cddfddu,Cddfddv,Cddfdudv;
1237
1238
double ddxddu,ddxddv,ddxdudv,dxdu,dxdv;
1239
double ddyddu,ddyddv,ddydudv,dydu,dydv;
1240
double ddzddu,ddzddv,ddzdudv,dzdu,dzdv;
1241
1242
double a,G_uu,G_vv,G_uv,H_uu,H_uv,H_vu,H_vv, detG;
1243
double C1_uu_u,C1_uu_v,C1_uv_u,C1_uv_v,C1_vv_u,C1_vv_v;
1244
double C2_uu_u,C2_uu_v,C2_uv_u,C2_uv_v,C2_vv_u,C2_vv_v;
1245
1246
element_type_t *elmt = elm->ElementType;
1247
1248
double (*dNdU)() = elmt->PartialU;
1249
double (*dNdV)() = elmt->PartialV;
1250
1251
double (*ddN)() = elmt->SecondPartials;
1252
1253
for( i=0; i<elmt->NumberOfNodes; i++ )
1254
{
1255
n = elm->Topology[i];
1256
X[i] = model->NodeArray[n];
1257
Y[i] = model->NodeArray[model->NofNodes+n];
1258
Z[i] = model->NodeArray[2*model->NofNodes+n];
1259
}
1260
1261
dxdu = (*dNdU)( X,u,v );
1262
dydu = (*dNdU)( Y,u,v );
1263
dzdu = (*dNdU)( Z,u,v );
1264
1265
dxdv = (*dNdV)( X,u,v );
1266
dydv = (*dNdV)( Y,u,v );
1267
dzdv = (*dNdV)( Z,u,v );
1268
1269
(*ddN)( X,u,v,partials );
1270
ddxddu = partials[0];
1271
ddxdudv = partials[1];
1272
ddxddv = partials[3];
1273
1274
(*ddN)( Y,u,v,partials );
1275
ddyddu = partials[0];
1276
ddydudv = partials[1];
1277
ddyddv = partials[3];
1278
1279
(*ddN)( Z,u,v,partials );
1280
ddzddu = partials[0];
1281
ddzdudv = partials[1];
1282
ddzddv = partials[3];
1283
1284
/*
1285
* covariant metric tensor
1286
*
1287
* TODO: multiply by global metric if not identity
1288
*/
1289
G_uu = dxdu * dxdu + dydu * dydu + dzdu * dzdu;
1290
G_vv = dxdv * dxdv + dydv * dydv + dzdv * dzdv;
1291
G_uv = dxdu * dxdv + dydu * dydv + dzdu * dzdv;
1292
detG = G_uu*G_vv - G_uv*G_uv;
1293
if ( ABS(detG)<AEPS ) return FALSE;
1294
1295
/*
1296
* contravariant metric tensor
1297
*/
1298
H_uu = G_vv / detG;
1299
H_uv = -G_uv / detG;
1300
H_vu = -G_uv / detG;
1301
H_vv = G_uu / detG;
1302
1303
/*
1304
* christoffel symbols of the second kind
1305
*
1306
* TODO: this is for cartesian global coordinates only...
1307
*/
1308
C2_uu_u = ddxddu * dxdu + ddyddu * dydu + ddzddu * dzdu;
1309
C2_uu_v = ddxddu * dxdv + ddyddu * dydv + ddzddu * dzdv;
1310
1311
C2_uv_u = ddxdudv * dxdu + ddydudv * dydu + ddzdudv * dzdu;
1312
C2_uv_v = ddxdudv * dxdv + ddydudv * dydv + ddzdudv * dzdv;
1313
1314
C2_vv_u = ddxddv * dxdu + ddyddv * dydu + ddzddv * dzdu;
1315
C2_vv_v = ddxddv * dxdv + ddyddv * dydv + ddzddv * dzdv;
1316
1317
/*
1318
* christoffel symbols of the first kind
1319
*/
1320
C1_uu_u = H_uu * C2_uu_u + H_uv * C2_uu_v;
1321
C1_uu_v = H_vu * C2_uu_u + H_vv * C2_uu_v;
1322
1323
C1_uv_u = H_uu * C2_uv_u + H_uv * C2_uv_v;
1324
C1_uv_v = H_vu * C2_uv_u + H_vv * C2_uv_v;
1325
1326
C1_vv_u = H_uu * C2_vv_u + H_uv * C2_vv_v;
1327
C1_vv_v = H_vu * C2_vv_u + H_vv * C2_vv_v;
1328
1329
/*
1330
* now we are ready to compute second covariant derivates of f
1331
*/
1332
dfdu = (*dNdU)( F,u,v );
1333
dfdv = (*dNdU)( F,u,v );
1334
1335
(*ddN)( F,u,v,partials );
1336
ddfddu = partials[0];
1337
ddfdudv = partials[1];
1338
ddfddv = partials[3];
1339
1340
ddfddu -= C1_uu_u * dfdu + C1_uu_v * dfdv;
1341
ddfddv -= C1_vv_u * dfdu + C1_vv_v * dfdv;
1342
ddfdudv -= C1_uv_u * dfdu + C1_uv_v * dfdv;
1343
1344
/*
1345
* convert to contravariant form
1346
*/
1347
Cddfddu = H_uu * (H_uu * ddfddu + H_uv * ddfdudv) + H_uv * (H_uu * ddfdudv + H_uv * ddfddv);
1348
Cddfddv = H_vu * (H_vu * ddfddu + H_vv * ddfdudv) + H_vv * (H_vu * ddfdudv + H_vv * ddfddv);
1349
Cddfdudv = H_uu * (H_vu * ddfddu + H_vv * ddfdudv) + H_uv * (H_vu * ddfdudv + H_vv * ddfddv);
1350
1351
/*
1352
* transform to global coordinates
1353
*
1354
* TODO: lower indexes if not cartesian x,y,z
1355
*/
1356
ddfddx = dxdu * dxdu * Cddfddu + dxdv * dxdv * Cddfddv + 2 * dxdu * dxdv * Cddfdudv;
1357
ddfddy = dydu * dydu * Cddfddu + dydv * dydv * Cddfddv + 2 * dydu * dydv * Cddfdudv;
1358
ddfddz = dzdu * dzdu * Cddfddu + dzdv * dzdv * Cddfddv + 2 * dzdu * dzdv * Cddfdudv;
1359
1360
ddfdxdy = dxdu * dydu * Cddfddu + (dxdu * dydv + dxdv * dydu) * Cddfdudv + dxdv * dydv * Cddfddv;
1361
ddfdxdz = dxdu * dzdu * Cddfddu + (dxdu * dzdv + dxdv * dzdu) * Cddfdudv + dxdv * dzdv * Cddfddv;
1362
ddfdydz = dydu * dzdu * Cddfddu + (dydu * dzdv + dydv * dzdu) * Cddfdudv + dydv * dzdv * Cddfddv;
1363
1364
Values[0] = ddfddx;
1365
Values[1] = ddfdxdy;
1366
Values[2] = ddfdxdz;
1367
Values[3] = ddfdxdy;
1368
Values[4] = ddfddy;
1369
Values[5] = ddfdydz;
1370
Values[6] = ddfdxdz;
1371
Values[7] = ddfdydz;
1372
Values[8] = ddfddz;
1373
1374
return TRUE;
1375
}
1376
1377