Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/CircuitUtils.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 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
! * Authors: Eelis Takala(Trafotek Oy) and Juha Ruokolainen(CSC)
27
! * Emails: [email protected] and [email protected]
28
! * Web: http://www.trafotek.fi and http://www.csc.fi/elmer
29
! * Addresses: Trafotek Oy
30
! * Kaarinantie 700
31
! * Turku
32
! *
33
! * and
34
! *
35
! * CSC - IT Center for Science Ltd.
36
! * Keilaranta 14
37
! * 02101 Espoo, Finland
38
! *
39
! * Original Date: October 2015
40
! *
41
! *****************************************************************************/
42
43
MODULE CircuitUtils
44
45
USE DefUtils
46
IMPLICIT NONE
47
48
CONTAINS
49
50
!------------------------------------------------------------------------------
51
FUNCTION GetCircuitModelDepth() RESULT (Depth)
52
!------------------------------------------------------------------------------
53
IMPLICIT NONE
54
55
TYPE(Valuelist_t), POINTER :: simulation
56
REAL(KIND=dp) :: depth
57
LOGICAL :: Found, CSymmetry, Parallel
58
INTEGER :: NoSlices
59
60
CSymmetry = ( CurrentCoordinateSystem() == AxisSymmetric .OR. &
61
CurrentCoordinateSystem() == CylindricSymmetric )
62
63
simulation => GetSimulation()
64
depth = GetConstReal(simulation, 'Circuit Model Depth', Found)
65
66
IF( Found ) THEN
67
NoSlices = ListGetInteger(simulation,'Number of Slices',Found)
68
IF(NoSlices > 1) THEN
69
IF( CurrentModel % Solver % Parallel ) depth = depth / NoSlices
70
END IF
71
ELSE
72
depth = 1._dp
73
IF (CSymmetry) depth = 2._dp * pi
74
END IF
75
76
!------------------------------------------------------------------------------
77
END FUNCTION GetCircuitModelDepth
78
!------------------------------------------------------------------------------
79
80
!------------------------------------------------------------------------------
81
FUNCTION GetComponentVoltageFactor(CompInd) RESULT (VoltageFactor)
82
!------------------------------------------------------------------------------
83
IMPLICIT NONE
84
85
INTEGER :: CompInd
86
REAL(KIND=dp) :: VoltageFactor
87
TYPE(Valuelist_t), POINTER :: CompParams
88
LOGICAL :: Found
89
90
CompParams => CurrentModel % Components(CompInd) % Values
91
IF (.NOT. ASSOCIATED(CompParams)) CALL Fatal ('GetComponentVoltageFactor',&
92
'Component parameters not found')
93
VoltageFactor = GetConstReal(CompParams, 'Circuit Equation Voltage Factor', Found)
94
IF (.NOT. Found) VoltageFactor = 1._dp
95
!------------------------------------------------------------------------------
96
END FUNCTION GetComponentVoltageFactor
97
!------------------------------------------------------------------------------
98
99
!------------------------------------------------------------------------------
100
FUNCTION GetComponentParams(Element) RESULT (ComponentParams)
101
!------------------------------------------------------------------------------
102
IMPLICIT NONE
103
104
INTEGER :: i
105
TYPE(Element_t), POINTER :: Element
106
TYPE(Valuelist_t), POINTER :: ComponentParams, EntityParams
107
LOGICAL :: Found
108
109
EntityParams => GetBC(Element)
110
IF (.NOT. ASSOCIATED(EntityParams)) THEN
111
112
EntityParams => GetBodyParams( Element )
113
IF (.NOT. ASSOCIATED(EntityParams)) CALL Fatal ('GetCompParams', 'Body Parameters not found')
114
115
END IF
116
117
i = GetInteger(EntityParams, 'Component', Found)
118
119
IF (.NOT. Found) THEN
120
ComponentParams => Null()
121
ELSE
122
ComponentParams => CurrentModel % Components(i) % Values
123
END IF
124
125
!------------------------------------------------------------------------------
126
END FUNCTION GetComponentParams
127
!------------------------------------------------------------------------------
128
129
130
! Get the current associated to the component from the solution of the
131
! constraint problem having lagrange multiplier vector.
132
!------------------------------------------------------------------------------
133
FUNCTION GetComponentCurrent(CompId,Found) RESULT ( Curr )
134
INTEGER :: CompId
135
LOGICAL :: Found
136
COMPLEX(KIND=dp) :: Curr
137
138
INTEGER :: i,j
139
TYPE(CircuitVariable_t), POINTER :: iVar
140
TYPE(Variable_t), POINTER :: LagrangeVar
141
REAL(KIND=dp) :: CurrIm, CurrRe
142
TYPE(Circuit_t), POINTER :: Circuit
143
CHARACTER(LEN=MAX_NAME_LEN) :: str
144
145
Found = .FALSE.
146
Curr = 0.0_dp
147
148
IF(CurrentModel % n_Circuits == 0) RETURN
149
150
CurrRe = 0.0_dp
151
CurrIm = 0.0_dp
152
153
DO i = 1, CurrentModel % n_Circuits
154
Circuit => CurrentModel % Circuits(i)
155
156
str = LagrangeMultiplierName( CurrentModel % ASolver )
157
LagrangeVar => VariableGet( CurrentModel % Mesh % Variables, str, ThisOnly = .TRUE.)
158
IF(.NOT. ASSOCIATED(LagrangeVar) ) RETURN
159
160
DO j = 1, SIZE(Circuit % Components)
161
ivar => Circuit % Components(j) % ivar
162
IF(.NOT. ASSOCIATED(ivar)) CYCLE
163
IF(.NOT. iVar % isIvar ) CYCLE
164
IF(iVar % BodyId /= CompId ) CYCLE
165
IF(iVar % ValueId > 0 ) THEN
166
Found = .TRUE.
167
CurrRe = LagrangeVar % Values(iVar % ValueId)
168
END IF
169
IF(iVar % ImValueId > 0 ) THEN
170
CurrIm = LagrangeVar % Values(iVar % ImValueId)
171
END IF
172
IF(Found) EXIT
173
END DO
174
IF(Found) EXIT
175
END DO
176
177
IF(.NOT. Found) THEN
178
CALL Fatal('GetComponentCurrent','Got circuits but no current for component: '//I2S(CompId))
179
END IF
180
181
!PRINT *,'Curr:',CompId,CurrRe,CurrIm
182
Curr = CMPLX(CurrRe,CurrIm)
183
184
END FUNCTION GetComponentCurrent
185
186
187
! Get the current associated to the component from the solution of the
188
! constraint problem having lagrange multiplier vector.
189
!------------------------------------------------------------------------------
190
FUNCTION GetComponentArea(CompId,Found) RESULT ( Area )
191
INTEGER :: CompId
192
LOGICAL :: Found
193
REAL(KIND=dp) :: Area
194
195
INTEGER :: i,j
196
TYPE(CircuitVariable_t), POINTER :: iVar
197
TYPE(Variable_t), POINTER :: LagrangeVar
198
REAL(KIND=dp) :: CurrIm, CurrRe
199
TYPE(Circuit_t), POINTER :: Circuit
200
CHARACTER(LEN=MAX_NAME_LEN) :: str
201
202
Found = .FALSE.
203
Area = 0.0_dp
204
205
IF(CurrentModel % n_Circuits == 0) RETURN
206
207
DO i = 1, CurrentModel % n_Circuits
208
Circuit => CurrentModel % Circuits(i)
209
DO j = 1, SIZE(Circuit % Components)
210
ivar => Circuit % Components(j) % ivar
211
IF(iVar % BodyId /= CompId ) CYCLE
212
213
Area = Circuit % Components(j) % ElArea
214
Found = .TRUE.
215
EXIT
216
END DO
217
IF(Found) EXIT
218
END DO
219
220
IF(.NOT. Found) THEN
221
CALL Fatal('GetComponentArea','Got circuits but no area for component: '//I2S(CompId))
222
END IF
223
224
END FUNCTION GetComponentArea
225
226
227
!------------------------------------------------------------------------------
228
FUNCTION GetComponentId(Element) RESULT (ComponentId)
229
!------------------------------------------------------------------------------
230
IMPLICIT NONE
231
232
INTEGER :: ComponentId
233
TYPE(Element_t), POINTER :: Element
234
TYPE(Valuelist_t), POINTER :: BodyParams
235
LOGICAL :: Found
236
237
BodyParams => GetBodyParams( Element )
238
IF (.NOT. ASSOCIATED(BodyParams)) CALL Fatal ('GetCompParams', 'Body Parameters not found')
239
240
ComponentId = GetInteger(BodyParams, 'Component', Found)
241
242
!------------------------------------------------------------------------------
243
END FUNCTION GetComponentId
244
!------------------------------------------------------------------------------
245
246
!------------------------------------------------------------------------------
247
SUBROUTINE GetWPotential(Wbase)
248
!------------------------------------------------------------------------------
249
IMPLICIT NONE
250
REAL(KIND=dp) :: Wbase(:)
251
252
CALL GetLocalSolution(Wbase,'W Potential')
253
IF(.NOT. ANY(Wbase/=0._dp)) CALL GetLocalSolution(Wbase,'W')
254
!------------------------------------------------------------------------------
255
END SUBROUTINE GetWPotential
256
!------------------------------------------------------------------------------
257
258
259
!------------------------------------------------------------------------------
260
SUBROUTINE GetWPotentialVar(pVar)
261
!------------------------------------------------------------------------------
262
IMPLICIT NONE
263
264
TYPE(Variable_t), POINTER :: pVar
265
266
pVar => VariableGet( CurrentModel % Mesh % Variables,'W Potential')
267
IF(.NOT. ASSOCIATED(pVar) ) THEN
268
pVar => VariableGet( CurrentModel % Mesh % Variables,'W')
269
END IF
270
IF(ASSOCIATED(pVar)) THEN
271
CALL Info('GetWPotentialVar','Using gradient of field to define direction: '&
272
//TRIM(pVar % Name),Level=7)
273
ELSE
274
CALL Warn('GetWPotentialVar','Could not obtain variable for potential "W"')
275
END IF
276
!------------------------------------------------------------------------------
277
END SUBROUTINE GetWPotentialVar
278
!------------------------------------------------------------------------------
279
280
281
!------------------------------------------------------------------------------
282
SUBROUTINE AddComponentsToBodyLists()
283
!------------------------------------------------------------------------------
284
IMPLICIT NONE
285
286
LOGICAL :: Found
287
INTEGER :: i, j, k
288
LOGICAL, SAVE :: Visited=.FALSE.
289
! Components and Bodies:
290
! ----------------------
291
INTEGER :: BodyId, BoundaryId
292
INTEGER, POINTER :: BodyAssociations(:) => Null()
293
INTEGER, POINTER :: BCAssociations(:) => Null()
294
TYPE(Valuelist_t), POINTER :: BodyParams, BCParams, ComponentParams
295
296
IF (Visited) RETURN
297
298
Visited = .TRUE.
299
DO i = 1, SIZE(CurrentModel % Components)
300
ComponentParams => CurrentModel % Components(i) % Values
301
302
IF( ListGetLogical( ComponentParams,'Passive Component', Found ) ) CYCLE
303
304
IF (.NOT. ASSOCIATED(ComponentParams)) CALL Fatal ('AddComponentsToBodyList', &
305
'Component parameters not found!')
306
BodyAssociations => ListGetIntegerArray(ComponentParams, 'Body', Found)
307
308
IF (.NOT. Found) BodyAssociations => ListGetIntegerArray(ComponentParams, 'Master Bodies', Found)
309
310
IF (.NOT. Found) BCAssociations => ListGetIntegerArray(ComponentParams, 'Master BCs', Found)
311
312
IF (.NOT. Found) CYCLE
313
314
IF (ASSOCIATED(BodyAssociations)) THEN
315
DO j = 1, SIZE(BodyAssociations)
316
BodyId = BodyAssociations(j)
317
BodyParams => CurrentModel % Bodies(BodyId) % Values
318
IF (.NOT. ASSOCIATED(BodyParams)) CALL Fatal ('AddComponentsToBodyList', &
319
'Body parameters not found!')
320
k = GetInteger(BodyParams, 'Component', Found)
321
IF (Found) CALL Fatal ('AddComponentsToBodyList', &
322
'Body '//TRIM(i2s(BodyId))//' associated to two components!')
323
CALL listAddInteger(BodyParams, 'Component', i)
324
BodyParams => Null()
325
END DO
326
END IF
327
IF (ASSOCIATED(BCAssociations)) THEN
328
DO j = 1, SIZE(BCAssociations)
329
BoundaryId = BCAssociations(j)
330
BCParams => CurrentModel % BCs(BoundaryId) % Values
331
IF (.NOT. ASSOCIATED(BCParams)) CALL Fatal ('AddComponentsToBodyList', &
332
'Boundary Condition parameters not found!')
333
334
k = GetInteger(BCParams, 'Component', Found)
335
336
IF (Found) CALL Fatal ('AddComponentsToBodyList', &
337
'Boundary Condition '//TRIM(i2s(BoundaryId))//' associated to two components!')
338
339
CALL ListAddInteger(BCParams, 'Component', i)
340
BCParams => Null()
341
END DO
342
END IF
343
BodyAssociations => Null()
344
BCAssociations => Null()
345
END DO
346
347
DO i = 1, CurrentModel % NumberOfBodies
348
BodyParams => CurrentModel % Bodies(i) % Values
349
IF (.NOT. ASSOCIATED(BodyParams)) CALL Fatal ('AddComponentsToBodyList', &
350
'Body parameters not found!')
351
j = GetInteger(BodyParams, 'Component', Found)
352
IF (.NOT. Found) CYCLE
353
354
WRITE(Message,'(A)') '"Body '//TRIM(I2S(i))//'" associated to "Component '//TRIM(I2S(j))//'"'
355
CALL Info('AddComponentsToBodyList',Message,Level=5)
356
BodyParams => Null()
357
END DO
358
359
DO i = 1, CurrentModel % NumberOfBCs
360
BCParams => CurrentModel % BCs(i) % Values
361
IF (.NOT. ASSOCIATED(BCParams)) CALL Fatal ('AddComponentsToBodyList', &
362
'Boundary Condition parameters not found!')
363
j = GetInteger(BCParams, 'Component', Found)
364
IF (.NOT. Found) CYCLE
365
366
WRITE(Message,'(A)') '"Boundary Condition '//TRIM(I2S(i))// &
367
'" associated to "Component '//TRIM(I2S(j))//'"'
368
CALL Info('AddComponentsToBodyList',Message,Level=5)
369
BCParams => Null()
370
END DO
371
!------------------------------------------------------------------------------
372
END SUBROUTINE AddComponentsToBodyLists
373
!------------------------------------------------------------------------------
374
375
376
!------------------------------------------------------------------------------
377
SUBROUTINE CheckComponentVariables()
378
!------------------------------------------------------------------------------
379
IMPLICIT NONE
380
381
LOGICAL :: Found
382
INTEGER :: i, j, k
383
LOGICAL, SAVE :: Visited=.FALSE.
384
TYPE(Valuelist_t), POINTER :: ComponentParams
385
CHARACTER(LEN=MAX_NAME_LEN) :: CoilType, VarName
386
387
IF(Visited) RETURN
388
IF(CurrentModel % NumberOfComponents == 0) RETURN
389
390
Visited = .TRUE.
391
392
j = 0
393
DO i = 1, CurrentModel % NumberOfComponents
394
ComponentParams => CurrentModel % Components(i) % Values
395
IF( ListGetLogical( ComponentParams,'Passive Component', Found ) ) CYCLE
396
CoilType = GetString(ComponentParams, 'Coil Type', Found)
397
IF(.NOT. Found) CYCLE
398
399
SELECT CASE (CoilType)
400
CASE ('stranded')
401
VarName = 'Circuit Current Variable Id'
402
CASE ('massive','foil winding')
403
VarName = 'Circuit Voltage Variable Id'
404
CASE DEFAULT
405
CYCLE
406
END SELECT
407
408
IF(.NOT. ListCheckPresent(ComponentParams, VarName) ) THEN
409
CALL Warn('CheckComponentOwners','Coil type given for component '//I2S(i)//' but no: '//TRIM(VarName))
410
j = j + 1
411
END IF
412
END DO
413
414
IF(j > 0) THEN
415
CALL Warn('CheckComponentOwners','Could not find variables for '//I2S(j)//' coils!')
416
CALL Fatal('CheckComponentOwners','Check your circuit settings!')
417
END IF
418
419
END SUBROUTINE CheckComponentVariables
420
421
422
423
!------------------------------------------------------------------------------
424
FUNCTION GetComponentBodyIds(Id) RESULT (BodyIds)
425
!------------------------------------------------------------------------------
426
IMPLICIT NONE
427
428
LOGICAL :: Found
429
INTEGER :: Id
430
INTEGER, POINTER :: BodyIds(:)
431
TYPE(Valuelist_t), POINTER :: ComponentParams
432
433
ComponentParams => CurrentModel % Components(Id) % Values
434
435
IF (.NOT. ASSOCIATED(ComponentParams)) CALL Fatal ('GetComponentBodyIds', &
436
'Component parameters not found!')
437
BodyIds => ListGetIntegerArray(ComponentParams, 'Body', Found)
438
IF (.NOT. Found) BodyIds => ListGetIntegerArray(ComponentParams, 'Master Bodies', Found)
439
IF (.NOT. Found) BodyIds => Null()
440
441
!------------------------------------------------------------------------------
442
END FUNCTION GetComponentBodyIds
443
!------------------------------------------------------------------------------
444
445
!------------------------------------------------------------------------------
446
FUNCTION GetComponentHomogenizationBodyIds(Id) RESULT (BodyIds)
447
!------------------------------------------------------------------------------
448
IMPLICIT NONE
449
450
LOGICAL :: Found
451
INTEGER :: Id
452
INTEGER, POINTER :: BodyIds(:)
453
TYPE(Valuelist_t), POINTER :: ComponentParams
454
455
ComponentParams => CurrentModel % Components(Id) % Values
456
457
IF (.NOT. ASSOCIATED(ComponentParams)) CALL Fatal ('GetComponentHomogenizationBodyIds', &
458
'Component parameters not found!')
459
BodyIds => ListGetIntegerArray(ComponentParams, 'Homogenization Parameters Body', Found)
460
IF (.NOT. Found) BodyIds => GetComponentBodyIds(Id)
461
462
!------------------------------------------------------------------------------
463
END FUNCTION GetComponentHomogenizationBodyIds
464
!------------------------------------------------------------------------------
465
466
!------------------------------------------------------------------------------
467
FUNCTION FindSolverWithKey(key) RESULT (Solver)
468
!------------------------------------------------------------------------------
469
IMPLICIT NONE
470
471
CHARACTER(*) :: key
472
473
LOGICAL :: Found
474
INTEGER :: i
475
TYPE(Solver_t), POINTER :: Solver
476
477
! Look for the solver we attach the circuit equations to:
478
! -------------------------------------------------------
479
Found = .FALSE.
480
DO i=1, CurrentModel % NumberOfSolvers
481
Solver => CurrentModel % Solvers(i)
482
IF(ListCheckPresent(Solver % Values, key)) THEN
483
Found = .TRUE.
484
EXIT
485
END IF
486
END DO
487
488
IF (.NOT. Found) CALL Fatal('FindSolverWithKey', &
489
TRIM(Key)//' keyword not found in any of the solvers!')
490
491
!------------------------------------------------------------------------------
492
END FUNCTION FindSolverWithKey
493
!------------------------------------------------------------------------------
494
495
496
497
498
499
END MODULE CircuitUtils
500
501
502
MODULE CircuitsMod
503
504
USE DefUtils
505
IMPLICIT NONE
506
507
CONTAINS
508
509
!------------------------------------------------------------------------------
510
SUBROUTINE AllocateCircuitsList()
511
!------------------------------------------------------------------------------
512
IMPLICIT NONE
513
INTEGER :: slen,n_Circuits
514
CHARACTER(:), ALLOCATABLE :: cmd
515
CHARACTER(LEN=MAX_NAME_LEN) :: name
516
517
! Read Circuit definitions from MATC:
518
! ----------------------------------
519
n_Circuits = NINT(GetMatcReal("Circuits"))
520
CurrentModel % n_Circuits = n_Circuits
521
522
IF( ASSOCIATED( CurrentModel % Circuits ) ) THEN
523
IF( SIZE( CurrentModel % Circuits ) == n_Circuits ) THEN
524
CALL Info('AllocateCircuitList','Circuit list already allocated!')
525
ELSE
526
CALL Warn('AllocateCircuitList','Circuit of wrong size already allocated, deallocating this!')
527
END IF
528
END IF
529
530
IF(.NOT. ASSOCIATED(CurrentModel % Circuits ) ) THEN
531
ALLOCATE( CurrentModel % Circuits(n_Circuits) )
532
END IF
533
534
!------------------------------------------------------------------------------
535
END SUBROUTINE AllocateCircuitsList
536
!------------------------------------------------------------------------------
537
538
!------------------------------------------------------------------------------
539
FUNCTION CountNofCircVarsOfType(CId, Var_type) RESULT (nofc)
540
!------------------------------------------------------------------------------
541
IMPLICIT NONE
542
INTEGER :: nofc, char_len, slen, CId, i
543
CHARACTER(LEN=*) :: Var_type
544
CHARACTER(:), ALLOCATABLE :: cmd
545
CHARACTER(LEN=MAX_NAME_LEN) :: name
546
TYPE(Circuit_t), POINTER :: Circuit
547
548
Circuit => CurrentModel % Circuits(CId)
549
550
nofc = 0
551
552
char_len = LEN_TRIM(Var_type)
553
DO i=1,Circuit % n
554
slen = Matc('C.'//i2s(CId)//'.name.'//i2s(i),name)
555
IF(name(1:char_len) == Var_type(1:char_len)) nofc = nofc + 1
556
END DO
557
558
!------------------------------------------------------------------------------
559
END FUNCTION CountNofCircVarsOfType
560
!------------------------------------------------------------------------------
561
562
!------------------------------------------------------------------------------
563
FUNCTION CountNofCircComponents(CId, nofvar) RESULT (nofc)
564
!------------------------------------------------------------------------------
565
IMPLICIT NONE
566
INTEGER :: nofc, nofvar, slen, CId, i, j, CompId, ibracket
567
INTEGER :: ComponentIDs(nofvar)
568
TYPE(Circuit_t), POINTER :: Circuit
569
CHARACTER(:), ALLOCATABLE :: cmd
570
CHARACTER(LEN=MAX_NAME_LEN) :: name
571
572
nofc = 0
573
ComponentIDs = -1
574
575
Circuit => CurrentModel % Circuits(CId)
576
577
578
DO i=1,Circuit % n
579
slen = Matc('C.'//i2s(CId)//'.name.'//i2s(i),name)
580
581
IF(isComponentName(name,slen)) THEN
582
DO ibracket=1,slen
583
IF(name(ibracket:ibracket)=='(') EXIT
584
END DO
585
586
DO j=ibracket+1,slen
587
IF(name(j:j)==')') EXIT
588
END DO
589
590
READ(name(ibracket+1:j-1),*) CompId
591
592
IF (.NOT. ANY(ComponentIDs == CompID)) nofc = nofc + 1
593
ComponentIDs(i) = CompId
594
END IF
595
596
END DO
597
598
!------------------------------------------------------------------------------
599
END FUNCTION CountNofCircComponents
600
!------------------------------------------------------------------------------
601
602
!------------------------------------------------------------------------------
603
FUNCTION isComponentName(name, len) RESULT(L)
604
!------------------------------------------------------------------------------
605
CHARACTER(LEN=*) :: name
606
INTEGER :: len
607
LOGICAL :: L
608
609
L = .FALSE.
610
IF(len<12) RETURN
611
IF(name(1:12)=='i_component(' .OR. &
612
name(1:12)=='v_component(' .OR. &
613
name(1:14)=='phi_component(') L=.TRUE.
614
!------------------------------------------------------------------------------
615
END FUNCTION isComponentName
616
!------------------------------------------------------------------------------
617
618
619
!------------------------------------------------------------------------------
620
SUBROUTINE ReadCircuitVariables(CId)
621
!------------------------------------------------------------------------------
622
IMPLICIT NONE
623
INTEGER :: slen, ComponentId,i,j,CId, CompInd, nofc, ibracket
624
TYPE(Circuit_t), POINTER :: Circuit
625
TYPE(CircuitVariable_t), POINTER :: CVar
626
LOGICAL :: LondonEquations = .FALSE.
627
CHARACTER(:), ALLOCATABLE :: cmd
628
CHARACTER(LEN=MAX_NAME_LEN) :: name
629
630
Circuit => CurrentModel % Circuits(CId)
631
632
nofc = SIZE(Circuit % Components)
633
DO i=1,nofc
634
Circuit % Components(i) % ComponentId = 0
635
END DO
636
637
CompInd = 0
638
DO i=1,Circuit % n
639
slen = Matc('C.'//i2s(CId)//'.name.'//i2s(i),name)
640
Circuit % names(i) = name(1:slen)
641
642
CVar => Circuit % CircuitVariables(i)
643
CVar % isIvar = .FALSE.
644
CVar % isVvar = .FALSE.
645
CVar % Component => Null()
646
647
IF(isComponentName(name,slen)) THEN
648
DO ibracket=1,slen
649
IF(name(ibracket:ibracket)=='(') EXIT
650
END DO
651
652
DO j=ibracket+1,slen
653
IF(name(j:j)==')') EXIT
654
END DO
655
READ(name(ibracket+1:j-1),*) ComponentId
656
657
CVar % BodyId = ComponentId
658
659
DO j=1,nofc
660
Cvar % Component => Circuit % Components(j)
661
IF(CVar % Component % ComponentId==ComponentId) EXIT
662
END DO
663
664
IF(CVar % Component % ComponentID /= ComponentId ) THEN
665
CompInd = CompInd + 1
666
CVar % Component => Circuit % Components(CompInd)
667
END IF
668
669
Cvar % Component % ComponentId = ComponentId
670
671
SELECT CASE (name(1:ibracket))
672
CASE('i_component(')
673
CVar % isIvar = .TRUE.
674
CVar % Component % ivar => CVar
675
CASE('v_component(')
676
LondonEquations = ListGetLogical(CurrentModel % Components (ComponentId) % Values, &
677
'London Equations', LondonEquations)
678
IF (.NOT. LondonEquations) THEN
679
CVar % isVvar = .TRUE.
680
CVar % Component % vvar => CVar
681
ELSE
682
Cvar % Component => Null()
683
CVar % isIvar = .FALSE.
684
CVar % isVvar = .FALSE.
685
CVar % dofs = 1
686
CVar % pdofs = 0
687
CVar % BodyId = 0
688
END IF
689
CASE('phi_component(')
690
! London equations lead to driving the a-formulation
691
! with the so called node flux. Thus we replace 'v_component'
692
! variable with phi_component:
693
! (beta a, phi') + phi_component(1) (beta grad phi_0, grad phi') = i_component(1)
694
!--------------------------------------------------------------------------------
695
CVar % isVvar = .TRUE.
696
CVar % Component % vvar => CVar
697
CASE DEFAULT
698
CALL Fatal('Circuits_Init()', 'Circuit variable should be either i_component or v_component!')
699
END SELECT
700
ELSE
701
CVar % isIvar = .FALSE.
702
CVar % isVvar = .FALSE.
703
CVar % dofs = 1
704
CVar % pdofs = 0
705
CVar % BodyId = 0
706
END IF
707
END DO
708
709
!------------------------------------------------------------------------------
710
END SUBROUTINE ReadCircuitVariables
711
!------------------------------------------------------------------------------
712
713
714
!------------------------------------------------------------------------------
715
FUNCTION GetNofCircVariables(CId) RESULT(n)
716
!------------------------------------------------------------------------------
717
IMPLICIT NONE
718
INTEGER :: CId, n, slen
719
TYPE(Circuit_t), POINTER :: Circuit
720
721
Circuit => CurrentModel % Circuits(CId)
722
Circuit % n = NINT(GetMatcReal('C.'//i2s(CId)//'.variables'))
723
n = Circuit % n
724
!------------------------------------------------------------------------------
725
END FUNCTION GetNofCircVariables
726
!------------------------------------------------------------------------------
727
728
729
!------------------------------------------------------------------------------
730
SUBROUTINE AllocateCircuit(CId)
731
!------------------------------------------------------------------------------
732
IMPLICIT NONE
733
INTEGER :: CId,n
734
TYPE(Circuit_t), POINTER :: Circuit
735
736
Circuit => CurrentModel % Circuits(CId)
737
738
n = Circuit % n
739
740
ALLOCATE(Circuit % ComponentIds(n))
741
ALLOCATE(Circuit % CircuitVariables(n), Circuit % Perm(n))
742
ALLOCATE(Circuit % names(n), Circuit % source(n))
743
ALLOCATE(Circuit % A(n,n), Circuit % B(n,n), &
744
Circuit % Mre(n,n), Circuit % Mim(n,n) )
745
Circuit % ComponentIds = 0
746
Circuit % names = ' '
747
Circuit % A = 0._dp
748
Circuit % B = 0._dp
749
Circuit % Mre = 0._dp
750
Circuit % Mim = 0._dp
751
752
!------------------------------------------------------------------------------
753
END SUBROUTINE AllocateCircuit
754
!------------------------------------------------------------------------------
755
756
!-------------------------------------------------------------------
757
SUBROUTINE SetBoundaryAreasToValueLists()
758
!-------------------------------------------------------------------
759
IMPLICIT NONE
760
TYPE(Element_t), POINTER :: Element
761
TYPE(Mesh_t), POINTER :: Mesh
762
TYPE(Valuelist_t), POINTER :: BC
763
REAL(KIND=dp), ALLOCATABLE :: BoundaryAreas(:)
764
REAL(KIND=dp) :: area
765
INTEGER :: Active, t0, t, i, BCid, n, nBC
766
INTEGER, POINTER :: ChildBCs(:)
767
LOGICAL :: Found
768
LOGICAL :: Parallel
769
770
Mesh => CurrentModel % Mesh
771
772
Parallel = CurrentModel % Solver % Parallel
773
774
! Not all boundary elements are associated to a BC.
775
! Some may also be created by extrusion.
776
t0 = Mesh % NumberOfBulkElements
777
nBC = 0
778
DO t=1,Mesh % NumberOfBoundaryElements
779
Element => Mesh % Elements(t0+t)
780
IF(ASSOCIATED(Element % BoundaryInfo) ) THEN
781
nBC = MAX(nBC, Element % BoundaryInfo % Constraint )
782
END IF
783
END DO
784
785
nBC = MAX(nBC,CurrentModel % NumberOfBCs)
786
nBC = ParallelReduction(nBC,2)
787
788
ALLOCATE( BoundaryAreas(nBC) )
789
BoundaryAreas = 0.0_dp
790
791
DO i=1, CurrentModel % NumberOfBcs
792
BC => CurrentModel % BCs(i) % Values
793
IF (.NOT. ASSOCIATED(BC) ) CALL Fatal('SetBoundaryAreasToValueLists', 'Boundary not found!')
794
CALL ListAddInteger(BC, 'Boundary Id', i)
795
END DO
796
797
Active = GetNOFBoundaryElements()
798
DO t=1,Active
799
Element => GetBoundaryElement(t)
800
801
BC=>GetBC()
802
IF (ASSOCIATED(BC) ) THEN
803
BCid = GetInteger(BC, 'Boundary Id', Found)
804
ELSE
805
BCid = Element % BoundaryInfo % Constraint
806
END IF
807
808
IF( BCid > 0 ) THEN
809
n = GetElementNOFNodes()
810
BoundaryAreas(BCid) = BoundaryAreas(BCid) + ElementAreaNoAxisTreatment(Mesh, Element, n)
811
END IF
812
END DO
813
814
IF( Parallel ) THEN
815
DO i=1, nBC
816
BoundaryAreas(i) = ParallelReduction(BoundaryAreas(i))
817
END DO
818
END IF
819
820
IF( InfoActive(25) ) THEN
821
DO i=1,nBC
822
PRINT *,'A(i)',i,i<=CurrentModel % NumberOfBCs,BoundaryAreas(i)
823
END DO
824
END IF
825
826
DO i=1, CurrentModel % NumberOfBcs
827
BC => CurrentModel % BCs(i) % Values
828
IF (.NOT. ASSOCIATED(BC) ) CALL Fatal('ComputeCoilBoundaryAreas', 'Boundary not found!')
829
BCid = GetInteger(BC, 'Boundary Id', Found)
830
CALL ListAddConstReal(BC, 'Area', BoundaryAreas(BCid))
831
END DO
832
833
DO i=1, CurrentModel % NumberOfBodies
834
BC => CurrentModel % Bodies(i) % Values
835
ChildBCs => ListGetIntegerArray( BC,'Extruded Child BCs',Found )
836
IF(Found) THEN
837
!PRINT *,'Child BCs area:',i,BoundaryAreas(ChildBCs)
838
area = SUM(BoundaryAreas(ChildBCs)) / SIZE( ChildBCs )
839
CALL ListAddConstReal(BC,'Extruded Child Area', area )
840
END IF
841
END DO
842
843
!-------------------------------------------------------------------
844
END SUBROUTINE SetBoundaryAreasToValueLists
845
!-------------------------------------------------------------------
846
847
848
!------------------------------------------------------------------------------
849
SUBROUTINE ReadComponents(CId)
850
!------------------------------------------------------------------------------
851
USE CircuitUtils
852
IMPLICIT NONE
853
INTEGER :: CId, CompInd
854
TYPE(Circuit_t), POINTER :: Circuit
855
TYPE(Component_t), POINTER :: Comp
856
TYPE(Valuelist_t), POINTER :: CompParams
857
LOGICAL :: Found
858
INTEGER :: ExtMaster
859
860
CALL Info('ReadComponents','Reading component: '//I2S(Cid),Level=20)
861
862
Circuit => CurrentModel % Circuits(CId)
863
864
Circuit % CvarDofs = 0
865
DO CompInd=1,Circuit % n_comp
866
Comp => Circuit % Components(CompInd)
867
Comp % nofcnts = 0
868
! Comp % ComponentId = Circuits(p) % body(CompInd)
869
Comp % BodyIds => GetComponentBodyIds(Comp % ComponentId)
870
871
IF (.NOT. ASSOCIATED(Comp % ivar) ) THEN
872
CALL FATAL('Circuits_Init', 'Current Circuit Variable is not found for Component '//i2s(Comp % ComponentId))
873
ELSE IF (.NOT. ASSOCIATED(Comp % vvar) ) THEN
874
CALL FATAL('Circuits_Init', 'Voltage Circuit Variable is not found for Component '//i2s(Comp % ComponentId))
875
END IF
876
877
CompParams => CurrentModel % Components (Comp % ComponentId) % Values
878
IF (.NOT. ASSOCIATED(CompParams)) CALL Fatal ('Circuits_Init', 'Component parameters not found!')
879
880
Comp % CoilType = GetString(CompParams, 'Coil Type', Found)
881
IF (.NOT. Found) THEN
882
CALL Info('Circuits_Init', 'Component '//i2s(Comp % ComponentId)//' is not a coil. &
883
Checking if it has a component type.', Level=7)
884
Comp % ComponentType = GetString(CompParams, 'Component Type', Found)
885
IF (.NOT. Found) CALL Fatal ('Circuits_Init', 'Component Type not found!')
886
ELSE
887
Comp % ComponentType = 'coil'
888
END IF
889
890
Comp % i_multiplier_re = GetConstReal(CompParams, 'Current Multiplier re', Found)
891
IF (.NOT. Found) Comp % i_multiplier_re = 0._dp
892
Comp % i_multiplier_im = GetConstReal(CompParams, 'Current Multiplier im', Found)
893
IF (.NOT. Found) Comp % i_multiplier_im = 0._dp
894
895
Comp % VoltageFactor = GetConstReal(CompParams, 'Circuit Equation Voltage Factor', Found)
896
IF (.NOT. Found) Comp % VoltageFactor = 1._dp
897
898
Comp % ElBoundaries => ListGetIntegerArray(CompParams, 'Electrode Boundaries', Found)
899
900
! This is a feature intended to make it easier to extruded meshes internally with
901
! ElmerSolver. The idea is that the code knows which are the BCs that were created
902
! from extruding this 2D body.
903
ExtMaster = 0
904
IF(.NOT. Found ) THEN
905
IF( ListGetLogical( CurrentModel % Solver % Values,'Extruded Child BC Electrode', Found ) ) THEN
906
907
IF( ListGetLogical( CurrentModel % Simulation,"Extruded BCs Collect",Found ) ) THEN
908
CALL Fatal('Circuits_init',&
909
'Conflicting keywords: "Extruded Child BC Electrode" vs. "Extruded BCs Collect"')
910
END IF
911
912
CALL Info('Circuits_init','Setting "Extruded Child BCs"',Level=10)
913
BLOCK
914
INTEGER :: body_id
915
INTEGER, POINTER :: pIntArray(:) => NULL()
916
pIntArray => ListGetIntegerArray(CompParams, 'Body', Found )
917
IF(.NOT. Found) pIntArray => ListGetIntegerArray(CompParams, 'Master Bodies', Found )
918
IF( Found ) THEN
919
IF(SIZE(pIntArray)==1) THEN
920
body_id = pIntArray(1)
921
NULLIFY(pIntArray)
922
pIntArray => ListGetIntegerArray(CurrentModel % Bodies(body_id) % Values,&
923
'Extruded Child BCs',Found )
924
IF(Found) THEN
925
CALL Info('Circuits_init','Setting Component '//I2S(CompInd)//' "Electrode Boundaries" to '&
926
//I2S(pIntArray(1))//' '//I2S(pIntArray(2)),Level=10)
927
Comp % ElBoundaries => pIntArray
928
ExtMaster = body_id
929
END IF
930
END IF
931
END IF
932
END BLOCK
933
END IF
934
END IF
935
936
IF (Comp % ComponentType == 'resistor') THEN
937
Comp % ivar % dofs = 1
938
Comp % vvar % dofs = 1
939
Comp % ivar % pdofs = 0
940
Comp % vvar % pdofs = 0
941
ELSE
942
SELECT CASE (Comp % CoilType)
943
CASE ('stranded')
944
945
Comp % nofturns = GetConstReal(CompParams, 'Number of Turns', Found)
946
IF (.NOT. Found) CALL Fatal('Circuits_Init','Number of Turns not found!')
947
948
Comp % ElArea = GetConstReal(CompParams, 'Electrode Area', Found)
949
IF (.NOT. Found) THEN
950
CALL ComputeElectrodeArea(Comp, CompParams, ExtMaster )
951
WRITE(Message,'(A,ES12.5)') 'Component '//I2S(CompInd)//' "Electrode Area" is ',Comp % ElArea
952
CALL Info('Circuits_Init',Message,Level=10)
953
END IF
954
955
Comp % CoilThickness = GetConstReal(CompParams, 'Coil Thickness', Found)
956
IF (.NOT. Found) Comp % CoilThickness = 1._dp
957
958
Comp % SymmetryCoeff = GetConstReal(CompParams, 'Symmetry Coefficient', Found)
959
IF (.NOT. Found) Comp % SymmetryCoeff = 1.0_dp
960
961
Comp % N_j = Comp % CoilThickness * Comp % nofturns / Comp % ElArea
962
963
! Stranded coil has current and voltage
964
! variables (which both have a dof):
965
! ------------------------------------
966
Comp % ivar % dofs = 1
967
Comp % vvar % dofs = 1
968
Comp % ivar % pdofs = 0
969
Comp % vvar % pdofs = 0
970
971
CASE ('massive')
972
! Massive coil has current and voltage
973
! variables (which both have a dof):
974
! ------------------------------------
975
Comp % ivar % dofs = 1
976
Comp % vvar % dofs = 1
977
Comp % ivar % pdofs = 0
978
Comp % vvar % pdofs = 0
979
980
CASE ('foil winding')
981
Comp % polord = GetInteger(CompParams, 'Foil Winding Voltage Polynomial Order', Found)
982
IF (.NOT. Found) Comp % polord = 2
983
984
! Foil winding has current and voltage
985
! variables. Current has one dof and
986
! voltage has a polynom for describing the
987
! global voltage. The polynom has 1+"polynom order"
988
! dofs. Thus voltage variable has 1+1+"polynom order"
989
! dofs (V=V0+V1*alpha+V2*alpha^2+..):
990
! dofs:
991
! V, V0, V1, V2, ...
992
! ------------------------------------
993
Comp % ivar % dofs = 1
994
Comp % ivar % pdofs = 0
995
Comp % vvar % dofs = Comp % polord + 2
996
! polynom dofs:
997
! -------------
998
Comp % vvar % pdofs = Comp % polord + 1
999
1000
Comp % coilthickness = GetConstReal(CompParams, 'Coil Thickness', Found)
1001
IF (.NOT. Found) CALL Fatal('Circuits_Init','Coil Thickness not found!')
1002
1003
Comp % nofturns = GetConstReal(CompParams, 'Number of Turns', Found)
1004
IF (.NOT. Found) CALL Fatal('Circuits_Init','Number of Turns not found!')
1005
1006
Comp % ElArea = GetConstReal(CompParams, 'Electrode Area', Found)
1007
IF (.NOT. Found) THEN
1008
CALL ComputeElectrodeArea(Comp, CompParams )
1009
WRITE(Message,'(A,ES12.5)') 'Component '//I2S(CompInd)//' "Electrode Area" is ',Comp % ElArea
1010
CALL Info('Circuits_Init',Message,Level=10)
1011
END IF
1012
1013
Comp % N_j = Comp % nofturns / Comp % ElArea
1014
END SELECT
1015
END IF
1016
1017
CALL AddVariableToCircuit(Circuit, Comp % ivar, CId)
1018
CALL AddVariableToCircuit(Circuit, Comp % vvar, CId)
1019
1020
END DO
1021
1022
!------------------------------------------------------------------------------
1023
END SUBROUTINE ReadComponents
1024
!------------------------------------------------------------------------------
1025
1026
!-------------------------------------------------------------------
1027
SUBROUTINE ComputeElectrodeArea(Comp, CompParams, ExtMaster )
1028
!-------------------------------------------------------------------
1029
USE ElementUtils
1030
IMPLICIT NONE
1031
TYPE(Component_t), POINTER :: Comp
1032
TYPE(ValueList_t), POINTER :: CompParams
1033
INTEGER, OPTIONAL :: ExtMaster
1034
1035
TYPE(ValueList_t), POINTER :: BC
1036
TYPE(Element_t), POINTER :: Element
1037
TYPE(Mesh_t), POINTER :: Mesh
1038
INTEGER :: t, n, BCid, NoSlices
1039
LOGICAL :: Found
1040
LOGICAL :: Parallel
1041
1042
Mesh => CurrentModel % Mesh
1043
Comp % ElArea = 0._dp
1044
1045
Parallel = ( ParEnv % PEs > 1 )
1046
IF( Parallel ) THEN
1047
! If we have single mesh then we have either parallel times or parallel slices.
1048
! In both cases let us not do a parallel sum.
1049
IF( Mesh % SingleMesh ) Parallel = .FALSE.
1050
END IF
1051
1052
IF (CoordinateSystemDimension() == 2) THEN
1053
DO t=1,GetNOFActive()
1054
Element => GetActiveElement(t)
1055
n = GetElementNOFNodes()
1056
IF (ElAssocToComp(Element, Comp)) THEN
1057
Comp % ElArea = Comp % ElArea + ElementAreaNoAxisTreatment(Mesh, Element, n)
1058
END IF
1059
END DO
1060
1061
IF( Parallel ) THEN
1062
Comp % ElArea = ParallelReduction(Comp % ElArea)
1063
END IF
1064
1065
! Add this to list since no need to compute this twice
1066
CALL ListAddConstReal(CompParams,'Electrode Area',Comp % ElArea )
1067
ELSE
1068
BCid = 0
1069
1070
! This is a special case for extruded meshes where the area is computed and stored
1071
! in the master body that the extruded boundary comes from. This is treated only
1072
! when the extruded master is given as a parameter.
1073
IF( PRESENT( ExtMaster ) ) BCid = ExtMaster
1074
IF( BCid > 0 ) THEN
1075
BC => CurrentModel % Bodies(BCid) % Values
1076
IF (.NOT. ASSOCIATED(BC) ) CALL Fatal('ComputeElectrodeArea', 'Master body not found!')
1077
Comp % ElArea = GetConstReal(BC, 'Extruded Child Area', Found )
1078
IF (.NOT. Found) CALL Fatal('ComputeElectrodeArea', '"Extruded Child Area" not found!')
1079
ELSE
1080
IF (.NOT. ASSOCIATED(Comp % ElBoundaries)) &
1081
CALL Fatal('ComputeElectrodeArea','Electrode Boundaries not found')
1082
BCid = Comp % ElBoundaries(1)
1083
IF( BCid < 1 .OR. BCid > CurrentModel % NumberOfBCs ) &
1084
CALL Fatal('ComputeElectrodeArea', 'BCid is beyond range: '//I2S(BCid))
1085
1086
BC => CurrentModel % BCs(BCid) % Values
1087
IF (.NOT. ASSOCIATED(BC) ) CALL Fatal('ComputeElectrodeArea', 'Boundary not found!')
1088
Comp % ElArea = GetConstReal(BC, 'Area', Found)
1089
IF (.NOT. Found) CALL Fatal('ComputeElectrodeArea', '"Area" not found!')
1090
END IF
1091
END IF
1092
1093
!-------------------------------------------------------------------
1094
END SUBROUTINE ComputeElectrodeArea
1095
!-------------------------------------------------------------------
1096
1097
! This function is originally from ElementUtils. However, there is
1098
! some kind of treatment regarding axisymmetric cases which fails
1099
! here since we don't want that.
1100
!------------------------------------------------------------------------------
1101
FUNCTION ElementAreaNoAxisTreatment( Mesh,Element,N ) RESULT(A)
1102
!------------------------------------------------------------------------------
1103
TYPE(Mesh_t), POINTER :: Mesh
1104
INTEGER :: N
1105
TYPE(Element_t) :: Element
1106
!------------------------------------------------------------------------------
1107
1108
REAL(KIND=dp), TARGET :: NX(N),NY(N),NZ(N)
1109
1110
REAL(KIND=dp) :: A
1111
1112
TYPE(GaussIntegrationPoints_t), TARGET :: IntegStuff
1113
INTEGER :: N_Integ,t
1114
1115
REAL(KIND=dp) :: Metric(3,3),Symb(3,3,3),dSymb(3,3,3,3), &
1116
SqrtMetric,SqrtElementMetric
1117
1118
TYPE(Nodes_t) :: Nodes
1119
1120
LOGICAL :: stat
1121
1122
REAL(KIND=dp) :: Basis(n),u,v,w,x,y,z
1123
REAL(KIND=dp) :: dBasisdx(n,3)
1124
1125
REAL(KIND=dp), DIMENSION(:), POINTER :: U_Integ,V_Integ,W_Integ,S_Integ
1126
!------------------------------------------------------------------------------
1127
1128
Nodes % x => NX
1129
Nodes % y => NY
1130
Nodes % z => NZ
1131
1132
Nodes % x = Mesh % Nodes % x(Element % NodeIndexes)
1133
Nodes % y = Mesh % Nodes % y(Element % NodeIndexes)
1134
Nodes % z = Mesh % Nodes % z(Element % NodeIndexes)
1135
1136
IntegStuff = GaussPoints( element )
1137
U_Integ => IntegStuff % u
1138
V_Integ => IntegStuff % v
1139
W_Integ => IntegStuff % w
1140
S_Integ => IntegStuff % s
1141
N_Integ = IntegStuff % n
1142
!
1143
!------------------------------------------------------------------------------
1144
! Now we start integrating
1145
!------------------------------------------------------------------------------
1146
!
1147
A = 0.0
1148
DO t=1,N_Integ
1149
!
1150
! Integration stuff
1151
!
1152
u = U_Integ(t)
1153
v = V_Integ(t)
1154
w = W_Integ(t)
1155
!
1156
!------------------------------------------------------------------------------
1157
! Basis function values & derivatives at the integration point
1158
!------------------------------------------------------------------------------
1159
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric, &
1160
Basis,dBasisdx )
1161
!------------------------------------------------------------------------------
1162
! Coordinatesystem dependent info
1163
!------------------------------------------------------------------------------
1164
A = A + SqrtElementMetric * S_Integ(t)
1165
END DO
1166
!------------------------------------------------------------------------------
1167
END FUNCTION ElementAreaNoAxisTreatment
1168
!------------------------------------------------------------------------------
1169
1170
1171
1172
!------------------------------------------------------------------------------
1173
SUBROUTINE AddVariableToCircuit(Circuit, Variable, k)
1174
!------------------------------------------------------------------------------
1175
IMPLICIT NONE
1176
TYPE(Circuit_t) :: Circuit
1177
TYPE(CircuitVariable_t) :: Variable
1178
INTEGER :: Owner=-1, k
1179
INTEGER, POINTER :: circuit_tot_n => Null()
1180
1181
CALL Info('AddVariableToCircuit','Adding variables count to circuit!',Level=20)
1182
1183
Circuit_tot_n => CurrentModel % Circuit_tot_n
1184
1185
IF(k==1) THEN
1186
IF(Owner<=0) Owner = MAX(Parenv % PEs/2,1)
1187
Owner = Owner - 1
1188
Variable % Owner = Owner
1189
variable % owner = 0
1190
ELSE
1191
IF(Owner<=ParEnv % PEs/2) Owner = ParEnv % PEs
1192
Owner = Owner - 1
1193
Variable % Owner = Owner
1194
variable % owner = ParEnv % PEs-1
1195
END IF
1196
1197
IF (Circuit % Harmonic) THEN
1198
IF (Circuit % UsePerm) THEN
1199
Variable % valueId = Circuit % Perm(Circuit_tot_n + 1)
1200
Variable % ImValueId = Variable % valueId + 1
1201
ELSE
1202
Variable % valueId = Circuit_tot_n + 1
1203
Variable % ImValueId = Circuit_tot_n + 2
1204
END IF
1205
1206
Circuit_tot_n = Circuit_tot_n + 2*Variable % dofs
1207
ELSE
1208
IF (Circuit % UsePerm) THEN
1209
Variable % valueId = Circuit % Perm(Circuit_tot_n + 1)
1210
ELSE
1211
Variable % valueId = Circuit_tot_n + 1
1212
END IF
1213
1214
Circuit_tot_n = Circuit_tot_n + Variable % dofs
1215
END IF
1216
!------------------------------------------------------------------------------
1217
END SUBROUTINE AddVariableToCircuit
1218
!------------------------------------------------------------------------------
1219
1220
!------------------------------------------------------------------------------
1221
SUBROUTINE AddComponentValuesToLists(CId)
1222
!------------------------------------------------------------------------------
1223
IMPLICIT NONE
1224
TYPE(Circuit_t), POINTER :: Circuit
1225
TYPE(Component_t), POINTER :: Comp
1226
TYPE(Valuelist_t), POINTER :: CompParams
1227
INTEGER :: CId, CompInd
1228
1229
Circuit => CurrentModel % Circuits(CId)
1230
1231
CALL Info('AddComponentValuesToLists','Adding "Circuit Voltage Variable *" keywords for '&
1232
//I2S(Circuit % n_comp)//' components in Circuit '//I2S(CId),Level=20)
1233
1234
DO CompInd=1,Circuit % n_comp
1235
1236
Comp => Circuit % Components(CompInd)
1237
1238
CompParams => CurrentModel % Components (Comp % ComponentId) % Values
1239
IF (.NOT. ASSOCIATED(CompParams)) CALL Fatal ('Circuits_Init', 'Component Parameters not found!')
1240
1241
CALL listAddInteger(CompParams, 'Circuit Voltage Variable Id', Comp % vvar % valueId)
1242
CALL listAddInteger(CompParams, 'Circuit Voltage Variable dofs', Comp % vvar % dofs)
1243
CALL listAddInteger(CompParams, 'Circuit Current Variable Id', Comp % ivar % valueId)
1244
CALL listAddInteger(CompParams, 'Circuit Current Variable dofs', Comp % ivar % dofs)
1245
CALL listAddConstReal(CompParams, 'Stranded Coil N_j', Comp % N_j)
1246
CurrentModel % Components (Comp % ComponentId) % Values => CompParams
1247
END DO
1248
1249
!------------------------------------------------------------------------------
1250
END SUBROUTINE AddComponentValuesToLists
1251
!------------------------------------------------------------------------------
1252
1253
!------------------------------------------------------------------------------
1254
SUBROUTINE AddBareCircuitVariables(CId)
1255
!------------------------------------------------------------------------------
1256
IMPLICIT NONE
1257
TYPE(Circuit_t), POINTER :: Circuit
1258
TYPE(CircuitVariable_t), POINTER :: CVar
1259
INTEGER :: CId, i
1260
1261
Circuit => CurrentModel % Circuits(CId)
1262
! add variables that are not associated to components
1263
DO i=1,Circuit % n
1264
Cvar => Circuit % CircuitVariables(i)
1265
IF (Cvar % isIvar .OR. Cvar % isVvar) CYCLE
1266
CALL AddVariableToCircuit(Circuit, Circuit % CircuitVariables(i), CId)
1267
END DO
1268
1269
!------------------------------------------------------------------------------
1270
END SUBROUTINE AddBareCircuitVariables
1271
!------------------------------------------------------------------------------
1272
1273
!------------------------------------------------------------------------------
1274
SUBROUTINE ReadCoefficientMatrices(CId)
1275
!------------------------------------------------------------------------------
1276
IMPLICIT NONE
1277
INTEGER :: CId,n
1278
TYPE(Circuit_t), POINTER :: Circuit
1279
1280
Circuit => CurrentModel % Circuits(CId)
1281
n = Circuit % n
1282
1283
! Read in the coefficient matrices for the circuit equations:
1284
! Ax' + Bx = source:
1285
! ------------------------------------------------------------
1286
1287
CALL matc_get_array('C.'//i2s(CId)//'.A'//CHAR(0),Circuit % A,n,n)
1288
CALL matc_get_array('C.'//i2s(CId)//'.B'//CHAR(0),Circuit % B,n,n)
1289
1290
IF (Circuit % Harmonic) THEN
1291
! Complex multiplier matrix is used for:
1292
! B = times(M,B), where B times is the element-wise product
1293
! ---------------------------------------------------------
1294
CALL matc_get_array('C.'//i2s(CId)//'.Mre'//CHAR(0),Circuit % Mre,n,n)
1295
CALL matc_get_array('C.'//i2s(CId)//'.Mim'//CHAR(0),Circuit % Mim,n,n)
1296
END IF
1297
1298
!------------------------------------------------------------------------------
1299
END SUBROUTINE ReadCoefficientMatrices
1300
!------------------------------------------------------------------------------
1301
1302
!------------------------------------------------------------------------------
1303
SUBROUTINE ReadPermutationVector(CId)
1304
!------------------------------------------------------------------------------
1305
IMPLICIT NONE
1306
INTEGER :: CId,n,slen,i
1307
TYPE(Circuit_t), POINTER :: Circuit
1308
1309
Circuit => CurrentModel % Circuits(CId)
1310
n = Circuit % n
1311
1312
DO i=1,n
1313
Circuit % Perm(i) = NINT(GetMatcReal('C.'//i2s(CId)//'.perm('//i2s(i-1)//')'))
1314
END DO
1315
IF(ANY(Circuit % Perm /= 0)) THEN
1316
Circuit % UsePerm = .TRUE.
1317
CALL Info( 'IHarmonic2D','Found Permutation vector for circuit '//i2s(CId), Level=4 )
1318
END IF
1319
!------------------------------------------------------------------------------
1320
END SUBROUTINE ReadPermutationVector
1321
!------------------------------------------------------------------------------
1322
1323
!------------------------------------------------------------------------------
1324
SUBROUTINE ReadCircuitSources(CId)
1325
!------------------------------------------------------------------------------
1326
IMPLICIT NONE
1327
INTEGER :: CId,n,slen,i
1328
TYPE(Circuit_t), POINTER :: Circuit
1329
CHARACTER(:), ALLOCATABLE :: cmd
1330
CHARACTER(LEN=MAX_NAME_LEN) :: name
1331
1332
Circuit => CurrentModel % Circuits(CId)
1333
n = Circuit % n
1334
DO i=1,n
1335
! Names of the source functions, these functions should be found
1336
! in the "Body Force 1" block of the .sif file.
1337
! (nc: is for 'no check' e.g. don't abort if the MATC variable is not found!)
1338
! ---------------------------------------------------------------------------
1339
slen = Matc('nc:C.'//i2s(CId)//'.source.'//i2s(i),name)
1340
Circuit % Source(i) = name(1:slen)
1341
END DO
1342
!------------------------------------------------------------------------------
1343
END SUBROUTINE ReadCircuitSources
1344
!------------------------------------------------------------------------------
1345
1346
!------------------------------------------------------------------------------
1347
SUBROUTINE WriteCoeffVectorsForCircVariables(CId)
1348
!------------------------------------------------------------------------------
1349
IMPLICIT NONE
1350
INTEGER :: CId,n,slen,i,j,RowId
1351
TYPE(Circuit_t), POINTER :: Circuit
1352
TYPE(CircuitVariable_t), POINTER :: Cvar
1353
COMPLEX(KIND=dp), PARAMETER :: im = (0._dp,1._dp)
1354
1355
Circuit => CurrentModel % Circuits(CId)
1356
n = Circuit % n
1357
1358
DO i=1,n
1359
Cvar => Circuit % CircuitVariables(i)
1360
RowId = Cvar % ValueId
1361
1362
ALLOCATE(Cvar % A(Circuit % n), &
1363
Cvar % B(Circuit % n), &
1364
Cvar % Mre(Circuit % n), &
1365
Cvar % Mim(Circuit % n), &
1366
Cvar % SourceRe(Circuit % n), &
1367
Cvar % SourceIm(Circuit % n))
1368
Cvar % A = 0._dp
1369
Cvar % B = 0._dp
1370
Cvar % Mre = 0._dp
1371
Cvar % Mim = 0._dp
1372
Cvar % SourceRe = 0._dp
1373
Cvar % SourceIm = 0._dp
1374
1375
DO j=1,Circuit % n
1376
IF (Circuit % A(i,j)/=0) Cvar % A(j) = Circuit % A(i,j)
1377
IF (Circuit % B(i,j)/=0) Cvar % B(j) = Circuit % B(i,j)
1378
IF (Circuit % Mre(i,j)/=0 .OR. Circuit % Mim(i,j)/=0) THEN
1379
Cvar % Mre(j) = Circuit % Mre(i,j)
1380
Cvar % Mim(j) = Circuit % Mim(i,j)
1381
END IF
1382
END DO
1383
END DO
1384
1385
!------------------------------------------------------------------------------
1386
END SUBROUTINE WriteCoeffVectorsForCircVariables
1387
!------------------------------------------------------------------------------
1388
1389
!------------------------------------------------------------------------------
1390
FUNCTION IdInList(Id, List) RESULT (T)
1391
!------------------------------------------------------------------------------
1392
IMPLICIT NONE
1393
INTEGER :: List(:), Id
1394
LOGICAL :: T
1395
T = .FALSE.
1396
IF (ANY(List == Id)) T = .TRUE.
1397
!------------------------------------------------------------------------------
1398
END FUNCTION IdInList
1399
!------------------------------------------------------------------------------
1400
1401
!------------------------------------------------------------------------------
1402
FUNCTION ElAssocToComp(Element, Component) RESULT (T)
1403
!------------------------------------------------------------------------------
1404
IMPLICIT NONE
1405
TYPE(Component_t), POINTER :: Component
1406
TYPE(Element_t), POINTER :: Element
1407
INTEGER :: k
1408
LOGICAL :: T, Found
1409
1410
k = GetInteger(GetBC(Element), 'Component', Found)
1411
1412
IF (Found) THEN
1413
T = (k .eq. Component % ComponentId)
1414
ELSE IF (ASSOCIATED(Component % BodyIds)) THEN
1415
T = IdInList(Element % BodyId, Component % BodyIds)
1416
ELSE
1417
T = .False.
1418
END IF
1419
1420
!------------------------------------------------------------------------------
1421
END FUNCTION ElAssocToComp
1422
!------------------------------------------------------------------------------
1423
1424
!------------------------------------------------------------------------------
1425
FUNCTION ElAssocToCvar(Element, Cvar) RESULT (T)
1426
!------------------------------------------------------------------------------
1427
IMPLICIT NONE
1428
TYPE(CircuitVariable_t), POINTER :: Cvar
1429
TYPE(Element_t), POINTER :: Element
1430
LOGICAL :: T
1431
T = .FALSE.
1432
IF (ASSOCIATED(Cvar % Component)) THEN
1433
IF (ASSOCIATED(Cvar % Component % BodyIds)) &
1434
T = IdInList(Element % BodyId, Cvar % Component % BodyIds)
1435
END IF
1436
!------------------------------------------------------------------------------
1437
END FUNCTION ElAssocToCvar
1438
!------------------------------------------------------------------------------
1439
1440
!------------------------------------------------------------------------------
1441
FUNCTION AddIndex(Ind, Harmonic)
1442
!------------------------------------------------------------------------------
1443
IMPLICIT NONE
1444
Integer :: Ind, AddIndex
1445
LOGICAL, OPTIONAL :: Harmonic
1446
LOGICAL :: harm
1447
1448
IF (.NOT. PRESENT(Harmonic)) THEN
1449
harm = CurrentModel % HarmonicCircuits
1450
ELSE
1451
harm = Harmonic
1452
END IF
1453
1454
IF (harm) THEN
1455
AddIndex = 2 * Ind
1456
ELSE
1457
AddIndex = Ind
1458
END IF
1459
!------------------------------------------------------------------------------
1460
END FUNCTION AddIndex
1461
!------------------------------------------------------------------------------
1462
1463
!------------------------------------------------------------------------------
1464
FUNCTION AddImIndex(Ind)
1465
!------------------------------------------------------------------------------
1466
IMPLICIT NONE
1467
INTEGER :: Ind
1468
Integer :: AddImIndex
1469
IF ( .NOT. CurrentModel % HarmonicCircuits ) CALL Fatal ('AddImIndex','Model is not of harmonic type!')
1470
1471
AddImIndex = 2 * Ind + 1
1472
!------------------------------------------------------------------------------
1473
END FUNCTION AddImIndex
1474
!------------------------------------------------------------------------------
1475
1476
!------------------------------------------------------------------------------
1477
FUNCTION ReIndex(Ind, Harmonic)
1478
!------------------------------------------------------------------------------
1479
IMPLICIT NONE
1480
INTEGER :: Ind, ReIndex
1481
LOGICAL, OPTIONAL :: Harmonic
1482
LOGICAL :: harm
1483
1484
IF (.NOT. PRESENT(Harmonic)) THEN
1485
harm = CurrentModel % HarmonicCircuits
1486
ELSE
1487
harm = Harmonic
1488
END IF
1489
1490
IF (harm) THEN
1491
ReIndex = 2 * Ind - 1
1492
ELSE
1493
ReIndex = Ind
1494
END IF
1495
!------------------------------------------------------------------------------
1496
END FUNCTION ReIndex
1497
!------------------------------------------------------------------------------
1498
1499
!------------------------------------------------------------------------------
1500
FUNCTION ImIndex(Ind)
1501
!------------------------------------------------------------------------------
1502
IMPLICIT NONE
1503
Integer :: Ind, ImIndex
1504
1505
ImIndex = 2 * Ind
1506
!------------------------------------------------------------------------------
1507
END FUNCTION ImIndex
1508
!------------------------------------------------------------------------------
1509
1510
!------------------------------------------------------------------------------
1511
FUNCTION HasSupport(Element, nn) RESULT(support)
1512
!------------------------------------------------------------------------------
1513
IMPLICIT NONE
1514
INTEGER :: nn, dim
1515
TYPE(Element_t) :: Element
1516
LOGICAL :: support, First=.TRUE.
1517
REAL(KIND=dp) :: wBase(nn)
1518
SAVE dim, First
1519
1520
IF (First) THEN
1521
First = .FALSE.
1522
dim = CoordinateSystemDimension()
1523
END IF
1524
1525
support = .TRUE.
1526
IF (dim == 3) THEN
1527
support = .FALSE.
1528
CALL GetLocalSolution(Wbase,'W')
1529
IF ( ANY(Wbase .ne. 0d0) ) support = .TRUE.
1530
END IF
1531
!------------------------------------------------------------------------------
1532
END FUNCTION HasSupport
1533
!------------------------------------------------------------------------------
1534
1535
1536
!------------------------------------------------------------------------------
1537
! Create a standard variable associated to the mesh that may be use for dependencies.
1538
!------------------------------------------------------------------------------
1539
SUBROUTINE Circuits_ToMeshVariable(Solver,crt)
1540
1541
TYPE(Solver_t) :: Solver
1542
REAL(KIND=dp) :: Crt(:)
1543
1544
TYPE(Circuit_t), POINTER :: Circuit
1545
TYPE(CircuitVariable_t), POINTER :: CVar
1546
TYPE(Variable_t), POINTER :: Var, VarIm
1547
INTEGER :: p,i,n,nv,ni,m,iv,nsize
1548
TYPE(Mesh_t), POINTER :: Mesh
1549
LOGICAL :: Found
1550
CHARACTER(:), ALLOCATABLE :: CrtName,VarName,VarnameIm
1551
1552
IF( .NOT. ListGetLogical( Solver % Values,'Export Circuit Variables',Found ) ) RETURN
1553
1554
CALL Info('Circuit_ToMeshVariable','Adding circuit variables to be mesh variables')
1555
1556
Mesh => Solver % Mesh
1557
1558
DO p=1,CurrentModel % n_Circuits
1559
CALL Info('Circuit_ToMeshVariable','Adding circuit: '//I2S(p),Level=12)
1560
1561
Circuit => CurrentModel % Circuits(p)
1562
1563
n = Circuit % n
1564
1565
IF( CurrentModel % n_Circuits == 1) THEN
1566
crtName = 'crt'
1567
ELSE
1568
crtName = 'crt '//I2S(p)
1569
END IF
1570
1571
! Count the v and i variables of the circuit.
1572
nv = 0; ni = 0
1573
DO i=1,n
1574
Cvar => Circuit % CircuitVariables(i)
1575
IF(Cvar % isIvar ) nv = nv + 1
1576
IF(Cvar % isVvar) ni = ni + 1
1577
END DO
1578
1579
IF( nv + ni == 0 ) THEN
1580
CALL Warn('Circuits_ToMeshVariable','No voltage or current variables exists!')
1581
CYCLE
1582
END IF
1583
1584
1585
! Go first through currents and then through voltages
1586
DO iv=1,2
1587
IF( Circuit % Harmonic ) THEN
1588
IF(iv==1) THEN
1589
varname = crtname//' i re'
1590
varnameim = crtname//' i im'
1591
ELSE
1592
varname = crtname//' v re'
1593
varnameim = crtname//' v im'
1594
END IF
1595
ELSE
1596
IF(iv==1) THEN
1597
varname = crtname//' i'
1598
ELSE
1599
varname = crtname//' v'
1600
END IF
1601
END IF
1602
1603
IF(iv==1) THEN
1604
nsize = ni
1605
ELSE
1606
nsize = nv
1607
END IF
1608
1609
! Get variable, if variable does not exist then we create here on-the-fly
1610
Var => VariableGet( Mesh % Variables,varname)
1611
IF(.NOT. ASSOCIATED( Var ) ) THEN
1612
CALL Info('Circuits_ToMeshVariable','Creating variable: '//TRIM(varname))
1613
CALL VariableAddVector( Mesh % Variables, Mesh, Solver,&
1614
varname,dofs=nsize,global=.TRUE.)
1615
Var => VariableGet( Mesh % Variables,varname)
1616
END IF
1617
CALL Info('Circuts_toMeshVariable','Filling variable: '//TRIM(VarName),Level=20)
1618
1619
IF( Circuit % Harmonic ) THEN
1620
VarIm => VariableGet( Mesh % Variables,varnameim)
1621
IF(.NOT. ASSOCIATED( VarIm ) ) THEN
1622
CALL Info('Circuits_ToMeshVariable','Creating variable: '//TRIM(varnameim))
1623
CALL VariableAddVector( Mesh % Variables, Mesh, Solver,&
1624
varnameim,dofs=nsize,global=.TRUE.)
1625
VarIm => VariableGet( Mesh % Variables,varnameim)
1626
END IF
1627
CALL Info('Circuts_toMeshVariable','Filling variable: '//TRIM(VarNameim),Level=20)
1628
END IF
1629
1630
1631
! Fill the currents or voltages
1632
m = 0
1633
DO i=1,n
1634
Cvar => Circuit % CircuitVariables(i)
1635
1636
IF(iv==1 .AND. .NOT. CVar % isIvar ) CYCLE
1637
IF(iv==2 .AND. .NOT. Cvar % isVvar) CYCLE
1638
1639
CALL Info('Circuts_toMeshVariable','Inserting variable '//I2S(CVar % ValueId)//': '&
1640
//TRIM(Circuit % names(i)),Level=20)
1641
1642
m = m + 1
1643
Var % Values(m) = crt(Cvar % ValueId)
1644
IF(Circuit % Harmonic) THEN
1645
VarIm % Values(m) = crt(Cvar % ImValueId)
1646
END IF
1647
END DO
1648
END DO
1649
END DO
1650
1651
END SUBROUTINE Circuits_ToMeshVariable
1652
1653
1654
END MODULE CircuitsMod
1655
1656
MODULE CircMatInitMod
1657
1658
USE CircuitsMod
1659
IMPLICIT NONE
1660
1661
CONTAINS
1662
1663
!------------------------------------------------------------------------------
1664
SUBROUTINE SetCircuitsParallelInfo()
1665
!------------------------------------------------------------------------------
1666
IMPLICIT NONE
1667
TYPE(Matrix_t), POINTER :: CM
1668
TYPE(CircuitVariable_t), POINTER :: Cvar
1669
TYPE(Solver_t), POINTER :: ASolver
1670
TYPE(Circuit_t), POINTER :: Circuits(:)
1671
TYPE(Element_t), POINTER :: Element
1672
INTEGER :: i, nm, Circuit_tot_n, p, j, &
1673
cnt(Parenv % PEs), r_cnt(ParEnv % PEs), &
1674
RowId, nn, l, k, n_Circuits
1675
1676
CM => CurrentModel % CircuitMatrix
1677
ASolver => CurrentModel % Asolver
1678
IF (.NOT.ASSOCIATED(ASolver)) CALL Fatal('SetCircuitsParallelInfo','ASolver not found!')
1679
nm = ASolver % Matrix % NumberOfRows
1680
Circuit_tot_n = CurrentModel % Circuit_tot_n
1681
Circuits => CurrentModel % Circuits
1682
n_Circuits = CurrentModel % n_Circuits
1683
1684
IF(.NOT.ASSOCIATED(CM % ParallelInfo)) THEN
1685
ALLOCATE(CM % ParallelInfo)
1686
ALLOCATE(CM % ParallelInfo % NeighbourList(nm+Circuit_tot_n))
1687
DO i=1,nm+Circuit_tot_n
1688
CM % ParallelInfo % NeighbourList(i) % Neighbours => Null()
1689
END DO
1690
END IF
1691
1692
DO p = 1,n_Circuits
1693
DO i=1,Circuits(p) % n
1694
cnt = 0
1695
Cvar => Circuits(p) % CircuitVariables(i)
1696
IF(ASSOCIATED(CVar%Component)) THEN
1697
DO j=1,GetNOFACtive()
1698
Element => GetActiveElement(j)
1699
IF(ElAssocToCvar(Element, Cvar)) THEN
1700
cnt(ParEnv % mype+1)=cnt(ParEnv % mype+1)+1
1701
END IF
1702
END DO
1703
END IF
1704
CALL MPI_ALLREDUCE(cnt,r_cnt,ParEnv % PEs, MPI_INTEGER, &
1705
MPI_MAX,ASolver % Matrix % Comm,j)
1706
1707
1708
RowId = Cvar % ValueId + nm
1709
1710
nn = COUNT(r_cnt>0)
1711
IF( r_cnt(CVar % Owner+1)<=0 ) THEN
1712
r_cnt(CVar % Owner+1) = 1
1713
nn=nn + 1
1714
END IF
1715
1716
IF(r_cnt(Parenv % myPE+1)<=0) THEN
1717
r_cnt(parenv % mype+1) = 1
1718
nn = nn + 1
1719
END IF
1720
1721
r_cnt = 1; nn=Parenv % PEs ! for now
1722
1723
IF (Circuits(p) % Harmonic) THEN
1724
DO j=1,Cvar % Dofs
1725
IF(.NOT.ASSOCIATED(CM % ParallelInfo % NeighbourList(RowId+AddIndex(j-1))%Neighbours)) THEN
1726
ALLOCATE(CM % ParallelInfo % NeighbourList(RowId+AddIndex(j-1)) % Neighbours(nn))
1727
ALLOCATE(CM % ParallelInfo % NeighbourList(RowId+AddImIndex(j-1)) % Neighbours(nn))
1728
END IF
1729
CM % ParallelInfo % NeighbourList(RowId+AddIndex(j-1)) % Neighbours(1) = CVar % Owner
1730
CM % ParallelInfo % NeighbourList(RowId+AddImIndex(j-1)) % Neighbours(1) = Cvar % Owner
1731
l = 1
1732
DO k=0,ParEnv % PEs-1
1733
IF(k==CVar % Owner) CYCLE
1734
IF(r_cnt(k+1)>0) THEN
1735
l = l + 1
1736
CM % ParallelInfo % NeighbourList(RowId+AddIndex(j-1)) % Neighbours(l) = k
1737
CM % ParallelInfo % NeighbourList(RowId+AddImIndex(j-1)) % Neighbours(l) = k
1738
END IF
1739
END DO
1740
CM % RowOwner(RowId + AddIndex(j-1)) = Cvar % Owner
1741
CM % RowOwner(RowId + AddImIndex(j-1)) = Cvar % Owner
1742
END DO
1743
ELSE
1744
DO j=1,Cvar % Dofs
1745
IF(.NOT.ASSOCIATED(CM % ParallelInfo % NeighbourList(RowId+j-1)%Neighbours)) THEN
1746
ALLOCATE(CM % ParallelInfo % NeighbourList(RowId+j-1) % Neighbours(nn))
1747
END IF
1748
CM % ParallelInfo % NeighbourList(RowId+j-1) % Neighbours(1) = CVar % Owner
1749
l = 1
1750
DO k=0,ParEnv % PEs-1
1751
IF(k==CVar % Owner) CYCLE
1752
IF(r_cnt(k+1)>0) THEN
1753
l = l + 1
1754
CM % ParallelInfo % NeighbourList(RowId+j-1) % Neighbours(l) = k
1755
END IF
1756
END DO
1757
CM % RowOwner(RowId+j-1) = Cvar % Owner
1758
END DO
1759
END IF
1760
END DO
1761
END DO
1762
1763
1764
IF ( parenv % mype==0 ) THEN
1765
DO i=1,parenv % pes
1766
CALL INFO('SetCircuitsParallelInfo','owners: '//i2s(i)//' '//i2s(count(cm % rowowner==i-1)), Level=9)
1767
END DO
1768
END IF
1769
!------------------------------------------------------------------------------
1770
END SUBROUTINE SetCircuitsParallelInfo
1771
!------------------------------------------------------------------------------
1772
1773
1774
!------------------------------------------------------------------------------
1775
SUBROUTINE CountCmplxMatElement(Rows, Cnts, RowId, dofs)
1776
!------------------------------------------------------------------------------
1777
IMPLICIT NONE
1778
INTEGER :: Rows(:), Cnts(:)
1779
INTEGER :: RowId, dofs
1780
1781
! Matrix element structure:
1782
!
1783
! Re -Im
1784
! Im Re
1785
!
1786
! First do Re -Im:
1787
! ----------------
1788
Cnts(RowId) = Cnts(RowId) + 2 * dofs
1789
1790
! Then do Im Re:
1791
! --------------
1792
Cnts(RowId+1) = Cnts(RowId+1) + 2 * dofs
1793
1794
!------------------------------------------------------------------------------
1795
END SUBROUTINE CountCmplxMatElement
1796
!------------------------------------------------------------------------------
1797
1798
!------------------------------------------------------------------------------
1799
SUBROUTINE CountMatElement(Rows, Cnts, RowId, dofs, Harmonic)
1800
!------------------------------------------------------------------------------
1801
IMPLICIT NONE
1802
INTEGER :: Rows(:), Cnts(:)
1803
INTEGER :: RowId, dofs
1804
LOGICAL, OPTIONAL :: Harmonic
1805
LOGICAL :: harm
1806
1807
IF (.NOT. PRESENT(Harmonic)) THEN
1808
harm = CurrentModel % HarmonicCircuits
1809
ELSE
1810
harm = Harmonic
1811
END IF
1812
1813
IF (harm) THEN
1814
CALL CountCmplxMatElement(Rows, Cnts, RowId, dofs)
1815
ELSE
1816
Cnts(RowId) = Cnts(RowId) + dofs
1817
END IF
1818
1819
!------------------------------------------------------------------------------
1820
END SUBROUTINE CountMatElement
1821
!------------------------------------------------------------------------------
1822
1823
!------------------------------------------------------------------------------
1824
SUBROUTINE CreateCmplxMatElement(Rows, Cols, Cnts, RowId, ColId)
1825
!------------------------------------------------------------------------------
1826
IMPLICIT NONE
1827
INTEGER :: Rows(:), Cols(:), Cnts(:)
1828
INTEGER :: RowId, ColId
1829
1830
! Matrix element structure:
1831
!
1832
! Re -Im
1833
! Im Re
1834
!
1835
! First do Re (0,0):
1836
! ------------------
1837
Cols(Rows(RowId) + Cnts(RowId)) = ColId
1838
Cnts(RowId) = Cnts(RowId) + 1
1839
1840
! Then do -Im (0,1):
1841
! ------------------
1842
Cols(Rows(RowId) + Cnts(RowId)) = ColId + 1
1843
Cnts(RowId) = Cnts(RowId) + 1
1844
1845
! Then do Re (1,0):
1846
! -----------------
1847
Cols(Rows(RowId+1) + Cnts(RowId+1)) = ColId
1848
Cnts(RowId+1) = Cnts(RowId+1) + 1
1849
1850
! Then do Im (1,1):
1851
! -----------------
1852
Cols(Rows(RowId+1) + Cnts(RowId+1)) = ColId + 1
1853
Cnts(RowId+1) = Cnts(RowId+1) + 1
1854
1855
!------------------------------------------------------------------------------
1856
END SUBROUTINE CreateCmplxMatElement
1857
!------------------------------------------------------------------------------
1858
1859
!------------------------------------------------------------------------------
1860
SUBROUTINE CreateMatElement(Rows, Cols, Cnts, RowId, ColId, Harmonic)
1861
!------------------------------------------------------------------------------
1862
IMPLICIT NONE
1863
INTEGER :: Rows(:), Cols(:), Cnts(:)
1864
INTEGER :: RowId, ColId
1865
LOGICAL, OPTIONAL :: Harmonic
1866
LOGICAL :: harm
1867
1868
IF (.NOT. PRESENT(Harmonic)) THEN
1869
harm = CurrentModel % HarmonicCircuits
1870
ELSE
1871
harm = Harmonic
1872
END IF
1873
1874
IF (harm) THEN
1875
CALL CreateCmplxMatElement(Rows, Cols, Cnts, RowId, ColId)
1876
ELSE
1877
Cols(Rows(RowId) + Cnts(RowId)) = ColId
1878
Cnts(RowId) = Cnts(RowId) + 1
1879
END IF
1880
1881
!------------------------------------------------------------------------------
1882
END SUBROUTINE CreateMatElement
1883
!------------------------------------------------------------------------------
1884
1885
1886
!------------------------------------------------------------------------------
1887
SUBROUTINE CountBasicCircuitEquations(Rows, Cnts)
1888
!------------------------------------------------------------------------------
1889
IMPLICIT NONE
1890
TYPE(Circuit_t), POINTER :: Circuits(:)
1891
TYPE(CircuitVariable_t), POINTER :: Cvar
1892
INTEGER :: i, j, p, nm, RowId, n_Circuits
1893
INTEGER, POINTER :: Rows(:), Cnts(:)
1894
1895
Circuits => CurrentModel % Circuits
1896
n_Circuits = CurrentModel % n_Circuits
1897
nm = CurrentModel % Asolver % Matrix % NumberOfRows
1898
1899
! Basic circuit equations...
1900
! ---------------------------
1901
DO p = 1,n_Circuits
1902
DO i=1,Circuits(p) % n
1903
Cvar => Circuits(p) % CircuitVariables(i)
1904
IF(CVar % Owner /= ParEnv % myPE) CYCLE
1905
1906
RowId = Cvar % ValueId + nm
1907
DO j=1,Circuits(p) % n
1908
IF(Cvar % A(j)/=0._dp.OR.Cvar % B(j)/=0._dp) &
1909
CALL CountMatElement(Rows, Cnts, RowId, 1)
1910
END DO
1911
END DO
1912
END DO
1913
!------------------------------------------------------------------------------
1914
END SUBROUTINE CountBasicCircuitEquations
1915
!------------------------------------------------------------------------------
1916
1917
!------------------------------------------------------------------------------
1918
SUBROUTINE CreateBasicCircuitEquations(Rows, Cols, Cnts)
1919
!------------------------------------------------------------------------------
1920
IMPLICIT NONE
1921
TYPE(Circuit_t), POINTER :: Circuits(:)
1922
TYPE(CircuitVariable_t), POINTER :: Cvar
1923
INTEGER :: i, j, p, nm, RowId, ColId, n_Circuits
1924
INTEGER, POINTER :: Rows(:), Cols(:), Cnts(:)
1925
1926
Circuits => CurrentModel % Circuits
1927
n_Circuits = CurrentModel % n_Circuits
1928
nm = CurrentModel % Asolver % Matrix % NumberOfRows
1929
1930
! Basic circuit equations...
1931
! ---------------------------
1932
DO p = 1,n_Circuits
1933
DO i=1,Circuits(p) % n
1934
Cvar => Circuits(p) % CircuitVariables(i)
1935
IF(Cvar % Owner /= ParEnv % myPE) CYCLE
1936
1937
RowId = Cvar % ValueId + nm
1938
DO j=1,Circuits(p) % n
1939
IF(Cvar % A(j)/=0._dp .OR. Cvar % B(j)/=0._dp) THEN
1940
ColId = Circuits(p) % CircuitVariables(j) % ValueId + nm
1941
CALL CreateMatElement(Rows, Cols, Cnts, RowId, ColId)
1942
END IF
1943
END DO
1944
END DO
1945
END DO
1946
1947
!------------------------------------------------------------------------------
1948
END SUBROUTINE CreateBasicCircuitEquations
1949
!------------------------------------------------------------------------------
1950
1951
!------------------------------------------------------------------------------
1952
SUBROUTINE CountComponentEquations(Rows, Cnts, Done, dofsdone)
1953
!------------------------------------------------------------------------------
1954
IMPLICIT NONE
1955
TYPE(Circuit_t), POINTER :: Circuits(:)
1956
TYPE(CircuitVariable_t), POINTER :: Cvar
1957
TYPE(Solver_t), POINTER :: ASolver
1958
TYPE(Element_t), POINTER :: Element
1959
TYPE(Component_t), POINTER :: Comp
1960
INTEGER :: i, j, p, nm, nn, nd, &
1961
RowId, ColId, n_Circuits, &
1962
CompInd, q
1963
INTEGER, POINTER :: Rows(:), Cnts(:)
1964
LOGICAL :: dofsdone
1965
LOGICAL*1 :: Done(:)
1966
1967
Circuits => CurrentModel % Circuits
1968
n_Circuits = CurrentModel % n_Circuits
1969
Asolver => CurrentModel % Asolver
1970
nm = Asolver % Matrix % NumberOfRows
1971
DO p=1,n_Circuits
1972
DO CompInd=1,Circuits(p) % n_comp
1973
Done = .FALSE.
1974
Comp => Circuits(p) % Components(CompInd)
1975
Cvar => Comp % vvar
1976
RowId = Cvar % ValueId + nm
1977
ColId = Cvar % ValueId + nm
1978
IF (Comp % ComponentType == 'resistor') THEN
1979
CALL CountMatElement(Rows, Cnts, RowId, 1)
1980
CALL CountMatElement(Rows, Cnts, RowId, 1)
1981
CYCLE
1982
ELSE
1983
SELECT CASE (Comp % CoilType)
1984
CASE('stranded')
1985
CALL CountMatElement(Rows, Cnts, RowId, 1)
1986
CALL CountMatElement(Rows, Cnts, RowId, 1)
1987
CASE('massive')
1988
CALL CountMatElement(Rows, Cnts, RowId, 1)
1989
CALL CountMatElement(Rows, Cnts, RowId, 1)
1990
CASE('foil winding')
1991
! V = V0 + V1*alpha + V2*alpha^2 + ...
1992
CALL CountMatElement(Rows, Cnts, RowId, Cvar % dofs)
1993
1994
! Circuit eqns for the pdofs:
1995
! I(Vj) - I = 0
1996
! ------------------------------------
1997
DO j=1, Cvar % pdofs
1998
CALL CountMatElement(Rows, Cnts, RowId + AddIndex(j), Cvar % dofs)
1999
END DO
2000
END SELECT
2001
END IF
2002
2003
! temp = SUM(Cnts)
2004
!print *, "Active elements", ParEnv % Mype, ":", GetNOFActive()
2005
DO q=GetNOFActive(),1,-1
2006
Element => GetActiveElement(q)
2007
CALL CountComponentElements(Element, Comp, RowId, Rows, Cnts, Done, dofsdone)
2008
END DO
2009
2010
DO q=GetNOFBoundaryElements(),1,-1
2011
Element => GetBoundaryElement(q)
2012
CALL CountComponentElements(Element, Comp, RowId, Rows, Cnts, Done, dofsdone)
2013
END DO
2014
! Comp % nofcnts = SUM(Cnts) - temp
2015
! print *, ParEnv % Mype, "CompInd:", CompInd, "Comp % nofcnts", Comp % nofcnts
2016
END DO
2017
END DO
2018
!------------------------------------------------------------------------------
2019
END SUBROUTINE CountComponentEquations
2020
!------------------------------------------------------------------------------
2021
2022
!------------------------------------------------------------------------------
2023
SUBROUTINE CreateComponentEquations(Rows, Cols, Cnts, Done, dofsdone)
2024
!------------------------------------------------------------------------------
2025
IMPLICIT NONE
2026
TYPE(Circuit_t), POINTER :: Circuits(:)
2027
TYPE(CircuitVariable_t), POINTER :: Cvar
2028
TYPE(Solver_t), POINTER :: ASolver
2029
TYPE(Element_t), POINTER :: Element
2030
TYPE(Component_t), POINTER :: Comp
2031
INTEGER :: i, j, jj, p, nm, nn, nd, &
2032
VvarId, IvarId, n_Circuits, &
2033
CompInd, q
2034
INTEGER, POINTER :: Rows(:), Cols(:), Cnts(:)
2035
LOGICAL :: dofsdone
2036
LOGICAL*1 :: Done(:)
2037
2038
Circuits => CurrentModel % Circuits
2039
n_Circuits = CurrentModel % n_Circuits
2040
Asolver => CurrentModel % Asolver
2041
nm = Asolver % Matrix % NumberOfRows
2042
2043
DO p=1,n_Circuits
2044
DO CompInd = 1, Circuits(p) % n_comp
2045
Done = .FALSE.
2046
Comp => Circuits(p) % Components(CompInd)
2047
Cvar => Comp % vvar
2048
VvarId = Comp % vvar % ValueId + nm
2049
IvarId = Comp % ivar % ValueId + nm
2050
2051
IF (Comp % ComponentType == 'resistor') THEN
2052
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, IvarId)
2053
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, VvarId)
2054
CYCLE
2055
ELSE
2056
SELECT CASE (Comp % CoilType)
2057
CASE('stranded')
2058
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, IvarId)
2059
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, VvarId)
2060
CASE('massive')
2061
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, IvarId)
2062
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, VvarId)
2063
CASE('foil winding')
2064
DO j=0, Cvar % pdofs
2065
! V = V0 + V1*alpha + V2*alpha^2 + ...
2066
CALL CreateMatElement(Rows, Cols, Cnts, VvarId, VvarId + AddIndex(j))
2067
IF (j/=0) THEN
2068
! Circuit eqns for the pdofs:
2069
! I(Vi) - I = 0
2070
! ------------------------------------
2071
CALL CreateMatElement(Rows, Cols, Cnts, VvarId + AddIndex(j), IvarId)
2072
DO jj = 1, Cvar % pdofs
2073
CALL CreateMatElement(Rows, Cols, Cnts, VvarId + AddIndex(j), VvarId + AddIndex(j))
2074
END DO
2075
END IF
2076
END DO
2077
END SELECT
2078
END IF
2079
2080
! temp = SUM(Cnts)
2081
!print *, "Active elements ", ParEnv % Mype, ":", GetNOFActive()
2082
DO q=GetNOFActive(),1,-1
2083
Element => GetActiveElement(q)
2084
CALL CreateComponentElements(Element, Comp, VvarId, IvarId, Rows, Cols, Cnts, Done, dofsdone)
2085
END DO
2086
2087
DO q=GetNOFBoundaryElements(),1,-1
2088
Element => GetBoundaryElement(q)
2089
CALL CreateComponentElements(Element, Comp, VvarId, IvarId, Rows, Cols, Cnts, Done, dofsdone)
2090
END DO
2091
! Comp % nofcnts = SUM(Cnts) - temp
2092
! print *, ParEnv % Mype, "CompInd:", CompInd, "Coil Type:", Comp % CoilType, &
2093
! "Comp % BodyId:", Comp % BodyId, "Comp % nofcnts", Comp % nofcnts
2094
2095
END DO
2096
END DO
2097
!------------------------------------------------------------------------------
2098
END SUBROUTINE CreateComponentEquations
2099
!------------------------------------------------------------------------------
2100
2101
!------------------------------------------------------------------------------
2102
SUBROUTINE CountComponentElements(Element, Comp, RowId, Rows, Cnts, Done, dofsdone)
2103
!------------------------------------------------------------------------------
2104
IMPLICIT NONE
2105
TYPE(Element_t), POINTER :: Element
2106
TYPE(Component_t), POINTER :: Comp
2107
INTEGER :: nn, nd, RowId
2108
TYPE(Solver_t), POINTER :: ASolver
2109
INTEGER, POINTER :: Rows(:), Cnts(:)
2110
LOGICAL*1 :: Done(:)
2111
LOGICAL :: dofsdone
2112
2113
IF (ElAssocToComp(Element, Comp)) THEN
2114
Asolver => CurrentModel % Asolver
2115
nn = GetElementNOFNodes(Element)
2116
nd = GetElementNOFDOFs(Element,ASolver)
2117
SELECT CASE (Comp % CoilType)
2118
CASE('stranded')
2119
CALL CountAndCreateStranded(Element,nn,nd,RowId,Cnts,Done,Rows)
2120
CASE('massive')
2121
IF (HasSupport(Element,nn)) THEN
2122
CALL CountAndCreateMassive(Element,nn,nd,RowId,Cnts,Done,Rows)
2123
END IF
2124
CASE('foil winding')
2125
IF (HasSupport(Element,nn)) THEN
2126
CALL CountAndCreateFoilWinding(Element,nn,nd,Comp,Cnts,Done,Rows)
2127
END IF
2128
END SELECT
2129
END IF
2130
!------------------------------------------------------------------------------
2131
END SUBROUTINE CountComponentElements
2132
!------------------------------------------------------------------------------
2133
2134
!------------------------------------------------------------------------------
2135
SUBROUTINE CreateComponentElements(Element, Comp, VvarId, IvarId, Rows, Cols, Cnts, Done, dofsdone)
2136
!------------------------------------------------------------------------------
2137
IMPLICIT NONE
2138
TYPE(Element_t), POINTER :: Element
2139
TYPE(Component_t), POINTER :: Comp
2140
TYPE(Solver_t), POINTER :: ASolver
2141
INTEGER :: nn, nd, VvarId, IvarId
2142
INTEGER, POINTER :: Rows(:), Cols(:), Cnts(:)
2143
LOGICAL*1 :: Done(:)
2144
LOGICAL :: dofsdone
2145
2146
IF (ElAssocToComp(Element, Comp)) THEN
2147
Asolver => CurrentModel % Asolver
2148
nn = GetElementNOFNodes(Element)
2149
nd = GetElementNOFDOFs(Element,ASolver)
2150
SELECT CASE (Comp % CoilType)
2151
CASE('stranded')
2152
CALL CountAndCreateStranded(Element,nn,nd,VvarId,Cnts,Done,Rows,Cols,IvarId)
2153
CASE('massive')
2154
IF (HasSupport(Element,nn)) THEN
2155
CALL CountAndCreateMassive(Element,nn,nd,VvarId,Cnts,Done,Rows,Cols=Cols)
2156
END IF
2157
CASE('foil winding')
2158
IF (HasSupport(Element,nn)) THEN
2159
CALL CountAndCreateFoilWinding(Element,nn,nd,Comp,Cnts,Done,Rows,Cols=Cols)
2160
END IF
2161
END SELECT
2162
END IF
2163
!------------------------------------------------------------------------------
2164
END SUBROUTINE CreateComponentElements
2165
!------------------------------------------------------------------------------
2166
2167
!------------------------------------------------------------------------------
2168
SUBROUTINE CountAndCreateStranded(Element,nn,nd,i,Cnts,Done,Rows,Cols,Jsind,Harmonic)
2169
!------------------------------------------------------------------------------
2170
IMPLICIT NONE
2171
TYPE(Element_t) :: Element
2172
INTEGER :: nn, nd, ncdofs1, ncdofs2, dim
2173
OPTIONAL :: Cols
2174
INTEGER :: Rows(:), Cols(:), Cnts(:)
2175
INTEGER :: p,i,j,k,Indexes(nd)
2176
INTEGER, OPTIONAL :: Jsind
2177
INTEGER, POINTER :: PS(:)
2178
LOGICAL*1 :: Done(:)
2179
LOGICAL :: First=.TRUE.
2180
LOGICAL, OPTIONAL :: Harmonic
2181
LOGICAL :: harm
2182
SAVE dim, First
2183
2184
IF (First) THEN
2185
First = .FALSE.
2186
dim = CoordinateSystemDimension()
2187
END IF
2188
2189
IF (.NOT. PRESENT(Harmonic)) THEN
2190
harm = CurrentModel % HarmonicCircuits
2191
ELSE
2192
harm = Harmonic
2193
END IF
2194
2195
2196
IF (.NOT. ASSOCIATED(CurrentModel % ASolver) ) CALL Fatal ('CountAndCreateStranded','ASolver not found!')
2197
PS => CurrentModel % Asolver % Variable % Perm
2198
2199
nd = GetElementDOFs(Indexes,Element,CurrentModel % ASolver)
2200
IF(dim==2) THEN
2201
ncdofs1=1
2202
ncdofs2=nd
2203
ELSE IF(dim==3) THEN
2204
ncdofs1=nn+1
2205
ncdofs2=nd
2206
END IF
2207
2208
DO p=ncdofs1,ncdofs2
2209
j = Indexes(p)
2210
2211
IF( ASSOCIATED( CurrentModel % Mesh % PeriodicPerm ) ) THEN
2212
! If we have periodicity eliminated only flag the master in Done
2213
k = CurrentModel % Mesh % PeriodicPerm(j)
2214
IF( k > 0 ) j = k
2215
END IF
2216
2217
IF(.NOT.Done(j)) THEN
2218
Done(j) = .TRUE.
2219
j = PS(j)
2220
IF (harm) j = ReIndex(j)
2221
IF(PRESENT(Cols)) THEN
2222
CALL CreateMatElement(Rows, Cols, Cnts, i, j, harm)
2223
CALL CreateMatElement(Rows, Cols, Cnts, j, Jsind, harm)
2224
! CALL CreateMatElement(Rows, Cols, Cnts, j, Jsind)
2225
ELSE
2226
CALL CountMatElement(Rows, Cnts, i, 1, harm)
2227
CALL CountMatElement(Rows, Cnts, j, 1, harm)
2228
! CALL CountMatElement(Rows, Cnts, j, 1)
2229
END IF
2230
END IF
2231
END DO
2232
!------------------------------------------------------------------------------
2233
END SUBROUTINE CountAndCreateStranded
2234
!------------------------------------------------------------------------------
2235
2236
!------------------------------------------------------------------------------
2237
SUBROUTINE CountAndCreateMassive(Element,nn,nd,i,Cnts,Done,Rows,Cols,Harmonic)
2238
!------------------------------------------------------------------------------
2239
IMPLICIT NONE
2240
TYPE(Element_t) :: Element
2241
INTEGER :: nn, nd, ncdofs1, ncdofs2, dim
2242
OPTIONAL :: Cols
2243
INTEGER :: Rows(:), Cols(:), Cnts(:)
2244
INTEGER :: p,i,j,k,Indexes(nd)
2245
INTEGER, POINTER :: PS(:)
2246
LOGICAL*1 :: Done(:)
2247
LOGICAL :: First=.TRUE.
2248
LOGICAL, OPTIONAL :: Harmonic
2249
LOGICAL :: harm
2250
SAVE dim, First
2251
2252
IF (First) THEN
2253
First = .FALSE.
2254
dim = CoordinateSystemDimension()
2255
END IF
2256
2257
IF (.NOT. PRESENT(Harmonic)) THEN
2258
harm = CurrentModel % HarmonicCircuits
2259
ELSE
2260
harm = Harmonic
2261
END IF
2262
2263
IF (.NOT. ASSOCIATED(CurrentModel % ASolver) ) CALL Fatal ('CountAndCreateMassive','ASolver not found!')
2264
PS => CurrentModel % Asolver % Variable % Perm
2265
nd = GetElementDOFs(Indexes,Element,CurrentModel % ASolver)
2266
IF(dim==2) THEN
2267
ncdofs1=1
2268
ncdofs2=nd
2269
ELSE IF(dim==3) THEN
2270
ncdofs1=nn+1
2271
ncdofs2=nd
2272
END IF
2273
DO p=ncdofs1,ncdofs2
2274
j = Indexes(p)
2275
2276
IF( ASSOCIATED( CurrentModel % Mesh % PeriodicPerm ) ) THEN
2277
! If we have periodicity eliminated only flag the master in Done
2278
k = CurrentModel % Mesh % PeriodicPerm(j)
2279
IF( k > 0 ) j = k
2280
END IF
2281
2282
IF(.NOT.Done(j)) THEN
2283
Done(j) = .TRUE.
2284
j = PS(j)
2285
IF (harm) j = ReIndex(j)
2286
IF(PRESENT(Cols)) THEN
2287
CALL CreateMatElement(Rows, Cols, Cnts, i, j, harm)
2288
CALL CreateMatElement(Rows, Cols, Cnts, j, i, harm)
2289
ELSE
2290
CALL CountMatElement(Rows, Cnts, i, 1, harm)
2291
CALL CountMatElement(Rows, Cnts, j, 1, harm)
2292
END IF
2293
END IF
2294
END DO
2295
!------------------------------------------------------------------------------
2296
END SUBROUTINE CountAndCreateMassive
2297
!------------------------------------------------------------------------------
2298
2299
!------------------------------------------------------------------------------
2300
SUBROUTINE CountAndCreateFoilWinding(Element,nn,nd,Comp,Cnts,Done,Rows,Cols,Harmonic)
2301
!------------------------------------------------------------------------------
2302
IMPLICIT NONE
2303
TYPE(Element_t) :: Element
2304
TYPE(Component_t), POINTER :: Comp
2305
INTEGER :: nn, nd, ncdofs, dim
2306
OPTIONAL :: Cols
2307
INTEGER :: Rows(:), Cols(:), Cnts(:)
2308
INTEGER :: Indexes(nd)
2309
INTEGER :: p,j,q,vpolord,vpolordtest,vpolord_tot,&
2310
dofId,dofIdtest,vvarId, nm
2311
LOGICAL :: dofsdone, First=.TRUE.
2312
INTEGER, POINTER :: PS(:)
2313
LOGICAL*1 :: Done(:)
2314
LOGICAL, OPTIONAL :: Harmonic
2315
LOGICAL :: harm
2316
SAVE dim, First
2317
2318
IF (First) THEN
2319
First = .FALSE.
2320
dim = CoordinateSystemDimension()
2321
END IF
2322
2323
IF (.NOT. PRESENT(Harmonic)) THEN
2324
harm = CurrentModel % HarmonicCircuits
2325
ELSE
2326
harm = Harmonic
2327
END IF
2328
2329
IF (.NOT. ASSOCIATED(CurrentModel % ASolver) ) CALL Fatal ('CountAndCreateFoilWinding','ASolver not found!')
2330
PS => CurrentModel % Asolver % Variable % Perm
2331
nd = GetElementDOFs(Indexes,Element,CurrentModel % ASolver)
2332
nm = CurrentModel % ASolver % Matrix % NumberOfRows
2333
2334
ncdofs=nd
2335
IF (dim == 3) ncdofs=nd-nn
2336
2337
vvarId = Comp % vvar % ValueId
2338
vpolord_tot = Comp % vvar % pdofs - 1
2339
2340
DO vpolordtest=0,vpolord_tot ! V'(alpha)
2341
dofIdtest = AddIndex(vpolordtest + 1) + vvarId
2342
DO vpolord = 0, vpolord_tot ! V(alpha)
2343
dofId = AddIndex(vpolord + 1) + vvarId
2344
IF (PRESENT(Cols)) THEN
2345
CALL CreateMatElement(Rows, Cols, Cnts, dofIdtest+nm, dofId+nm, harm)
2346
ELSE
2347
CALL CountMatElement(Rows, Cnts, dofIdtest+nm, 1, harm)
2348
END IF
2349
END DO
2350
2351
DO j=1,ncdofs
2352
q=j
2353
IF (dim == 3) q=q+nn
2354
IF (PRESENT(Cols)) THEN
2355
q = PS(Indexes(q))
2356
IF (harm) q = ReIndex(q)
2357
CALL CreateMatElement(Rows, Cols, Cnts, dofIdtest+nm, q, harm)
2358
ELSE
2359
CALL CountMatElement(Rows, Cnts, dofIdtest+nm, 1, harm)
2360
END IF
2361
END DO
2362
END DO
2363
2364
DO vpolord = 0, vpolord_tot ! V(alpha)
2365
dofId = AddIndex(vpolord + 1) + vvarId
2366
DO j=1,ncdofs
2367
q=j
2368
IF (dim == 3) q=q+nn
2369
q = PS(Indexes(q))
2370
IF (harm) q = ReIndex(q)
2371
IF (PRESENT(Cols)) THEN
2372
CALL CreateMatElement(Rows, Cols, Cnts, q, dofId+nm, harm)
2373
ELSE
2374
CALL CountMatElement(Rows, Cnts, q, 1, harm)
2375
END IF
2376
END DO
2377
END DO
2378
!------------------------------------------------------------------------------
2379
END SUBROUTINE CountAndCreateFoilWinding
2380
!------------------------------------------------------------------------------
2381
2382
!------------------------------------------------------------------------------
2383
SUBROUTINE Circuits_MatrixInit()
2384
!------------------------------------------------------------------------------
2385
IMPLICIT NONE
2386
TYPE(Matrix_t), POINTER :: CM
2387
TYPE(Solver_t), POINTER :: ASolver
2388
INTEGER, POINTER :: PS(:), Cnts(:)
2389
INTEGER, POINTER CONTIG :: Rows(:), Cols(:)
2390
INTEGER :: nm, Circuit_tot_n, n, i
2391
LOGICAL :: dofsdone
2392
LOGICAL*1, ALLOCATABLE :: Done(:)
2393
REAL(KIND=dp), POINTER CONTIG :: Values(:)
2394
LOGICAL :: Parallel, Found
2395
2396
ASolver => CurrentModel % Asolver
2397
IF (.NOT.ASSOCIATED(ASolver)) CALL Fatal('Circuits_MatrixInit','ASolver not found!')
2398
Circuit_tot_n = CurrentModel % Circuit_tot_n
2399
2400
! Initialize Circuit matrix:
2401
! -----------------------------
2402
PS => Asolver % Variable % Perm
2403
nm = Asolver % Matrix % NumberOfRows
2404
2405
CM => AllocateMatrix()
2406
CurrentModel % CircuitMatrix=>CM
2407
2408
CM % Format = MATRIX_CRS
2409
Asolver % Matrix % AddMatrix => CM
2410
ALLOCATE(CM % RHS(nm + Circuit_tot_n)); CM % RHS=0._dp
2411
2412
CM % NumberOfRows = nm + Circuit_tot_n
2413
2414
n = CM % NumberOfRows
2415
2416
ALLOCATE(Rows(n+1), Cnts(n)); Rows=0; Cnts=0
2417
ALLOCATE(Done(SIZE(PS)), CM % RowOwner(n)); Cm % RowOwner=-1
2418
2419
2420
Parallel = CurrentModel % Solver % Parallel
2421
IF( Parallel ) CALL SetCircuitsParallelInfo()
2422
2423
! COUNT SIZES:
2424
! ============
2425
dofsdone = .FALSE.
2426
2427
CALL CountBasicCircuitEquations(Rows, Cnts)
2428
CALL CountComponentEquations(Rows, Cnts, Done, dofsdone)
2429
2430
! ALLOCATE CRS STRUCTURES (if need be):
2431
! =====================================
2432
2433
n = SUM(Cnts)
2434
2435
IF (n<=0) THEN
2436
CM % NUmberOfRows = 0
2437
DEALLOCATE(Rows,Cnts,Done,CM); CM=>Null()
2438
Asolver % Matrix % AddMatrix => CM
2439
CurrentModel % CircuitMatrix=>CM
2440
RETURN
2441
END IF
2442
2443
ALLOCATE(Cols(n+1), Values(n+1))
2444
Cols = 0; Values = 0._dp
2445
2446
! CREATE ROW POINTERS:
2447
! ====================
2448
2449
CM % NumberOfRows = nm + Circuit_tot_n
2450
Rows(1) = 1
2451
DO i=2,CM % NumberOfRows+1
2452
Rows(i) = Rows(i-1) + Cnts(i-1)
2453
END DO
2454
2455
Cnts = 0
2456
2457
! CREATE COLUMNS:
2458
! ===============
2459
2460
CALL CreateBasicCircuitEquations(Rows, Cols, Cnts)
2461
CALL CreateComponentEquations(Rows, Cols, Cnts, Done, dofsdone)
2462
2463
IF (n /= SUM(Cnts)) THEN
2464
CALL Fatal('Circuits_MatrixInit', &
2465
'Inconsistent number of matrix elements: '//I2S(n)//' vs. '//I2S(SUM(CNTs)))
2466
END IF
2467
2468
DEALLOCATE( Cnts, Done )
2469
CM % Rows => Rows
2470
CM % Cols => Cols
2471
CM % Values => Values
2472
CALL CRS_SortMatrix(CM)
2473
2474
Asolver % Matrix % AddMatrix => CM
2475
!------------------------------------------------------------------------------
2476
END SUBROUTINE Circuits_MatrixInit
2477
!------------------------------------------------------------------------------
2478
2479
2480
END MODULE CircMatInitMod
2481
2482
2483
2484