Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/Differentials.F90
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 library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library 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 GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
!
24
!/******************************************************************************
25
! *
26
! * Authors: Juha Ruokolainen
27
! * Email: [email protected]
28
! * Web: http://www.csc.fi/elmer
29
! * Address: CSC - IT Center for Science Ltd.
30
! * Keilaranta 14
31
! * 02101 Espoo, Finland
32
! *
33
! * Original Date: 02 Jun 1997
34
! *
35
! *****************************************************************************/
36
37
!> \ingroup ElmerLib
38
!> \{
39
40
!-----------------------------------------------------------------------------
41
!> This module contains some built-in material laws, and also some
42
!> vector utilities, curl, dot, cross, etc. Some of these may be
43
!> of no use currently.
44
!-----------------------------------------------------------------------------
45
MODULE Differentials
46
47
USE Types
48
USE Lists
49
USE LinearAlgebra
50
USE CoordinateSystems
51
USE ElementDescription, ONLY : ElementInfo
52
53
IMPLICIT NONE
54
55
CONTAINS
56
57
!------------------------------------------------------------------------------
58
!> Computes the Lorentz force resulting from a magnetic field at
59
!> integration point (u,v,w).
60
!------------------------------------------------------------------------------
61
FUNCTION LorentzForce( Element,Nodes,u,v,w,n ) RESULT(L)
62
!------------------------------------------------------------------------------
63
TYPE(Element_t), POINTER :: Element
64
TYPE(Nodes_t) :: Nodes
65
INTEGER :: n
66
REAL(KIND=dp) :: L(3),u,v,w,x,y,z
67
!------------------------------------------------------------------------------
68
TYPE(Variable_t), POINTER :: Mx,My,Mz,MFx,MFy,MFz
69
INTEGER :: i,j,k,bfId
70
LOGICAL :: stat,GotIt
71
INTEGER, POINTER :: NodeIndexes(:)
72
73
TYPE(ValueList_t), POINTER :: Material
74
75
REAL(KIND=dp) :: B(3),dHdx(3,3)
76
REAL(KIND=dp) :: dBasisdx(n,3),SqrtElementMetric
77
REAL(KIND=dp) :: Basis(n),Permeability(n),mu
78
79
REAL(KIND=dp) :: ExtMx(n),ExtMy(n),ExtMz(n)
80
81
REAL(KIND=dp) :: SqrtMetric,Metric(3,3),Symb(3,3,3),dSymb(3,3,3,3)
82
!------------------------------------------------------------------------------
83
L = 0.0D0
84
85
! bfId = ListGetInteger( CurrentModel % Bodies( Element % BodyId ) % Values, &
86
! 'Body Force', GotIt, 1, CurrentModel % NumberOFBodyForces )
87
88
! IF ( .NOT.GotIt ) RETURN
89
90
! IF ( .NOT.ListGetLogical( CurrentModel % BodyForces( &
91
! bfId ) % Values, 'Lorentz Force' , GotIt ) ) RETURN
92
!------------------------------------------------------------------------------
93
NodeIndexes => Element % NodeIndexes
94
95
Mx => VariableGet( CurrentModel % Variables, 'Magnetic Field 1' )
96
My => VariableGet( CurrentModel % Variables, 'Magnetic Field 2' )
97
Mz => VariableGet( CurrentModel % Variables, 'Magnetic Field 3' )
98
IF ( .NOT.ASSOCIATED( Mx ) ) RETURN
99
100
IF ( ANY(Mx % Perm(NodeIndexes)<=0) ) RETURN
101
102
k = ListGetInteger( CurrentModel % Bodies &
103
(Element % BodyId) % Values, 'Material', &
104
minv=1, maxv=CurrentModel % NumberOFMaterials )
105
Material => CurrentModel % Materials(k) % Values
106
107
Permeability(1:n) = ListGetReal( Material, 'Magnetic Permeability', &
108
n, NodeIndexes )
109
!------------------------------------------------------------------------------
110
ExtMx(1:n) = ListGetReal( Material, 'Applied Magnetic Field 1', &
111
n,NodeIndexes, Gotit )
112
113
ExtMy(1:n) = ListGetReal( Material, 'Applied Magnetic Field 2', &
114
n,NodeIndexes, Gotit )
115
116
ExtMz(1:n) = ListGetReal( Material, 'Applied Magnetic Field 3', &
117
n,NodeIndexes, Gotit )
118
119
! If you want to use time-domain solution for high-frequendy part,
120
! leave external field out. Better to use frequency-domain solver!
121
#if 1
122
MFx => VariableGet( CurrentModel % Variables, 'Magnetic Flux Density 1' )
123
MFy => VariableGet( CurrentModel % Variables, 'Magnetic Flux Density 2' )
124
MFz => VariableGet( CurrentModel % Variables, 'Magnetic Flux Density 3' )
125
IF ( ASSOCIATED( MFx ) ) THEN
126
ExtMx(1:n) = ExtMx(1:n) + MFx % Values(MFx % Perm(NodeIndexes))
127
ExtMy(1:n) = ExtMy(1:n) + MFy % Values(MFy % Perm(NodeIndexes))
128
ExtMz(1:n) = ExtMz(1:n) + MFz % Values(MFz % Perm(NodeIndexes))
129
END IF
130
#endif
131
132
!------------------------------------------------------------------------------
133
! Get element info
134
!------------------------------------------------------------------------------
135
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric, &
136
Basis,dBasisdx )
137
!------------------------------------------------------------------------------
138
B(1) = SUM( Basis(1:n)*Mx % Values(Mx % Perm(NodeIndexes)) )
139
B(2) = SUM( Basis(1:n)*My % Values(My % Perm(NodeIndexes)) )
140
B(3) = SUM( Basis(1:n)*Mz % Values(Mz % Perm(NodeIndexes)) )
141
142
B(1) = B(1) + SUM( Basis(1:n)*ExtMx(1:n) )
143
B(2) = B(2) + SUM( Basis(1:n)*ExtMy(1:n) )
144
B(3) = B(3) + SUM( Basis(1:n)*ExtMz(1:n) )
145
146
DO i=1,3
147
dHdx(1,i) = SUM( dBasisdx(1:n,i)* &
148
Mx % Values(Mx % Perm(NodeIndexes)) / Permeability(1:n) )
149
dHdx(2,i) = SUM( dBasisdx(1:n,i)* &
150
My % Values(My % Perm(NodeIndexes)) / Permeability(1:n) )
151
dHdx(3,i) = SUM( dBasisdx(1:n,i)* &
152
Mz % Values(Mz % Perm(NodeIndexes)) / Permeability(1:n) )
153
END DO
154
!------------------------------------------------------------------------------
155
! Get coordinate system info
156
!------------------------------------------------------------------------------
157
x = SUM( Nodes % x(1:n) * Basis(1:n) )
158
y = SUM( Nodes % y(1:n) * Basis(1:n) )
159
z = SUM( Nodes % z(1:n) * Basis(1:n) )
160
CALL CoordinateSystemInfo( Metric,SqrtMetric,Symb,dSymb,x,y,z )
161
IF ( CurrentCoordinateSystem() /= Cartesian ) CALL InvertMatrix( Metric,3 )
162
163
mu = SUM( Permeability(1:n)*Basis(1:n) )
164
L = ComputeLorentz( B,dHdx,mu,SqrtMetric,Metric,Symb )
165
166
CONTAINS
167
168
!------------------------------------------------------------------------------
169
FUNCTION ComputeLorentz( B,dHdx,mu,SqrtMetric,Metric,Symb ) RESULT(LF)
170
!------------------------------------------------------------------------------
171
REAL(KIND=dp) :: B(:),dHdx(:,:),mu,LF(3),SqrtMetric,Metric(:,:),Symb(:,:,:)
172
!------------------------------------------------------------------------------
173
INTEGER :: i,j,k,l,m
174
REAL(KIND=dp) :: Bc(3),Ji(3),Jc(3),s,Perm(3,3,3),r
175
!------------------------------------------------------------------------------
176
177
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
178
Ji(1) = dHdx(3,2) - dHdx(2,3)
179
Ji(2) = dHdx(1,3) - dHdx(3,1)
180
Ji(3) = dHdx(2,1) - dHdx(1,2)
181
LF(1) = Ji(2)*B(3) - Ji(3)*B(2)
182
LF(2) = Ji(3)*B(1) - Ji(1)*B(3)
183
LF(3) = Ji(1)*B(2) - Ji(2)*B(1)
184
RETURN
185
END IF
186
187
r = SqrtMetric
188
189
IF ( CurrentCoordinateSystem() == CylindricSymmetric ) THEN
190
Ji(1) = -dHdx(3,2)
191
Ji(2) = dHdx(3,1)
192
IF (r > 1.0d-10) THEN
193
Ji(2) = Ji(2) + B(3)/(r*mu)
194
ELSE
195
Ji(2) = Ji(2) + Ji(2)
196
END IF
197
Ji(3) = dHdx(1,2) - dHdx(2,1)
198
199
LF(1) = Ji(3)*B(2) - Ji(2)*B(3)
200
LF(2) = Ji(1)*B(3) - Ji(3)*B(1)
201
! You might want to use SI units for the azimuthal component,
202
! if you compute Lorentz force at nodal points and symmetry axis,
203
! otherwise you divide by zero.
204
#ifdef SI_UNITS
205
LF(3) = Ji(2)*B(1) - Ji(1)*B(2)
206
#else
207
IF (r > 1.0d-10) THEN
208
LF(3) = ( Ji(2)*B(1) - Ji(1)*B(2) ) / r
209
ELSE
210
LF(3) = 0.d0
211
END IF
212
#endif
213
RETURN
214
END IF
215
216
Perm = 0
217
Perm(1,2,3) = -1.0d0 / SqrtMetric
218
Perm(1,3,2) = 1.0d0 / SqrtMetric
219
Perm(2,1,3) = 1.0d0 / SqrtMetric
220
Perm(2,3,1) = -1.0d0 / SqrtMetric
221
Perm(3,1,2) = -1.0d0 / SqrtMetric
222
Perm(3,2,1) = 1.0d0 / SqrtMetric
223
!------------------------------------------------------------------------------
224
225
Bc = 0.0d0
226
DO i=1,3
227
DO j=1,3
228
Bc(i) = Bc(i) + Metric(i,j)*B(j)
229
END DO
230
END DO
231
232
!------------------------------------------------------------------------------
233
234
Ji = 0.0d0
235
DO i=1,3
236
s = 0.0D0
237
DO j=1,3
238
DO k=1,3
239
IF ( Perm(i,j,k) /= 0 ) THEN
240
DO l=1,3
241
s = s + Perm(i,j,k)*Metric(j,l)*dHdx(l,k)
242
DO m=1,3
243
s = s + Perm(i,j,k)*Metric(j,l)*Symb(k,m,l)*B(m)/mu
244
END DO
245
END DO
246
END IF
247
END DO
248
END DO
249
Ji(i) = s
250
END DO
251
252
Jc = 0.0d0
253
DO i=1,3
254
DO j=1,3
255
Jc(i) = Jc(i) + Metric(i,j)*Ji(j)
256
END DO
257
END DO
258
!------------------------------------------------------------------------------
259
260
LF = 0.0d0
261
DO i=1,3
262
s = 0.0D0
263
DO j=1,3
264
DO k=1,3
265
IF ( Perm(i,j,k) /= 0 ) THEN
266
s = s + Perm(i,j,k)*Jc(k)*Bc(j)
267
END IF
268
END DO
269
END DO
270
LF(i) = s
271
END DO
272
!------------------------------------------------------------------------------
273
END FUNCTION ComputeLorentz
274
!------------------------------------------------------------------------------
275
END FUNCTION LorentzForce
276
!------------------------------------------------------------------------------
277
278
279
!------------------------------------------------------------------------------
280
!> Compute the Joule heating at integration point (u,v,w) given the
281
!> appropriate electrostatic or magnetic field that initiates the
282
!> current through a conductor.
283
!------------------------------------------------------------------------------
284
FUNCTION JouleHeat( Element,Nodes,u,v,w,n ) RESULT(JouleH)
285
!------------------------------------------------------------------------------
286
TYPE(Element_t) :: Element
287
TYPE(Nodes_t) :: Nodes
288
INTEGER :: n
289
REAL(KIND=dp) :: JouleH,u,v,w,x,y,z
290
!------------------------------------------------------------------------------
291
TYPE(Variable_t), POINTER :: Mx,My,Mz,MFx,MFy,MFz
292
INTEGER :: i,j,k,bfId
293
LOGICAL :: stat,GotIt
294
INTEGER, POINTER :: NodeIndexes(:)
295
296
TYPE(ValueList_t), POINTER :: Material
297
298
REAL(KIND=dp) :: B(3),dHdx(3,3)
299
REAL(KIND=dp) :: dBasisdx(n,3),SqrtElementMetric
300
REAL(KIND=dp) :: Basis(n),Permeability(n), &
301
ElectricConductivity(n)
302
303
REAL(KIND=dp) :: ExtMx(n),ExtMy(n),ExtMz(n)
304
REAL(KIND=dp) :: mu,elcond,SqrtMetric,Metric(3,3),Symb(3,3,3),dSymb(3,3,3,3)
305
306
INTEGER, SAVE :: JouleMode = 0
307
TYPE(Variable_t), POINTER, SAVE :: Jvar
308
!------------------------------------------------------------------------------
309
JouleH = 0.0_dp
310
311
bfId = ListGetInteger( CurrentModel % Bodies( Element % BodyId ) % &
312
Values, 'Body Force', GotIt, 1, CurrentModel % NumberOfBodyForces )
313
314
IF ( .NOT.GotIt ) RETURN
315
316
IF ( .NOT.ListGetLogical( CurrentModel % BodyForces( &
317
bfId ) % Values, 'Joule Heat' , GotIt ) ) RETURN
318
!------------------------------------------------------------------------------
319
320
IF( JouleMode == 0 ) THEN
321
Jvar => VariableGet( CurrentModel % Variables, 'Joule Heating e' )
322
IF ( ASSOCIATED( Jvar ) ) JouleMode = 1
323
324
IF( JouleMode == 0 ) THEN
325
Jvar => VariableGet( CurrentModel % Variables, 'Joule Field' )
326
IF ( ASSOCIATED( Jvar ) ) JouleMode = 2
327
END IF
328
329
IF( JouleMode == 0 ) THEN
330
Jvar => VariableGet( CurrentModel % Variables, 'Potential' )
331
IF ( ASSOCIATED( Jvar ) ) JouleMode = 3
332
END IF
333
334
IF( JouleMode == 0 ) THEN
335
Jvar => VariableGet( CurrentModel % Variables, 'Magnetic Field 1' )
336
IF ( ASSOCIATED( Jvar ) ) JouleMode = 4
337
END IF
338
339
IF( JouleMode == 0 ) THEN
340
CALL Warn('JouleHeat','Joule heating requested but no field to compute it!')
341
RETURN
342
END IF
343
END IF
344
345
IF( JouleMode == 1 ) THEN
346
NodeIndexes => Element % DgIndexes
347
ELSE
348
NodeIndexes => Element % NodeIndexes
349
END IF
350
IF( ANY( Jvar % Perm( NodeIndexes ) == 0 ) ) RETURN
351
352
353
!------------------------------------------------------------------------------
354
! The simplest model just evaluates precomputed elemental heating at integration point
355
!------------------------------------------------------------------------------
356
IF( JouleMode == 1 ) THEN
357
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric,Basis )
358
JouleH = SUM( Basis(1:n) * Jvar % Values( Jvar % Perm( NodeIndexes ) ) )
359
360
! Make an early exit since we don't need conductivity
361
RETURN
362
END IF
363
364
365
!------------------------------------------------------------------------------
366
! All other models require electric conductivity
367
!------------------------------------------------------------------------------
368
k = ListGetInteger( CurrentModel % Bodies &
369
(Element % BodyId) % Values, 'Material')
370
Material => CurrentModel % Materials(k) % Values
371
372
ElectricConductivity(1:n) = ListGetReal( Material, &
373
'Electric Conductivity',n,NodeIndexes,GotIt )
374
375
IF( JouleMode == 2 ) THEN
376
! This model uses a "joule field" and multiplies it with conductivity at the integration point
377
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric,Basis )
378
elcond = SUM( ElectricConductivity(1:n) * Basis(1:n) )
379
JouleH = elcond * SUM( Basis(1:n) * Jvar % Values(Jvar % Perm(NodeIndexes)) )
380
381
ELSE IF( JouleMode == 3 ) THEN
382
! This model uses potential and evaluates the current from its gradient
383
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric,Basis,dBasisdx )
384
elcond = SUM( ElectricConductivity(1:n) * Basis(1:n) )
385
386
B(1) = SUM( dBasisdx(1:n,1) * Jvar % Values(Jvar % Perm(NodeIndexes)) )
387
B(2) = SUM( dBasisdx(1:n,2) * Jvar % Values(Jvar % Perm(NodeIndexes)) )
388
B(3) = SUM( dBasisdx(1:n,3) * Jvar % Values(Jvar % Perm(NodeIndexes)) )
389
JouleH = elcond * SUM( B * B )
390
391
ELSE IF( JouleMode == 4 ) THEN
392
!------------------------------------------------------------------------------
393
! Magnetic induction equation, might be obsolete
394
!------------------------------------------------------------------------------
395
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric,Basis,dBasisdx )
396
elcond = SUM( ElectricConductivity(1:n) * Basis(1:n) )
397
IF( elcond < TINY( elcond ) ) RETURN
398
399
Permeability(1:n) = ListGetReal( Material, 'Magnetic Permeability', &
400
n, NodeIndexes )
401
402
Mx => VariableGet( CurrentModel % Variables, 'Magnetic Field 1' )
403
My => VariableGet( CurrentModel % Variables, 'Magnetic Field 2' )
404
Mz => VariableGet( CurrentModel % Variables, 'Magnetic Field 3' )
405
406
!------------------------------------------------------------------------------
407
ExtMx(1:n) = ListGetReal( Material, 'Applied Magnetic Field 1', &
408
n,NodeIndexes, Gotit )
409
ExtMy(1:n) = ListGetReal( Material, 'Applied Magnetic Field 2', &
410
n,NodeIndexes, Gotit )
411
ExtMz(1:n) = ListGetReal( Material, 'Applied Magnetic Field 3', &
412
n,NodeIndexes, Gotit )
413
!
414
MFx => VariableGet( CurrentModel % Variables, 'Magnetic Flux Density 1' )
415
MFy => VariableGet( CurrentModel % Variables, 'Magnetic Flux Density 2' )
416
MFz => VariableGet( CurrentModel % Variables, 'Magnetic Flux Density 3' )
417
IF ( ASSOCIATED( MFx ) ) THEN
418
ExtMx(1:n) = ExtMx(1:n) + MFx % Values(MFx % Perm(NodeIndexes))
419
ExtMy(1:n) = ExtMy(1:n) + MFy % Values(MFy % Perm(NodeIndexes))
420
ExtMz(1:n) = ExtMz(1:n) + MFz % Values(MFz % Perm(NodeIndexes))
421
END IF
422
423
!------------------------------------------------------------------------------
424
B(1) = SUM( Basis(1:n) * Mx % Values(Mx % Perm(NodeIndexes)) )
425
B(2) = SUM( Basis(1:n) * My % Values(My % Perm(NodeIndexes)) )
426
B(3) = SUM( Basis(1:n) * Mz % Values(Mz % Perm(NodeIndexes)) )
427
428
B(1) = B(1) + SUM( Basis(1:n) * ExtMx(1:n) )
429
B(2) = B(2) + SUM( Basis(1:n) * ExtMy(1:n) )
430
B(3) = B(3) + SUM( Basis(1:n) * ExtMz(1:n) )
431
432
mu = SUM( Basis(1:n) * Permeability(1:n) )
433
DO i=1,3
434
dHdx(1,i) = SUM( dBasisdx(1:n,i)* &
435
Mx % Values(Mx % Perm(NodeIndexes))/Permeability(1:n) )
436
dHdx(2,i) = SUM( dBasisdx(1:n,i)* &
437
My % Values(My % Perm(NodeIndexes))/Permeability(1:n) )
438
dHdx(3,i) = SUM( dBasisdx(1:n,i)* &
439
Mz % Values(Mz % Perm(NodeIndexes))/Permeability(1:n) )
440
END DO
441
442
IF ( CurrentCoordinateSystem() /= Cartesian ) THEN
443
x = SUM( Nodes % x(1:n) * Basis(1:n))
444
y = SUM( Nodes % y(1:n) * Basis(1:n))
445
z = SUM( Nodes % z(1:n) * Basis(1:n))
446
CALL CoordinateSystemInfo( Metric,SqrtMetric,Symb,dSymb,x,y,z )
447
CALL InvertMatrix( Metric,3 )
448
END IF
449
JouleH = ComputeMagneticHeat( B,dHdx,mu,SqrtMetric,Metric,Symb ) / &
450
elcond
451
END IF
452
453
CONTAINS
454
455
!------------------------------------------------------------------------------
456
FUNCTION ComputeMagneticHeat( B,dHdx,mu,SqrtMetric,Metric,Symb ) RESULT(JH)
457
!------------------------------------------------------------------------------
458
REAL(KIND=dp) :: B(:),dHdx(:,:),mu,JH,SqrtMetric,Metric(:,:),Symb(:,:,:)
459
!------------------------------------------------------------------------------
460
INTEGER :: i,j,k,l,m
461
REAL(KIND=dp) :: Bc(3),Ji(3),Jc(3),s,Perm(3,3,3),r
462
!------------------------------------------------------------------------------
463
464
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
465
Ji(1) = dHdx(3,2) - dHdx(2,3)
466
Ji(2) = dHdx(1,3) - dHdx(3,1)
467
Ji(3) = dHdx(2,1) - dHdx(1,2)
468
JH = Ji(1)*Ji(1) + Ji(2)*Ji(2) + Ji(3)*Ji(3)
469
RETURN
470
END IF
471
472
IF ( CurrentCoordinateSystem() == CylindricSymmetric ) THEN
473
r = SqrtMetric
474
Ji(1) = -dHdx(3,2)
475
Ji(2) = B(3)/(r*mu) + dHdx(3,1)
476
Ji(3) = dHdx(1,2) - dHdx(2,1)
477
JH = Ji(1)*Ji(1) + Ji(2)*Ji(2) + Ji(3)*Ji(3)
478
RETURN
479
END IF
480
481
Perm = 0
482
Perm(1,2,3) = -1.0d0 / SqrtMetric
483
Perm(1,3,2) = 1.0d0 / SqrtMetric
484
Perm(2,1,3) = 1.0d0 / SqrtMetric
485
Perm(2,3,1) = -1.0d0 / SqrtMetric
486
Perm(3,1,2) = -1.0d0 / SqrtMetric
487
Perm(3,2,1) = 1.0d0 / SqrtMetric
488
!------------------------------------------------------------------------------
489
490
Bc = 0.0d0
491
DO i=1,3
492
DO j=1,3
493
Bc(i) = Bc(i) + Metric(i,j)*B(j)
494
END DO
495
END DO
496
497
!------------------------------------------------------------------------------
498
499
Ji = 0.0d0
500
DO i=1,3
501
s = 0.0D0
502
DO j=1,3
503
DO k=1,3
504
IF ( Perm(i,j,k) /= 0 ) THEN
505
DO l=1,3
506
s = s + Perm(i,j,k)*Metric(j,l)*dHdx(l,k)
507
DO m=1,3
508
s = s + Perm(i,j,k)*Metric(j,l)*Symb(k,m,l)*B(m)/mu
509
END DO
510
END DO
511
END IF
512
END DO
513
END DO
514
Ji(i) = s
515
END DO
516
517
Jc = 0.0d0
518
DO i=1,3
519
DO j=1,3
520
Jc(i) = Jc(i) + Metric(i,j)*Ji(j)
521
END DO
522
END DO
523
524
!------------------------------------------------------------------------------
525
526
JH = 0.0d0
527
DO i=1,3
528
JH = JH + Ji(i) * Jc(i)
529
END DO
530
!------------------------------------------------------------------------------
531
END FUNCTION ComputeMagneticHeat
532
!------------------------------------------------------------------------------
533
END FUNCTION JouleHeat
534
!------------------------------------------------------------------------------
535
536
537
538
!------------------------------------------------------------------------------
539
!> Compute the curl vector B = curl(A) at all nodes.
540
!> \deprecated Is this used anywhere?
541
!------------------------------------------------------------------------------
542
SUBROUTINE Curl( Ax,Ay,Az,Bx,By,Bz,Reorder )
543
!------------------------------------------------------------------------------
544
REAL(KIND=dp) :: Ax(:),Ay(:),Az(:),Bx(:),By(:),Bz(:)
545
INTEGER :: Reorder(:)
546
!------------------------------------------------------------------------------
547
TYPE(Element_t), POINTER :: Element
548
TYPE(Nodes_t) :: Nodes
549
550
LOGICAL :: Stat
551
INTEGER :: i,j,k,l,m,n,p,q,t
552
REAL(KIND=dp) :: x,y,z,u,v,w,s,A(3),B(3),dx(3,3)
553
554
INTEGER :: Perm(3,3,3)
555
INTEGER, POINTER :: NodeIndexes(:),Visited(:)
556
557
REAL(KIND=dp), ALLOCATABLE :: dBasisdx(:,:)
558
REAL(KIND=dp), ALLOCATABLE :: Basis(:),aaz(:)
559
560
REAL(KIND=dp) :: SqrtElementMetric
561
REAL(KIND=dp) :: SqrtMetric,Metric(3,3),Symb(3,3,3),dSymb(3,3,3,3)
562
!------------------------------------------------------------------------------
563
564
ALLOCATE( Visited(CurrentModel % NumberOfNodes) )
565
Visited = 0
566
567
Perm = 0
568
Perm(1,2,3) = -1
569
Perm(1,3,2) = 1
570
Perm(2,1,3) = 1
571
Perm(2,3,1) = -1
572
Perm(3,1,2) = -1
573
Perm(3,2,1) = 1
574
575
n = CurrentModel % Mesh % MaxElementNodes
576
ALLOCATE( dBasisdx(n,3), Basis(n), aaz(n) )
577
ALLOCATE( Nodes % x(n), Nodes % y(n), Nodes % z(n) )
578
579
Bx = 0.0D0
580
By = 0.0D0
581
Bz = 0.0D0
582
!------------------------------------------------------------------------------
583
! Go through model elements, we will compute on average of elementwise
584
! curls on nodes of the model
585
!------------------------------------------------------------------------------
586
DO t=1,CurrentModel % NumberOfBulkElements
587
!------------------------------------------------------------------------------
588
Element => CurrentModel % Elements(t)
589
n = Element % TYPE % NumberOfNodes
590
NodeIndexes => Element % NodeIndexes
591
592
Nodes % x(1:n) = CurrentModel % Nodes % x( NodeIndexes )
593
Nodes % y(1:n) = CurrentModel % Nodes % y( NodeIndexes )
594
Nodes % z(1:n) = CurrentModel % Nodes % z( NodeIndexes )
595
!------------------------------------------------------------------------------
596
! Through element nodes
597
!------------------------------------------------------------------------------
598
599
IF (MINVAL(Reorder(NodeIndexes)) > 0) THEN
600
601
DO p=1,n
602
q = Reorder(NodeIndexes(p))
603
u = Element % TYPE % NodeU(p)
604
v = Element % TYPE % NodeV(p)
605
606
IF ( Element % TYPE % DIMENSION == 3 ) THEN
607
w = Element % TYPE % NodeW(p)
608
ELSE
609
w = 0.0D0
610
END IF
611
!------------------------------------------------------------------------------
612
! Get element basis functions, basis function derivatives, etc,
613
! and compute partials derivatives of the vector A with respect
614
! to global coordinates.
615
!------------------------------------------------------------------------------
616
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric, &
617
Basis,dBasisdx )
618
!------------------------------------------------------------------------------
619
! Get coordinate system info
620
!------------------------------------------------------------------------------
621
IF ( CurrentCoordinateSystem() /= Cartesian ) THEN
622
x = SUM( Nodes % x(1:n) * Basis(1:n))
623
y = SUM( Nodes % y(1:n) * Basis(1:n))
624
z = SUM( Nodes % z(1:n) * Basis(1:n))
625
CALL CoordinateSystemInfo( Metric,SqrtMetric,Symb,dSymb,x,y,z )
626
CALL InvertMatrix( Metric,3 )
627
END IF
628
629
! print *, '***',p
630
! print *, '***',x,y,z
631
! print *, '***',NodeIndexes
632
! print *, '***',Reorder(NodeIndexes)
633
634
DO k=1,3
635
dx(1,k) = SUM( dBasisdx(1:n,k) * Ax(Reorder(NodeIndexes)) )
636
dx(2,k) = SUM( dBasisdx(1:n,k) * Ay(Reorder(NodeIndexes)) )
637
dx(3,k) = SUM( dBasisdx(1:n,k) * Az(Reorder(NodeIndexes)) )
638
END DO
639
!------------------------------------------------------------------------------
640
! And compute the curl for the node of the current element
641
!------------------------------------------------------------------------------
642
IF ( CurrentCoordinateSystem() /= Cartesian ) THEN
643
A(1) = Ax(q)
644
A(2) = Ay(q)
645
A(3) = Az(q)
646
B = 0.0D0
647
IF ( ABS(SqrtMetric) > 1.0d-15 ) THEN
648
DO i=1,3
649
s = 0.0D0
650
DO j=1,3
651
DO k=1,3
652
IF ( Perm(i,j,k) /= 0 ) THEN
653
DO l=1,3
654
s = s + Perm(i,j,k)*Metric(j,l)*dx(l,k)
655
DO m=1,3
656
s = s + Perm(i,j,k)*Metric(j,l)*Symb(k,m,l)*A(m)
657
END DO
658
END DO
659
END IF
660
END DO
661
END DO
662
B(i) = s
663
END DO
664
665
Bx(q) = Bx(q) + B(1) / SqrtMetric
666
By(q) = By(q) + B(2) / SqrtMetric
667
Bz(q) = Bz(q) + B(3) / SqrtMetric
668
END IF
669
ELSE
670
671
Bx(q) = Bx(q) + dx(3,2) - dx(2,3)
672
By(q) = By(q) + dx(1,3) - dx(3,1)
673
Bz(q) = Bz(q) + dx(2,1) - dx(1,2)
674
675
END IF
676
Visited(q) = Visited(q) + 1
677
END DO
678
679
END IF
680
681
!------------------------------------------------------------------------------
682
END DO
683
!------------------------------------------------------------------------------
684
! Finally, compute the average of the curls at nodes
685
!------------------------------------------------------------------------------
686
DO i=1,CurrentModel % NumberOfNodes
687
IF ( Visited(i) > 0 ) THEN
688
Bx(i) = Bx(i) / Visited(i)
689
By(i) = By(i) / Visited(i)
690
Bz(i) = Bz(i) / Visited(i)
691
END IF
692
END DO
693
694
DEALLOCATE( Visited, Nodes % x, Nodes % y, Nodes % z, Basis, dBasisdx, aaz )
695
!------------------------------------------------------------------------------
696
END SUBROUTINE Curl
697
!------------------------------------------------------------------------------
698
699
700
!------------------------------------------------------------------------------
701
!> Compute the curl in axisymmetric coordinates.
702
!> \deprecated Is this used anywhere?
703
!------------------------------------------------------------------------------
704
SUBROUTINE AxiSCurl( Ar,Az,Ap,Br,Bz,Bp,Reorder )
705
!------------------------------------------------------------------------------
706
IMPLICIT NONE
707
REAL(KIND=dp) :: Ar(:),Az(:),Ap(:),Br(:),Bz(:),Bp(:)
708
INTEGER :: Reorder(:)
709
710
TYPE(Element_t), POINTER :: Element
711
TYPE(Nodes_t) :: Nodes
712
713
LOGICAL :: Stat
714
715
INTEGER, POINTER :: NodeIndexes(:),Visited(:)
716
INTEGER :: p,q,i,t,n
717
718
REAL(KIND=dp) :: u,v,w,r
719
720
REAL(KIND=dp) :: SqrtElementMetric
721
REAL(KIND=dp), ALLOCATABLE :: Basis(:), dBasisdx(:,:)
722
!------------------------------------------
723
ALLOCATE( Visited(CurrentModel % NumberOfNodes) )
724
725
n = CurrentModel % Mesh % MaxElementDOFs
726
ALLOCATE( Basis(n), dBasisdx(n,3) )
727
ALLOCATE(Nodes % x(n),Nodes % y(n),Nodes % z(n))
728
729
Visited = 0
730
731
Br = 0.0d0
732
Bz = 0.0d0
733
Bp = 0.0d0
734
735
DO t=1,CurrentModel % NumberOfBulkElements
736
737
Element => CurrentModel % Elements(t)
738
n = Element % TYPE % NumberOfNodes
739
NodeIndexes => Element % NodeIndexes
740
741
Nodes % x(1:n) = CurrentModel % Nodes % x( NodeIndexes )
742
Nodes % y(1:n) = CurrentModel % Nodes % y( NodeIndexes )
743
Nodes % z(1:n) = CurrentModel % Nodes % z( NodeIndexes )
744
745
IF ( MINVAL(Reorder(NodeIndexes)) > 0 ) THEN
746
DO p=1,n
747
q = Reorder(NodeIndexes(p))
748
u = Element % TYPE % NodeU(p)
749
v = Element % TYPE % NodeV(p)
750
751
IF ( Element % TYPE % DIMENSION == 3 ) THEN
752
w = Element % TYPE % NodeW(p)
753
ELSE
754
w = 0.0D0
755
END IF
756
757
stat = ElementInfo( Element, Nodes, u, v, w, SqrtElementMetric, &
758
Basis, dBasisdx )
759
760
r = SUM( Basis(1:n) * Nodes % x(1:n) )
761
762
Br(q) = Br(q) - SUM( dBasisdx(1:n,2)*Ap(Reorder(NodeIndexes)) )
763
764
Bp(q) = Bp(q) + SUM( dBasisdx(1:n,2) * Ar(Reorder(NodeIndexes)) ) &
765
- SUM( dBasisdx(1:n,1) * Az(Reorder(NodeIndexes)) )
766
767
Bz(q) = Bz(q) + SUM( dBasisdx(1:n,1) * Ap(Reorder(NodeIndexes)) )
768
769
IF (r > 1.0d-10) THEN
770
Bz(q) = Bz(q) + SUM( Basis(1:n)*Ap(Reorder(NodeIndexes)) ) / r
771
ELSE
772
Bz(q) = Bz(q) + SUM( dBasisdx(1:n,1)*Ap(Reorder(NodeIndexes)) )
773
END IF
774
775
Visited(q) = Visited(q) + 1
776
END DO
777
END IF
778
END DO
779
780
DO i=1,CurrentModel % NumberOfNodes
781
IF ( Visited(i) > 0 ) THEN
782
Br(i) = Br(i) / Visited(i)
783
Bp(i) = Bp(i) / Visited(i)
784
Bz(i) = Bz(i) / Visited(i)
785
END IF
786
END DO
787
788
DEALLOCATE( Visited, Basis, dBasisdx )
789
DEALLOCATE( Nodes % x, Nodes % y, Nodes % z )
790
791
!------------------------------------------------------------------------------
792
END SUBROUTINE AxiSCurl
793
!------------------------------------------------------------------------------
794
795
796
!------------------------------------------------------------------------------
797
!> Compute cross product of given vectors: C = A x B in generalized coordinates.
798
!> \deprecated Is this used anywhere?
799
!------------------------------------------------------------------------------
800
SUBROUTINE Cross( Ax,Ay,Az,Bx,By,Bz,Cx,Cy,Cz,n )
801
!------------------------------------------------------------------------------
802
REAL(KIND=dp) :: Ax,Ay,Az,Bx,By,Bz,Cx,Cy,Cz
803
!------------------------------------------------------------------------------
804
INTEGER :: i,j,k,n
805
REAL(KIND=dp) :: SqrtMetric,Metric(3,3),Symb(3,3,3),dSymb(3,3,3,3),x,y,z
806
!------------------------------------------------------------------------------
807
808
!------------------------------------------------------------------------------
809
! Compute the cross product
810
!------------------------------------------------------------------------------
811
Cx = Ay * Bz - Az * By
812
Cy = Az * Bx - Ax * Bz
813
Cz = Ax * By - Ay * Bx
814
!------------------------------------------------------------------------------
815
! Make contravariant
816
!------------------------------------------------------------------------------
817
IF ( CurrentCoordinateSystem() /= Cartesian ) THEN
818
x = CurrentModel % Nodes % x(n)
819
y = CurrentModel % Nodes % y(n)
820
z = CurrentModel % Nodes % z(n)
821
CALL CoordinateSystemInfo( Metric,SqrtMetric,Symb,dSymb,x,y,z )
822
823
x = SqrtMetric * Cx
824
y = SqrtMetric * Cy
825
z = SqrtMetric * Cz
826
827
Cx = Metric(1,1)*x + Metric(1,2)*y + Metric(1,3)*z
828
Cy = Metric(2,1)*x + Metric(2,2)*y + Metric(2,3)*z
829
Cz = Metric(3,1)*x + Metric(3,2)*y + Metric(3,3)*z
830
END IF
831
!------------------------------------------------------------------------------
832
END SUBROUTINE Cross
833
!------------------------------------------------------------------------------
834
835
836
!------------------------------------------------------------------------------
837
!> Compute dot product of given vectors: L=A \cdot B in orthogonal
838
!> coordinate system.
839
!> \deprecated Is this used anywhere?
840
!------------------------------------------------------------------------------
841
FUNCTION Dot( Ax,Ay,Az,Bx,By,Bz,n ) RESULT(L)
842
!------------------------------------------------------------------------------
843
REAL(KIND=dp) :: Ax,Ay,Az,Bx,By,Bz
844
REAL(KIND=dp) :: L
845
!------------------------------------------------------------------------------
846
INTEGER :: i,j,k,n
847
REAL(KIND=dp) :: SqrtMetric,Metric(3,3),Symb(3,3,3),dSymb(3,3,3,3),x,y,z
848
!------------------------------------------------------------------------------
849
850
!------------------------------------------------------------------------------
851
! Compute the dot product
852
!------------------------------------------------------------------------------
853
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
854
L = Ax*Bx + Ay*By + Az*Bz
855
ELSE
856
x = CurrentModel % Nodes % x(n)
857
y = CurrentModel % Nodes % y(n)
858
z = CurrentModel % Nodes % z(n)
859
CALL CoordinateSystemInfo( Metric,SqrtMetric,Symb,dSymb,x,y,z )
860
!
861
! NOTE: this is for orthogonal coordinates only
862
!
863
L = Ax*Bx / Metric(1,1) + Ay*By / Metric(2,2) + Az*Bz / Metric(3,3)
864
END IF
865
!------------------------------------------------------------------------------
866
END FUNCTION Dot
867
!------------------------------------------------------------------------------
868
869
END MODULE Differentials
870
871
!> \} ElmerLib
872
873
874