• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

trixi-framework / HOHQMesh / 30045849576

23 Jul 2026 09:21PM UTC coverage: 76.996% (+1.1%) from 75.909%
30045849576

Pull #166

github

web-flow
Merge 123ec0950 into 955f92dca
Pull Request #166: Add L2/H1 boundary optimization

1580 of 1903 new or added lines in 32 files covered. (83.03%)

44 existing lines in 2 files now uncovered.

9566 of 12424 relevant lines covered (77.0%)

634460.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.88
/Source/Project/Model/SMModel.f90
1
! MIT License
2
!
3
! Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md
4
!
5
! Permission is hereby granted, free of charge, to any person obtaining a copy
6
! of this software and associated documentation files (the "Software"), to deal
7
! in the Software without restriction, including without limitation the rights
8
! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
! copies of the Software, and to permit persons to whom the Software is
10
! furnished to do so, subject to the following conditions:
11
!
12
! The above copyright notice and this permission notice shall be included in all
13
! copies or substantial portions of the Software.
14
!
15
! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
! SOFTWARE.
22
!
23
! --- End License
24
!
25
!////////////////////////////////////////////////////////////////////////
26
!
27
!      SMModel.f90
28
!      Created: August 5, 2013 2:11 PM
29
!      By: David Kopriva
30
!
31
!////////////////////////////////////////////////////////////////////////
32
!
33
      Module SMModelClass
34
      USE ProgramGlobals
35
      USE FTLinkedListClass
36
      USE FTExceptionClass
37
      USE SMChainedCurveClass
38
      USE SharedExceptionManagerModule
39
      USE SMParametricEquationCurveClass
40
      USE SMSplineCurveClass
41
      USE SMLineClass
42
      USE SMEllipticArcClass
43
      USE CurveSweepClass
44
      USE FTValueDictionaryClass
45
      USE ErrorTypesModule
46
      USE SMTopographyClass
47
      USE SMEquationTopographyClass
48
      USE SMTopographyFromFileClass
49
      USE ScanningModule
50
      IMPLICIT NONE
51
!
52
!     ---------
53
!     Constants
54
!     ---------
55
!
56
      INTEGER, PARAMETER, PRIVATE :: INNER_BOUNDARY_BLOCK     = 0, INTERFACE_BOUNDARY_BLOCK = 1
57
      INTEGER, PARAMETER          :: BOUNDARY_CURVE           = 0, INTERFACE_CURVE = 1
58
      INTEGER, PARAMETER          :: BLOCK_NAME_STRING_LENGTH = 32
59
      CHARACTER(LEN=16)           :: MODEL_READ_EXCEPTION     = "Model read error"
60

61
      CHARACTER(LEN=LINE_LENGTH), PARAMETER, PRIVATE  :: OUTER_BOUNDARY_BLOCK_KEY       = "OUTER_BOUNDARY"
62
      CHARACTER(LEN=LINE_LENGTH), PARAMETER, PRIVATE  :: INNER_BOUNDARIES_BLOCK_KEY     = "INNER_BOUNDARIES"
63
      CHARACTER(LEN=LINE_LENGTH), PARAMETER, PRIVATE  :: INTERFACE_BOUNDARIES_BLOCK_KEY = "INTERFACE_BOUNDARIES"
64
      CHARACTER(LEN=LINE_LENGTH), PARAMETER           :: TOPOGRAPHY_BLOCK_KEY           = "TOPOGRAPHY"
65
      CHARACTER(LEN=LINE_LENGTH), PARAMETER           :: H1NORM_KEY                     = "H1Norm"
66
      CHARACTER(LEN=LINE_LENGTH), PARAMETER           :: L2NORM_KEY                     = "L2Norm"
67
!
68
!     ---------------------
69
!     Class type definition
70
!     ---------------------
71
!
72
      TYPE, EXTENDS(FTObject) ::  SMModel
73
         INTEGER                                  :: curveCount
74
         INTEGER                                  :: numberOfOuterCurves
75
         INTEGER                                  :: numberOfInnerCurves
76
         INTEGER                                  :: numberOfInterfaceCurves
77
         CHARACTER(LEN=32)                        :: modelName
78
         CLASS(SMChainedCurve)      , POINTER     :: outerBoundary       => NULL()
79
         CLASS(SMChainedCurve)      , POINTER     :: sweepCurve          => NULL()
80
         CLASS(SMChainedCurve)      , POINTER     :: scaleCurve          => NULL()
81
         CLASS(FTLinkedList)        , POINTER     :: innerBoundaries     => NULL()
82
         CLASS(FTLinkedList)        , POINTER     :: interfaceBoundaries => NULL()
83
         TYPE(FTLinkedListIterator) , POINTER     :: innerBoundariesIterator => NULL()
84
         TYPE(FTLinkedListIterator) , POINTER     :: interfaceBoundariesIterator => NULL()
85
         TYPE(FTMutableObjectArray) , POINTER     :: allChains  => NULL()
86
         CLASS(SMTopography)        , POINTER     :: topography => NULL()
87
         INTEGER                    , ALLOCATABLE :: boundaryCurveMap(:) ! Tells which chain a curve is in
88
         INTEGER, DIMENSION(:)      , ALLOCATABLE :: curveType           ! Either a boundary or an interface
89
!
90
!        ========
91
         CONTAINS
92
!        ========
93
!
94
         PROCEDURE :: initWithContentsOfDictionary
95
         FINAL     :: destructModel
96
         PROCEDURE :: chainWithID
97
         PROCEDURE :: curveWithID => curveInModelWithID
98
         PROCEDURE :: symmetryCurve
99
         PROCEDURE :: numberOfChains
100
      END TYPE SMModel
101
!
102
!     ========
103
      CONTAINS
104
!     ========
105
!
106
!////////////////////////////////////////////////////////////////////////
107
!
108
      SUBROUTINE initWithContentsOfDictionary( self, modelDict )
24✔
109
         IMPLICIT NONE
110
         CLASS(SMModel)                    :: self
111
         CLASS(FTValueDictionary), POINTER :: modelDict
112

113
         CALL self % FTObject % init()
24✔
114

115
         self % outerBoundary               => NULL()
24✔
116
         self % innerBoundaries             => NULL()
24✔
117
         self % interfaceBoundaries         => NULL()
24✔
118
         self % innerBoundariesIterator     => NULL()
24✔
119
         self % interfaceBoundariesIterator => NULL()
24✔
120
         self % topography                  => NULL()
24✔
121
         self % allChains                   => NULL()
24✔
122
         self % curveCount                  =  0
24✔
123
         self % numberOfOuterCurves         =  0
24✔
124
         self % numberOfInnerCurves         =  0
24✔
125
         self % numberOfInterfaceCurves     =  0
24✔
126

127
         IF( .NOT.ASSOCIATED(modelDict)) RETURN
24✔
128
         CALL constructModelFromDictionary( self, modelDict )
22✔
129

130
      END SUBROUTINE initWithContentsOfDictionary
131
!
132
!////////////////////////////////////////////////////////////////////////
133
!
134
      SUBROUTINE destructModel(self)
24✔
135
         IMPLICIT NONE
136
         TYPE(SMModel)            :: self
137
         CLASS(FTObject), POINTER :: obj
138

139
         obj => self % innerBoundariesIterator
24✔
140
         CALL release(self = obj)
24✔
141
         obj => self % interfaceBoundariesIterator
24✔
142
         CALL release(self = obj)
24✔
143
         obj => self % innerBoundaries
24✔
144
         CALL release(self = obj)
24✔
145
         obj => self % interfaceBoundaries
24✔
146
         CALL release(self = obj)
24✔
147
         obj => self % outerBoundary
24✔
148
         CALL release(obj)
24✔
149

150
         IF ( ASSOCIATED(self % sweepCurve) )     THEN
24✔
151
            obj => self % sweepCurve
1✔
152
            CALL release(obj)
1✔
153
         END IF
154

155
         IF ( ASSOCIATED(self % scaleCurve) )     THEN
24✔
156
            obj => self % scaleCurve
1✔
157
            CALL release(obj)
1✔
158
         END IF
159

160
         IF ( ALLOCATED(self % boundaryCurveMap) )     THEN
24✔
161
            DEALLOCATE(self % boundaryCurveMap)
21✔
162
         END IF
163

164
         IF ( ALLOCATED(self % curveType) )     THEN
24✔
165
            DEALLOCATE(self % curveType)
21✔
166
         END IF
167

168
         IF ( ASSOCIATED(self % topography) )     THEN
24✔
169
            obj => self % topography
4✔
170
            CALL release(obj)
4✔
171
         END IF
172

173
         IF ( ASSOCIATED(self % allChains) )     THEN
24✔
174
            CALL releaseFTMutableObjectArray(self % allChains)
22✔
175
         END IF
176

177
      END SUBROUTINE destructModel
24✔
178
!
179
!////////////////////////////////////////////////////////////////////////
180
!
181
      SUBROUTINE releaseModel(self)
24✔
182
         IMPLICIT NONE
183
         TYPE (SMModel)  , POINTER :: self
184
         CLASS(FTObject), POINTER :: obj
185

186
         IF(.NOT. ASSOCIATED(self)) RETURN
24✔
187

188
         obj => self
24✔
189
         CALL releaseFTObject(self = obj)
24✔
190
         IF ( .NOT. ASSOCIATED(obj) )     THEN
24✔
191
            self => NULL()
24✔
192
         END IF
193
      END SUBROUTINE releaseModel
194
!@mark -
195
!
196
!////////////////////////////////////////////////////////////////////////
197
!
198
      SUBROUTINE constructModelFromDictionary( self, modelDict )
22✔
199
         IMPLICIT NONE
200
!
201
!        -----------
202
!        Arguments
203
!        -----------
204
!
205
         CLASS(SMModel)                    :: self
206
         CLASS(FTValueDictionary), POINTER :: modelDict
207
!
208
!        ---------------
209
!        Local variables
210
!        ---------------
211
!
212
         INTEGER, EXTERNAL                 :: UnusedUnit
213
         CLASS(FTValueDictionary), POINTER :: outerBoundaryDict, innerBoundariesDict, sweepCurveDict
214
         CLASS(FTValueDictionary), POINTER :: topographyDict
215
         CLASS(FTValueDictionary), POINTER :: scaleCurveDict
216
         CLASS(FTLinkedList)     , POINTER :: innerBoundariesList
217
         CLASS(FTObject)         , POINTER :: obj
218
!
219
!        ----------
220
!        Interfaces
221
!        ----------
222
!
223
         LOGICAL, EXTERNAL :: ReturnOnFatalError
224
!
225
!        --------------------------------
226
!        Construct outer boundary, if any
227
!        --------------------------------
228
!
229
         IF ( modelDict % containsKey(key = OUTER_BOUNDARY_BLOCK_KEY) )     THEN
22✔
230

231
            ALLOCATE( self % outerBoundary )
20✔
232
            CALL self % outerBoundary % initChainWithNameAndID("Outer Boundary",1)
20✔
233

234
            obj               => modelDict % objectForKey(key = OUTER_BOUNDARY_BLOCK_KEY)
20✔
235
            outerBoundaryDict => valueDictionaryFromObject(obj)
20✔
236

237
            CALL ConstructOuterBoundary( self, outerBoundaryDict )
20✔
238
            IF(ReturnOnFatalError())     RETURN
20✔
239
            self % numberOfOuterCurves = 1
20✔
240

241
         END IF
242
!
243
!        ----------------------------------
244
!        Construct inner boundaries, if any
245
!        ----------------------------------
246
!
247
         IF ( modelDict% containsKey(key = INNER_BOUNDARIES_BLOCK_KEY) )     THEN
22✔
248

249
            ALLOCATE( self % innerBoundaries )
10✔
250
            CALL self % innerBoundaries % init()
10✔
251

252
            obj                 => modelDict % objectForKey(key = INNER_BOUNDARIES_BLOCK_KEY)
10✔
253
            innerBoundariesDict => valueDictionaryFromObject(obj)
10✔
254
            obj                 => innerBoundariesDict % objectForKey(key = "LIST")
10✔
255
            innerBoundariesList => linkedListFromObject(obj)
10✔
256

257
            CALL ConstructInnerBoundaries( self, INNER_BOUNDARY_BLOCK, innerBoundariesList )
10✔
258
            IF(ReturnOnFatalError())     RETURN
10✔
259

260
         END IF
261

262
         IF ( ASSOCIATED(self % innerBoundaries) )     THEN
22✔
263
            ALLOCATE(self % innerBoundariesIterator)
10✔
264
            CALL  self % innerBoundariesIterator % initWithFTLinkedList(self % innerboundaries)
10✔
265
         END IF
266
!
267
!        -----------------------------------
268
!        Import interface boundaries, if any
269
!        -----------------------------------
270
!
271
         IF ( modelDict% containsKey(key = INTERFACE_BOUNDARIES_BLOCK_KEY) )     THEN
22✔
272
            ALLOCATE( self % interfaceBoundaries )
1✔
273
            CALL self % interfaceBoundaries % init()
1✔
274

275
            obj                 => modelDict % objectForKey(key = INTERFACE_BOUNDARIES_BLOCK_KEY)
1✔
276
            innerBoundariesDict => valueDictionaryFromObject(obj)
1✔
277
            obj                 => innerBoundariesDict % objectForKey(key = "LIST")
1✔
278
            innerBoundariesList => linkedListFromObject(obj)
1✔
279

280
            CALL ConstructInnerBoundaries( self, INTERFACE_BOUNDARY_BLOCK,innerBoundariesList )
1✔
281
            IF(ReturnOnFatalError())     RETURN
1✔
282

283
         END IF
284

285
         IF ( ASSOCIATED(self % interfaceBoundaries) )     THEN
22✔
286
            ALLOCATE(self % interfaceBoundariesIterator)
1✔
287
            CALL  self % interfaceBoundariesIterator % initWithFTLinkedList(self % interfaceBoundaries)
1✔
288
         END IF
289
!
290
!        -----------------------------
291
!        Construct sweep curve, if any
292
!        -----------------------------
293
!
294
         IF ( modelDict % containsKey(key = SWEEP_CURVE_BLOCK_KEY) )     THEN
22✔
295

296
            ALLOCATE( self % sweepCurve )
1✔
297
            CALL self % sweepCurve % initChainWithNameAndID("Sweep curve",1)
1✔
298

299
            obj            => modelDict % objectForKey(key = SWEEP_CURVE_BLOCK_KEY)
1✔
300
            sweepCurveDict => valueDictionaryFromObject(obj)
1✔
301

302
            CALL AssembleChainCurve(self           = self,             &
303
                                    curveDict      = sweepCurveDict,   &
304
                                    curveChain     = self % sweepCurve,&
305
                                    innerOrOuter   = NOT_APPLICABLE,   &
306
                                    chainMustClose = .FALSE.)
1✔
307
            IF(ReturnOnFatalError())     RETURN
1✔
308

309
         END IF
310
!
311
!        -----------------------------
312
!        Construct scale curve, if any
313
!        -----------------------------
314
!
315
         IF ( modelDict % containsKey(key = SWEEP_SCALE_FACTOR_EQN_BLOCK_KEY) )     THEN
22✔
316

317
            ALLOCATE( self % scaleCurve )
1✔
318
            CALL self % scaleCurve % initChainWithNameAndID("Scale curve",1)
1✔
319

320
            obj            => modelDict % objectForKey(key = SWEEP_SCALE_FACTOR_EQN_BLOCK_KEY)
1✔
321
            scaleCurveDict => valueDictionaryFromObject(obj)
1✔
322

323
            CALL AssembleChainCurve(self           = self,             &
324
                                    curveDict      = scaleCurveDict,   &
325
                                    curveChain     = self % scaleCurve,&
326
                                    innerOrOuter   = NOT_APPLICABLE,   &
327
                                    chainMustClose = .FALSE.)
1✔
328
            IF(ReturnOnFatalError())     RETURN
1✔
329

330
         END IF
331
!
332
!        ------------------
333
!        Topography, if any
334
!        ------------------
335
!
336
         IF ( modelDict % containsKey(key = TOPOGRAPHY_BLOCK_KEY) )     THEN
22✔
337
            obj            => modelDict % objectForKey(key = TOPOGRAPHY_BLOCK_KEY)
4✔
338
            topographyDict => valueDictionaryFromObject(obj)
4✔
339
            CALL ConstructTopographyFromDict(self, topographyDict)
4✔
340
         END IF
341
!
342
!        ---------
343
!        Finish up
344
!        ---------
345
!
346
         CALL MakeCurveToChainConnections(self)
22✔
347
         CALL GatherAllChains(self)
22✔
348

349
      END SUBROUTINE constructModelFromDictionary
350
!
351
!////////////////////////////////////////////////////////////////////////
352
!
353
      SUBROUTINE ConstructOuterBoundary( self, outerBoundaryDict )
20✔
354
         IMPLICIT NONE
355
!
356
!        -----------
357
!        Arguments
358
!        -----------
359
!
360
         CLASS(SMModel)                    :: self
361
         CLASS(FTValueDictionary), POINTER :: outerBoundaryDict
362
!
363
!        ---------------
364
!        Local variables
365
!        ---------------
366
!
367
         CALL AssembleChainCurve(self           = self,                &
368
                                 curveDict      = outerBoundaryDict,   &
369
                                 curveChain     = self % outerBoundary,&
370
                                 innerOrOuter   = OUTER,               &
371
                                 chainMustClose = .TRUE.)
20✔
372

373
      END SUBROUTINE ConstructOuterBoundary
20✔
374
!
375
!////////////////////////////////////////////////////////////////////////
376
!
377
      SUBROUTINE AssembleChainCurve( self, curveDict, curveChain, innerOrOuter, chainMustClose )
22✔
378
         IMPLICIT NONE
379
!
380
!        -----------
381
!        Arguments
382
!        -----------
383
!
384
         CLASS(SMModel)                    :: self
385
         CLASS(FTValueDictionary), POINTER :: curveDict
386
         CLASS(SMChainedCurve)   , POINTER :: curveChain
387
         INTEGER                           :: innerOrOuter
388
         LOGICAL                           :: chainMustClose
389
!
390
!        ---------------
391
!        Local variables
392
!        ---------------
393
!
394
         CLASS(FTLinkedList)       , POINTER     :: curveList
395
         CLASS(FTObject)           , POINTER     :: obj
396
         CLASS(FTValueDictionary)  , POINTER     :: blockDict
397
         TYPE(FTLinkedListIterator)              :: iterator
22✔
398
!
399
!        ---------------------------------
400
!        Construct the curves in the chain
401
!        ---------------------------------
402
!
403
         obj       => curveDict % objectForKey(key = "LIST")
22✔
404
         curveList => linkedListFromObject(obj)
22✔
405
         CALL iterator % initWithFTLinkedList(list = curveList)
22✔
406

407
         DO WHILE (.NOT. iterator % isAtEnd())
63✔
408
            obj       => iterator % object()
41✔
409
            blockDict => valueDictionaryFromObject(obj)
41✔
410

411
            CALL ConstructCurve( self, curveChain, blockDict )
41✔
412

413
            CALL iterator % moveToNext()
41✔
414
         END DO
415
!
416
!        ------------------
417
!        Finalize the chain
418
!        ------------------
419
!
420
         CALL curveChain % complete(innerOrOuterCurve = innerOrOuter,chainMustClose = chainMustClose)
22✔
421
         CALL SetChainOptimizationParameters(curveChain, curveDict)
22✔
422

423
      END SUBROUTINE AssembleChainCurve
22✔
424
!
425
!////////////////////////////////////////////////////////////////////////
426
!
427
      SUBROUTINE ConstructInnerBoundaries( self, blockType, boundariesList )
11✔
428
         IMPLICIT NONE
429
!
430
!        ---------
431
!        Arguments
432
!        ---------
433
!
434
         CLASS(SMModel)               :: self
435
         INTEGER                      :: blockType
436
         CLASS(FTLinkedList), POINTER :: boundariesList
437
!
438
!        ---------------
439
!        Local variables
440
!        ---------------
441
!
442
         CLASS(FTLinkedListIterator), POINTER    :: innerBoundariesIterator, listOfCurvesIterator
443
         CLASS(FTValueDictionary)   , POINTER    :: chainDict, curveDict, ibDict
444
         CLASS(FTObject)            , POINTER    :: obj
445
         CLASS(FTLinkedList)        , POINTER    :: listOfCurves
446

447
         CLASS(SMChainedCurve), POINTER          :: chain => NULL()
448
         CHARACTER(LEN=BLOCK_NAME_STRING_LENGTH) :: chainName, ibType
449

450
         ALLOCATE(innerBoundariesIterator)
11✔
451
         CALL innerBoundariesIterator % initWithFTLinkedList(list = boundariesList)
11✔
452
         ALLOCATE(listOfCurvesIterator)
11✔
453
         CALL listOfCurvesIterator % init()
11✔
454

455
         CALL innerBoundariesIterator % setToStart()
11✔
456
         DO WHILE(.NOT. innerBoundariesIterator % isAtEnd())
46✔
457
!
458
!           ----------------------------------------------
459
!           Inner boundaries is a list of curves or chains
460
!           ----------------------------------------------
461
!
462
            obj    => innerBoundariesIterator % object()
35✔
463
            ibDict => valueDictionaryFromObject(obj)
35✔
464
            ibType = ibDict % stringValueForKey(key = "TYPE", &
465
                                                requestedLength = BLOCK_NAME_STRING_LENGTH)
35✔
466
            IF ( ibType /= "CHAIN" )     THEN ! Put the curve into a chain directly
35✔
467
!
468
!              -----------------------------------------------------------------------
469
!              The entry should be a single curve. Make the chain name the same as the
470
!              curve name
471
!              -----------------------------------------------------------------------
472
!
473
!
474
               chainName = ibDict % stringValueForKey(key = "name", &
475
                                                     requestedLength = BLOCK_NAME_STRING_LENGTH)
1✔
476
               ALLOCATE(chain)
1✔
477
               CALL chain % initChainWithNameAndID(chainName,0)
1✔
478
               CALL ConstructCurve(self, chain, ibDict )
1✔
479
               CALL SetChainOptimizationParameters(chain, ibDict)
1✔
480

481
            ELSE
482
               chainDict => ibDict !This is just an alias
34✔
483
               chainName = chainDict % stringValueForKey(key = "name", &
484
                                                         requestedLength = BLOCK_NAME_STRING_LENGTH)
34✔
485
               ALLOCATE(chain)
34✔
486
               CALL chain % initChainWithNameAndID(chainName,0)
34✔
487
!
488
!              -------------------------------
489
!              Chains contain a list of curves
490
!              -------------------------------
491
!
492
               obj          => chainDict % objectForKey(key = "LIST")
34✔
493
               listOfCurves => linkedListFromObject(obj)
34✔
494
               CALL listOfCurvesIterator % setLinkedList(list = listOfCurves)
34✔
495
               CALL listOfCurvesIterator % setToStart()
34✔
496

497
               DO WHILE( .NOT. listOfCurvesIterator % isAtEnd())
85✔
498
                  obj       => listOfCurvesIterator % object()
51✔
499
                  curveDict => valueDictionaryFromObject(obj)
51✔
500

501
                  CALL ConstructCurve(self, chain, curveDict )
51✔
502
                  CALL SetChainOptimizationParameters(chain, chainDict)
51✔
503

504
                  CALL listOfCurvesIterator % moveToNext()
51✔
505
               END DO
506

507
            END IF
508

509
            IF ( blockType == INNER_BOUNDARY_BLOCK )     THEN
35✔
510
              obj => chain
33✔
511
              CALL self % innerBoundaries % add(obj)
33✔
512
            ELSE
513
              obj => chain
2✔
514
              CALL self % interfaceBoundaries % add(obj)
2✔
515
            END IF
516
!
517
!           ------------------
518
!           Finalize the chain
519
!           ------------------
520
!
521
            CALL chain % complete(innerOrOuterCurve = INNER, chainMustClose = .TRUE.)
35✔
522
            obj => chain
35✔
523
            CALL release(obj)
35✔
524
!
525
!           --------------------------------------------------------
526
!           The chain has been created, clean up and then start over
527
!           --------------------------------------------------------
528
!
529
            IF ( blockType == INNER_BOUNDARY_BLOCK )     THEN
35✔
530
               self % numberOfInnerCurves     = self % numberOfInnerCurves + 1
33✔
531
            ELSE
532
               self % numberOfInterfaceCurves = self % numberOfInterfaceCurves + 1
2✔
533
            END IF
534

535
            CALL innerBoundariesIterator % moveToNext()
35✔
536
         END DO
537

538
         obj => innerBoundariesIterator
11✔
539
         CALL release(self = obj)
11✔
540
         obj => listOfCurvesIterator
11✔
541
         CALL release(self = obj)
11✔
542

543
      END SUBROUTINE ConstructInnerBoundaries
11✔
544
!
545
!////////////////////////////////////////////////////////////////////////
546
!
547
      SUBROUTINE SetChainOptimizationParameters(curveChain, curveDict)
74✔
548
         USE SMScannerClass
549
         IMPLICIT NONE
550
!
551
!        ---------
552
!        Arguments
553
!        ---------
554
!
555
         CLASS(FTValueDictionary), POINTER :: curveDict
556
         CLASS(SMChainedCurve)   , POINTER :: curveChain
557
!
558
!        ---------------
559
!        Local Variables
560
!        ---------------
561
!
562
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str
563
         INTEGER      , PARAMETER                :: DONT_SKIP = 0, SKIP = 1
564
         INTEGER                                 :: j
565

566
!
567
         curveChain % optimization = NONE
74✔
568
         IF ( curveDict % containsKey(CHAIN_OPTIMIZATION_KEY) )     THEN
74✔
NEW
569
            str = curveDict % stringValueForKey(CHAIN_OPTIMIZATION_KEY)
×
NEW
570
            SELECT CASE ( str )
×
571
               CASE( H1NORM_KEY )
NEW
572
                  curveChain % optimization = H1_NORM
×
573
               CASE( L2NORM_KEY )
NEW
574
                  curveChain % optimization = L2_NORM
×
575
               CASE DEFAULT
NEW
576
                  curveChain % optimization = NONE
×
577
            END SELECT
578
         END IF
579

580
         IF ( curveChain % optimization /= NONE )     THEN
74✔
581

NEW
582
            IF ( curveDict % containsKey(CHAIN_CONTINUITY_KEY) )     THEN
×
NEW
583
               curveChain % continuity = curveDict % integerValueForKey(CHAIN_CONTINUITY_KEY)
×
584
            ELSE
NEW
585
               curveChain % continuity = 0
×
586
               str = "Optimization continuity key not found in " // &
587
                      TRIM(curveDict % stringValueForKey("name")) // &
NEW
588
                      " Defaulting to 0"
×
589
               CALL ThrowErrorExceptionOfType(poster = "SetChainOptimizationParameters",&
590
                                              msg    = str, &
NEW
591
                                              typ    = FT_ERROR_WARNING)
×
592
            END IF
593

NEW
594
            IF ( curveDict % containsKey(CHAIN_TOLERANCE_KEY) )     THEN
×
NEW
595
               curveChain % tolerance = curveDict % realValueForKey(CHAIN_TOLERANCE_KEY)
×
596
            ELSE
NEW
597
               curveChain % tolerance = 1.0d-3
×
598
               str = "Optimization tolerance key not found in " // &
599
                      TRIM(curveDict % stringValueForKey("name")) // &
NEW
600
                     ". Defaulting to 1.0d-3."
×
601
               CALL ThrowErrorExceptionOfType(poster = "SetChainOptimizationParameters",&
602
                                              msg    = str, &
NEW
603
                                              typ    = FT_ERROR_WARNING)
×
604
            END IF
605

NEW
606
            IF ( curveDict % containsKey(CHAIN_BREAKS_KEY) )     THEN
×
607
!
608
!              -------------------------------------------------------------------------------
609
!              Chain breaks are defined by the end of the numbered curve in the chain, e.g.
610
!              with five curves in the chain, putting a break at the end of curve 2 and curve
611
!              3, write
612
!                 connect = 2-3
613
!              and to connect 2 & 3 and 4&5,
614
!                 connect = 2-3, 4-5
615
!              where the separator is a comma. (Spaces are ignored)
616
!              -------------------------------------------------------------------------------
617
!
NEW
618
               IF ( curveChain % COUNT() == 1 )     THEN ! No breaks if there is only one curve
×
NEW
619
                  curveChain % breaks = [0.0_RP, 1.0_RP]
×
620
               ELSE
NEW
621
                  str = curveDict % stringValueForKey(CHAIN_BREAKS_KEY)
×
NEW
622
                  CALL ScanForBreaks(str, curveChain % breaks, curveChain % COUNT() )
×
623
               END IF
624
            ELSE
NEW
625
               IF ( curveChain % COUNT() == 1 )     THEN ! No breaks if there is only one curve
×
NEW
626
                  curveChain % breaks = [0.0_RP, 1.0_RP]
×
627
               ELSE                                      ! Break all curves
NEW
628
                  ALLOCATE(curveChain % breaks(0:curveChain % COUNT()))
×
NEW
629
                  curveChain % breaks = [(REAL(j,RP)/REAL(curveChain % COUNT(), RP),j=0,curveChain % COUNT())]
×
630
               END IF
631
            END IF
632
         END IF
633

634
      END SUBROUTINE SetChainOptimizationParameters
74✔
635
!
636
!////////////////////////////////////////////////////////////////////////
637
!
638
      SUBROUTINE ConstructCurve( self, chain, curveDict )
93✔
639
         IMPLICIT NONE
640
!
641
!        ---------
642
!        Arguments
643
!        ---------
644
!
645
         CLASS(SMModel)                    :: self
646
         CLASS(SMChainedCurve)   , POINTER :: chain
647
         CLASS(FTValueDictionary), POINTER :: curveDict
648
!
649
!        ----------
650
!        Interfaces
651
!        ----------
652
!
653
         LOGICAL, EXTERNAL :: ReturnOnFatalError
654
!
655
!        ---------------
656
!        Local Variables
657
!        ---------------
658
!
659
         CHARACTER(LEN=BLOCK_NAME_STRING_LENGTH) :: curveType
660

661
         curveType = curveDict % stringValueForKey(key = "TYPE", &
662
                       requestedLength = BLOCK_NAME_STRING_LENGTH)
93✔
663
         SELECT CASE (curveType )
28✔
664

665
            CASE("PARAMETRIC_EQUATION_CURVE")
666

667
               CALL ConstructParametricEquationCurveFromDict( self, chain, curveDict )
28✔
668
               IF(ReturnOnFatalError())     RETURN
28✔
669

670
            CASE("PARAMETRIC_EQUATION")
671

672
               CALL ConstructParametricEquationFromDict( self, chain, curveDict )
1✔
673
               IF(ReturnOnFatalError())     RETURN
1✔
674

675
            CASE ("SPLINE_CURVE" )
676

677
               CALL ImportSplineBlock( self, chain, curveDict )
9✔
678

679
            CASE ("END_POINTS_LINE" )
680

681
               CALL ImportLineEquationBlock( self, chain, curveDict )
37✔
682

683
            CASE (CIRCULAR_ARC_CONTROL_KEY)
684

685
               CALL ImportCircularArcEquationBlock(self = self, chain = chain, circularArcBlockDict = curveDict)
14✔
686

687
            CASE (ELLIPTIC_ARC_CONTROL_KEY)
688

689
               CALL ImportEllipticArcEquationBlock(self = self, chain = chain, ellipticArcBlockDict = curveDict)
4✔
690

691
            CASE DEFAULT
692
               CALL ThrowErrorExceptionOfType(poster = "ConstructCurve",&
693
                                              msg    = "Unimplemented curve type "// TRIM(curveType) // " in model", &
694
                                              typ    = FT_ERROR_FATAL)
×
695
               RETURN
93✔
696
         END SELECT
697

698
         self % curveCount = self % curveCount + 1
93✔
699

700
      END SUBROUTINE ConstructCurve
74✔
701
!
702
!////////////////////////////////////////////////////////////////////////
703
!
704
      SUBROUTINE ConstructParametricEquationCurveFromDict( self, chain, curveDict )
28✔
705
         IMPLICIT NONE
706
!
707
!        ---------
708
!        Arguments
709
!        ---------
710
!
711
         CLASS(SMModel)                    :: self
712
         CLASS(SMChainedCurve)   , POINTER :: chain
713
         CLASS(FTValueDictionary), POINTER :: curveDict
714
!
715
!        ---------------
716
!        Local variables
717
!        ---------------
718
!
719
         CHARACTER(LEN=SM_CURVE_NAME_LENGTH)       :: curveName
720
         CHARACTER(LEN=EQUATION_STRING_LENGTH)     :: eqnX, eqnY, eqnZ
721
         CLASS(SMParametricEquationCurve), POINTER :: cCurve => NULL()
722
         CLASS(SMCurve)                  , POINTER :: curvePtr => NULL()
723
         CLASS(FTObject)                 , POINTER :: obj
724
!
725
!        ----------
726
!        Interfaces
727
!        ----------
728
!
729
         LOGICAL :: returnOnFatalError
730
!
731
!        ------------
732
!        Get the data
733
!        ------------
734
!
735
         IF ( curveDict % containsKey(key = "name") )     THEN
28✔
736
            curveName = curveDict % stringValueForKey(key = "name", &
737
                                                      requestedLength = SM_CURVE_NAME_LENGTH)
28✔
738
         ELSE
739
            curveName = "curve"
×
740
            CALL ThrowErrorExceptionOfType(poster = "ConstructParametricEquationCurveFromDict",&
741
                                           msg = "PARAMETRIC_EQUATION_CURVE has no name. Use default 'curve'", &
742
                                           typ = FT_ERROR_WARNING)
×
743
         END IF
744

745
         IF ( curveDict % containsKey(key = "xEqn") )     THEN
28✔
746
            eqnX = curveDict % stringValueForKey(key = "xEqn", &
747
                                                      requestedLength = DEFAULT_CHARACTER_LENGTH)
28✔
748
         ELSE
749
            CALL ThrowErrorExceptionOfType(poster = "ConstructParametricEquationCurveFromDict",&
750
                                           msg = "PARAMETRIC_EQUATION_CURVE has no xEqn.", &
751
                                           typ = FT_ERROR_FATAL)
×
752
            RETURN
×
753
         END IF
754

755
         IF ( curveDict % containsKey(key = "yEqn") )     THEN
28✔
756
            eqnY = curveDict % stringValueForKey(key = "yEqn", &
757
                                                      requestedLength = DEFAULT_CHARACTER_LENGTH)
28✔
758
         ELSE
759
            CALL ThrowErrorExceptionOfType(poster = "ConstructParametricEquationCurveFromDict",&
760
                                           msg = "PARAMETRIC_EQUATION_CURVE has no yEqn.", &
761
                                           typ = FT_ERROR_FATAL)
×
762
            RETURN
×
763
         END IF
764

765
         IF ( curveDict % containsKey(key = "zEqn") )     THEN
28✔
766
            eqnZ = curveDict % stringValueForKey(key = "zEqn", &
767
                                                      requestedLength = DEFAULT_CHARACTER_LENGTH)
28✔
768
         ELSE
769
            CALL ThrowErrorExceptionOfType(poster = "ConstructParametricEquationCurveFromDict",&
770
                                           msg = "PARAMETRIC_EQUATION_CURVE has no zEqn. Default is z = 0", &
771
                                           typ = FT_ERROR_WARNING)
×
772
            eqnZ = "z(t) = 0.0"
×
773
         END IF
774
!
775
!        ----------------
776
!        Create the curve
777
!        ----------------
778
!
779
         ALLOCATE(cCurve)
28✔
780
         CALL cCurve % initWithEquationsNameAndID(eqnX, eqnY, eqnZ, curveName, self % curveCount + 1)
28✔
781
         IF(ReturnOnFatalError())     RETURN
28✔
782

783
         curvePtr => cCurve
28✔
784
         CALL chain  % addCurve(curvePtr)
28✔
785
         obj => cCurve
28✔
786
         CALL release(obj)
28✔
787

788
      END SUBROUTINE ConstructParametricEquationCurveFromDict
789
!
790
!////////////////////////////////////////////////////////////////////////
791
!
792
      SUBROUTINE ConstructParametricEquationFromDict( self, chain, curveDict )
1✔
793
         IMPLICIT NONE
794
!
795
!        ---------
796
!        Arguments
797
!        ---------
798
!
799
         CLASS(SMModel)                    :: self
800
         CLASS(SMChainedCurve)   , POINTER :: chain
801
         CLASS(FTValueDictionary), POINTER :: curveDict
802
!
803
!        ---------------
804
!        Local variables
805
!        ---------------
806
!
807
         CHARACTER(LEN=SM_CURVE_NAME_LENGTH)       :: curveName
808
         CHARACTER(LEN=EQUATION_STRING_LENGTH)     :: eqnX, eqnY, eqnZ
809
         CLASS(SMParametricEquationCurve), POINTER :: cCurve => NULL()
810
         CLASS(SMCurve)                  , POINTER :: curvePtr => NULL()
811
         CLASS(FTObject)                 , POINTER :: obj
812
!
813
!        ----------
814
!        Interfaces
815
!        ----------
816
!
817
         LOGICAL :: returnOnFatalError
818
!
819
!        ------------
820
!        Get the data
821
!        ------------
822
!
823
         IF ( curveDict % containsKey(key = "eqn") )     THEN
1✔
824
            eqnX = curveDict % stringValueForKey(key = "eqn", &
825
                                                      requestedLength = DEFAULT_CHARACTER_LENGTH)
1✔
826
         ELSE
827
            CALL ThrowErrorExceptionOfType(poster = "ConstructParametricEquationFromDict",&
828
                                           msg = "PARAMETRIC_EQUATION has no eqn key.", &
829
                                           typ = FT_ERROR_FATAL)
×
830
            RETURN
×
831
         END IF
832
!
833
!        ------------------------------------------------------------------
834
!        For just a parametric equation, the other equations are irrelevant
835
!        ------------------------------------------------------------------
836
!
837
         eqnY = "y(t) = 0.0"
1✔
838
         eqnZ = "z(t) = 0.0"
1✔
839
!
840
!        ----------------
841
!        Create the curve
842
!        ----------------
843
!
844
         ALLOCATE(cCurve)
1✔
845
         CALL cCurve % initWithEquationsNameAndID(eqnX, eqnY, eqnZ, curveName, self % curveCount + 1)
1✔
846
         IF(ReturnOnFatalError())     RETURN
1✔
847

848
         curvePtr => cCurve
1✔
849
         CALL chain  % addCurve(curvePtr)
1✔
850
         obj => cCurve
1✔
851
         CALL release(obj)
1✔
852

853
      END SUBROUTINE ConstructParametricEquationFromDict
854
!
855
!////////////////////////////////////////////////////////////////////////
856
!
857
      SUBROUTINE ConstructTopographyFromDict(self, dict)
4✔
858
         IMPLICIT NONE
859
!
860
!        -----------
861
!        Arguments
862
!        -----------
863
!
864
         CLASS(SMModel)                            :: self
865
         CLASS(FTValueDictionary), POINTER         :: dict
866
!
867
!        ---------------
868
!        Local variables
869
!        ---------------
870
!
871
         CHARACTER(LEN = EQUATION_STRING_LENGTH)   :: eqn
872
         CLASS(SMEquationTopography), POINTER      :: topog
873
         CHARACTER(LEN = DEFAULT_FILE_PATH_LENGTH) :: topog_file
874
         CLASS(SMTopographyFromFile), POINTER      :: topog_data
875
         LOGICAL                                   :: sizingIsON
876
         CHARACTER(LEN=3)                          :: sizing
877
!
878
!        ----------
879
!        Interfaces
880
!        ----------
881
!
882
         LOGICAL :: returnOnFatalError
883
!
884
!        --------------------------------------
885
!        Detect the type of topology definition
886
!        --------------------------------------
887
!
888
         IF ( dict % containsKey(TOPOGRAPHY_EQUATION_KEY) )     THEN
4✔
889
            IF ( .NOT.dict % containsKey(key = TOPOGRAPHY_EQUATION_KEY) )     THEN
2✔
890
               CALL ThrowErrorExceptionOfType(poster = "ConstructTopographyFromDict",&
891
                                              msg = "TOPOGRAPHY has no eqn key.", &
892
                                              typ = FT_ERROR_FATAL)
×
893
               RETURN
×
894
            END IF
895

896
            eqn = dict % stringValueForKey(key             = TOPOGRAPHY_EQUATION_KEY, &
897
                                           requestedLength = EQUATION_STRING_LENGTH)
2✔
898
            ALLOCATE(topog)
2✔
899
            CALL topog % initWithEquation(zEqn = eqn)
2✔
900
            IF(ReturnOnFatalError())     RETURN
2✔
901
            self % topography => topog
2✔
902

903
         ELSEIF ( dict % containsKey(TOPOGRAPHY_FROM_FILE_KEY) )     THEN
2✔
904

905
            topog_file = dict % stringValueForKey(key             = TOPOGRAPHY_FROM_FILE_KEY, &
906
                                                  requestedLength = DEFAULT_FILE_PATH_LENGTH)
2✔
907
            sizingIsON = .FALSE.
2✔
908
            IF ( dict % containsKey(key = SIZING_KEY) )     THEN
2✔
909
               sizing = dict % stringValueForKey(key = SIZING_KEY, requestedLength = 3)
1✔
910
               IF ( sizing == "ON " )     THEN
1✔
911
                  sizingIsON = .TRUE.
1✔
912
               END IF
913
            END IF
914

915
            ALLOCATE(topog_data)
2✔
916
            CALL topog_data % initWithDataFile(topog_file, sizingIsON)
2✔
917
            IF(ReturnOnFatalError())     RETURN
2✔
918
            self % topography => topog_data
2✔
919

920
         ELSE !TODO TOPOGRAPHY: ADD TEST AND CONSTRUCTION OF ALTERNATE TOPOGRAPHIES HERE
921
            PRINT *, "Unknown topography definition. Ignoring."
×
922
         END IF
923

924
      END SUBROUTINE ConstructTopographyFromDict
925
!
926
!////////////////////////////////////////////////////////////////////////
927
!
928
      SUBROUTINE ImportSplineBlock( self, chain, splineDict )
9✔
929
         USE ValueSettingModule
930
         USE FTDataClass
931
         USE EncoderModule
932
         IMPLICIT NONE
933
!
934
!        ---------
935
!        Arguments
936
!        ---------
937
!
938
         CLASS(SMModel)                    :: self
939
         CLASS(FTValueDictionary), POINTER :: splineDict
940
         CLASS(SMChainedCurve)   , POINTER :: chain
941
!
942
!        ----------
943
!        Interfaces
944
!        ----------
945
!
946
         LOGICAL, EXTERNAL :: ReturnOnFatalError
947
!
948
!        ---------------
949
!        Local variables
950
!        ---------------
951
!
952
         CLASS(FTObject) , POINTER                  :: obj
953
         CLASS(FTData)   , POINTER                  :: splineData
954
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH)    :: curveName
955
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH)    :: curveFile
956
         CHARACTER(LEN=1), POINTER                  :: encodedData(:)
957
         REAL(KIND=RP), ALLOCATABLE                 :: decodedArray(:,:)
9✔
958
         CLASS(SMSplineCurve)             , POINTER :: cCurve      => NULL()
959
         CLASS(SMCurve)                   , POINTER :: curvePtr    => NULL()
960
         INTEGER                                    :: numKnots
961

962
         INTEGER, EXTERNAL :: GetIntValue
963
         LOGICAL :: curveFileFound
964
!
965
!        ------------
966
!        Get the data
967
!        ------------
968
!
969
         curveName = "spline"
9✔
970
         CALL SetStringValueFromDictionary(valueToSet = curveName,                 &
971
                                           sourceDict = splineDict,                &
972
                                           key = "name",                           &
973
                                           errorLevel = FT_ERROR_WARNING,          &
974
                                           message = "spline block has no name. Using default name spline", &
975
                                           poster = "ImportSplineBlock")
9✔
976

977
         IF( splineDict % containsKey(SPLINE_FILE_KEY) )THEN
9✔
978

979
            curveFile = splineDict % stringValueforKey( key = SPLINE_FILE_KEY, &
980
                                                        requestedLength = DEFAULT_CHARACTER_LENGTH )
1✔
981

982
            INQUIRE( FILE=TRIM(curveFile), EXIST=curveFileFound )
1✔
983

984
            IF(.NOT. curveFileFound)     THEN
1✔
985
               CALL ThrowErrorExceptionOfType(poster = "ImportSplineBlock", &
986
                                              msg    = "Spline curve file not found",&
987
                                              typ    = FT_ERROR_FATAL)
×
988
               RETURN
×
989
            END IF
990

991
            ALLOCATE(cCurve)
1✔
992
            CALL cCurve % initWithDataFile( TRIM(curveFile), curveName, self % curveCount + 1 )
1✔
993
            IF(ReturnOnFatalError()) RETURN
1✔
994

995
            curvePtr => cCurve
1✔
996
            CALL chain  % addCurve(curvePtr)
1✔
997
            obj => cCurve
1✔
998
            CALL release(obj)
1✔
999

1000
!
1001
         ELSE
1002

1003
            CALL SetIntegerValueFromDictionary(valueToSet = numKnots,             &
1004
                                               sourceDict = splineDict,           &
1005
                                               key = "nKnots",                    &
1006
                                               errorLevel = FT_ERROR_FATAL,       &
1007
                                               message = "nKnots keyword not found in spline definition", &
1008
                                               poster = "ImportSplineBlock")
8✔
1009
            IF(ReturnOnFatalError()) RETURN
8✔
1010
!
1011
!           ---------------------
1012
!           Get the spline points
1013
!           ---------------------
1014
!
1015
            obj         => splineDict % objectForKey(key = "data")
8✔
1016
            splineData  => dataFromObject(obj)
8✔
1017
            encodedData => splineData % storedData()
8✔
1018

1019
            IF(.NOT. ASSOCIATED(encodedData))     THEN
8✔
1020
               CALL ThrowErrorExceptionOfType(poster = "ImportSplineBlock", &
1021
                                              msg    = "Spline does not appear to contain any data",&
1022
                                              typ    = FT_ERROR_FATAL)
×
1023
               RETURN
×
1024
            END IF
1025

1026
            CALL DECODE(enc = encodedData, N = 4, M = numKnots, arrayOut = decodedArray)
8✔
1027
!
1028
!           ----------------
1029
!           Create the curve
1030
!           ----------------
1031
!
1032
            ALLOCATE(cCurve)
8✔
1033
            CALL cCurve % initWithPointsNameAndID(decodedArray(1,:), decodedArray(2,:), &
1034
                                                  decodedArray(3,:), decodedArray(4,:), &
1035
                                                  curveName, self % curveCount + 1 )
8✔
1036
            IF(ReturnOnFatalError()) RETURN
8✔
1037
            curvePtr => cCurve
8✔
1038
            CALL chain  % addCurve(curvePtr)
8✔
1039
            obj => cCurve
8✔
1040
            CALL release(obj)
8✔
1041

1042
         ENDIF
1043

1044
      END SUBROUTINE ImportSplineBlock
18✔
1045
!
1046
!////////////////////////////////////////////////////////////////////////
1047
!
1048
      SUBROUTINE ImportLineEquationBlock( self, chain, lineBlockDict)
37✔
1049
         IMPLICIT NONE
1050
!
1051
!        ---------
1052
!        Arguments
1053
!        ---------
1054
!
1055
         CLASS(SMModel)                    :: self
1056
         CLASS(SMChainedCurve)   , POINTER :: chain
1057
         CLASS(FTValueDictionary), POINTER :: lineBlockDict
1058
!
1059
!        ---------------
1060
!        Local variables
1061
!        ---------------
1062
!
1063
         CHARACTER(LEN=LINE_LENGTH)            :: inputLine = " "
1064
         CHARACTER(LEN=SM_CURVE_NAME_LENGTH)   :: curveName
1065
         REAL(KIND=RP), DIMENSION(3)           :: xStart, xEnd
1066
         CLASS(SMLine)          , POINTER      :: cCurve => NULL()
1067
         CLASS(SMCurve)         , POINTER      :: curvePtr => NULL()
1068
         CLASS(FTObject)        , POINTER      :: obj
1069
!
1070
!        ------------------------------------------------
1071
         INTERFACE
1072
            FUNCTION GetRealArray( inputLine ) RESULT(x)
1073
               USE SMConstants
1074
               IMPLICIT NONE
1075
               REAL(KIND=RP), DIMENSION(3) :: x
1076
               CHARACTER ( LEN = * ) :: inputLine
1077
            END FUNCTION GetRealArray
1078
         END INTERFACE
1079
!        ________________________________________________
1080
!
1081
!        ------------
1082
!        Get the data
1083
!        ------------
1084
!
1085
         IF( lineBlockDict % containsKey(key = 'name') )     THEN
37✔
1086
            curveName = lineBlockDict % stringValueForKey(key             = "name", &
1087
                                                          requestedLength = SM_CURVE_NAME_LENGTH)
37✔
1088
         ELSE
1089
            curveName = "line"
×
1090
            CALL ThrowErrorExceptionOfType(poster = "ImportLineEquationBlock",&
1091
                                           msg = "No name found in line curve definition. Using 'line' as default", &
1092
                                           typ = FT_ERROR_WARNING)
×
1093

1094
         END IF
1095

1096
         IF( lineBlockDict % containsKey(key = 'xStart') )     THEN
37✔
1097
            inputLine = lineBlockDict % stringValueForKey(key             = "xStart", &
1098
                                                          requestedLength = LINE_LENGTH)
37✔
1099
            xStart = GetRealArray(inputLine)
37✔
1100
         ELSE
1101
            CALL ThrowErrorExceptionOfType(poster = "ImportLineEquationBlock",&
1102
                                           msg = "No xStart in line curve definition.", &
1103
                                           typ = FT_ERROR_FATAL)
×
1104
            RETURN
×
1105
         END IF
1106

1107
         IF( lineBlockDict % containsKey(key = 'xEnd') )     THEN
37✔
1108
            inputLine = lineBlockDict % stringValueForKey(key             = "xEnd", &
1109
                                                          requestedLength = LINE_LENGTH)
37✔
1110
            xEnd = GetRealArray(inputLine)
37✔
1111
         ELSE
1112
            CALL ThrowErrorExceptionOfType(poster = "ImportLineEquationBlock",&
1113
                                           msg = "No xEnd in line curve definition.", &
1114
                                           typ = FT_ERROR_FATAL)
×
1115
            RETURN
×
1116
         END IF
1117
!
1118
!        ----------------
1119
!        Create the curve
1120
!        ----------------
1121
!
1122
         ALLOCATE(cCurve)
37✔
1123
         CALL cCurve % initWithStartEndNameAndID( xStart, xEnd, curveName, self % curveCount + 1 )
37✔
1124
         !SMLine does not throw exceptions on init
1125

1126
         curvePtr => cCurve
37✔
1127
         CALL chain  % addCurve(curvePtr)
37✔
1128
         obj => cCurve
37✔
1129
         CALL release(obj)
37✔
1130

1131
      END SUBROUTINE ImportLineEquationBlock
9✔
1132
!
1133
!////////////////////////////////////////////////////////////////////////
1134
!
1135
      SUBROUTINE ImportCircularArcEquationBlock( self, chain, circularArcBlockDict )
14✔
1136
         IMPLICIT NONE
1137
!
1138
!        ---------
1139
!        Arguments
1140
!        ---------
1141
!
1142
         CLASS(SMModel)                    :: self
1143
         CLASS(SMChainedCurve)   , POINTER :: chain
1144
         CLASS(FTValueDictionary), POINTER :: circularArcBlockDict
1145
!
1146
!        ---------------
1147
!        Local variables
1148
!        ---------------
1149
!
1150
         CHARACTER(LEN=LINE_LENGTH)            :: inputLine = " "
1151
         CHARACTER(LEN=SM_CURVE_NAME_LENGTH)   :: curveName
1152
         CHARACTER(LEN=LINE_LENGTH)            :: units
1153
         REAL(KIND=RP), DIMENSION(3)           :: center
1154
         REAL(KIND=RP)                         :: radius, startAngle, endAngle
1155
         CLASS(SMEllipticArc)   , POINTER      :: cCurve => NULL()
1156
         CLASS(SMCurve)         , POINTER      :: curvePtr => NULL()
1157
         CLASS(FTObject)        , POINTER      :: obj
1158
!
1159
!        ------------------------------------------------
1160
         INTERFACE
1161
            FUNCTION GetRealArray( inputLine ) RESULT(x)
1162
               USE SMConstants
1163
               IMPLICIT NONE
1164
               REAL(KIND=RP), DIMENSION(3) :: x
1165
               CHARACTER ( LEN = * ) :: inputLine
1166
            END FUNCTION GetRealArray
1167
         END INTERFACE
1168
!        ________________________________________________
1169
!
1170
         REAL(KIND=RP), EXTERNAL :: getRealValue
1171
!
1172
!        ------------
1173
!        Get the data
1174
!        ------------
1175
!
1176
         IF( circularArcBlockDict % containsKey(key = 'name') )     THEN
14✔
1177
            curveName = circularArcBlockDict % stringValueForKey(key             = "name", &
1178
                                                          requestedLength = SM_CURVE_NAME_LENGTH)
14✔
1179
         ELSE
1180
            curveName = "circularArc"
×
1181
            CALL ThrowErrorExceptionOfType(poster = "ImportCircularArcEquationBlock",&
1182
                                           msg = "No name found in circular arc curve definition. Using 'circularArc' as default", &
1183
                                           typ = FT_ERROR_WARNING)
×
1184

1185
         END IF
1186
!
1187
!        -----------
1188
!        Start Angle
1189
!        -----------
1190
!
1191
         IF( circularArcBlockDict % containsKey(key = CIRCULAR_ARC_START_ANGLE_KEY) )     THEN
14✔
1192
            inputLine = circularArcBlockDict % stringValueForKey(key              = CIRCULAR_ARC_START_ANGLE_KEY, &
1193
                                                          requestedLength = LINE_LENGTH)
14✔
1194
            startAngle = getRealValue(inputLine)
14✔
1195
         ELSE
1196
            CALL ThrowErrorExceptionOfType(poster = "ImportCircularArcEquationBlock",&
1197
                                           msg    = "No start angle in circular arc curve definition.", &
1198
                                           typ    = FT_ERROR_FATAL)
×
1199
            RETURN
×
1200
         END IF
1201
!
1202
!        ---------
1203
!        End Angle
1204
!        ---------
1205
!
1206
         IF( circularArcBlockDict % containsKey(key = CIRCULAR_ARC_END_ANGLE_KEY) )     THEN
14✔
1207
            inputLine = circularArcBlockDict % stringValueForKey(key              = CIRCULAR_ARC_END_ANGLE_KEY, &
1208
                                                          requestedLength = LINE_LENGTH)
14✔
1209
            endAngle = getRealValue(inputLine)
14✔
1210
         ELSE
1211
            CALL ThrowErrorExceptionOfType(poster = "ImportCircularArcEquationBlock",&
1212
                                           msg    = "No end angle in circular arc curve definition.", &
1213
                                           typ    = FT_ERROR_FATAL)
×
1214
            RETURN
×
1215
         END IF
1216
!
1217
!        -----------
1218
!        Angle Units
1219
!        -----------
1220
!
1221
         units = "radians"
14✔
1222
         IF( circularArcBlockDict % containsKey(key = CIRCULAR_ARC_UNITS_KEY) )     THEN
14✔
1223
            units = circularArcBlockDict % stringValueForKey(key              = CIRCULAR_ARC_UNITS_KEY, &
1224
                                                          requestedLength = LINE_LENGTH)
14✔
1225
         END IF
1226
!
1227
!        ------
1228
!        Radius
1229
!        ------
1230
!
1231
         IF( circularArcBlockDict % containsKey(key = CIRCULAR_ARC_RADIUS_KEY) )     THEN
14✔
1232
            inputLine = circularArcBlockDict % stringValueForKey(key              = CIRCULAR_ARC_RADIUS_KEY, &
1233
                                                          requestedLength = LINE_LENGTH)
14✔
1234
            radius = getRealValue(inputLine)
14✔
1235
         ELSE
1236
            CALL ThrowErrorExceptionOfType(poster = "ImportCircularArcEquationBlock",&
1237
                                           msg    = "No radius in circular arc curve definition.", &
1238
                                           typ    = FT_ERROR_FATAL)
×
1239
            RETURN
×
1240
         END IF
1241
!
1242
!        ------
1243
!        Center
1244
!        ------
1245
!
1246
         IF( circularArcBlockDict % containsKey(key = CIRCULAR_ARC_CENTER_KEY) )     THEN
14✔
1247
            inputLine = circularArcBlockDict % stringValueForKey(key              = CIRCULAR_ARC_CENTER_KEY, &
1248
                                                          requestedLength = LINE_LENGTH)
14✔
1249
            center = GetRealArray(inputLine)
14✔
1250
         ELSE
1251
            CALL ThrowErrorExceptionOfType(poster = "ImportCircularArcEquationBlock",&
1252
                                           msg    = "No center in circular arc curve definition.", &
1253
                                           typ    = FT_ERROR_FATAL)
×
1254
            RETURN
×
1255
         END IF
1256
!
1257
!        ----------------
1258
!        Create the curve
1259
!        ----------------
1260
!
1261
         IF ( units == "degrees" )     THEN
14✔
1262
            startAngle = startAngle*DEGREES_TO_RADIANS
14✔
1263
            endAngle   = endAngle  *DEGREES_TO_RADIANS
14✔
1264
         END IF
1265

1266
         ALLOCATE(cCurve)
14✔
1267
         CALL cCurve % initWithParametersNameAndID(center     = center,        &
1268
                                                   radius     = radius,        &
1269
                                                   startAngle = startAngle,    &
1270
                                                   endAngle   = endAngle,      &
1271
                                                   cName      = curveName,     &
1272
                                                   id = self % curveCount + 1)
14✔
1273

1274
         !SMCircularArc does not throw exceptions on init
1275

1276
         curvePtr => cCurve
14✔
1277
         CALL chain  % addCurve(curvePtr)
14✔
1278
         obj => cCurve
14✔
1279
         CALL release(obj)
14✔
1280

1281
      END SUBROUTINE ImportCircularArcEquationBlock
1282
!
1283
!////////////////////////////////////////////////////////////////////////
1284
!
1285
      SUBROUTINE ImportEllipticArcEquationBlock( self, chain, ellipticArcBlockDict )
4✔
1286
         IMPLICIT NONE
1287
!
1288
!        ---------
1289
!        Arguments
1290
!        ---------
1291
!
1292
         CLASS(SMModel)                    :: self
1293
         CLASS(SMChainedCurve)   , POINTER :: chain
1294
         CLASS(FTValueDictionary), POINTER :: ellipticArcBlockDict
1295
!
1296
!        ---------------
1297
!        Local variables
1298
!        ---------------
1299
!
1300
         CHARACTER(LEN=LINE_LENGTH)            :: inputLine = " "
1301
         CHARACTER(LEN=SM_CURVE_NAME_LENGTH)   :: curveName
1302
         CHARACTER(LEN=LINE_LENGTH)            :: units
1303
         REAL(KIND=RP), DIMENSION(3)           :: center
1304
         REAL(KIND=RP)                         :: xRadius, yRadius, startAngle, endAngle, rotation
1305
         CLASS(SMEllipticArc)   , POINTER      :: cCurve => NULL()
1306
         CLASS(SMCurve)         , POINTER      :: curvePtr => NULL()
1307
         CLASS(FTObject)        , POINTER      :: obj
1308
!
1309
!        ------------------------------------------------
1310
         INTERFACE
1311
            FUNCTION GetRealArray( inputLine ) RESULT(x)
1312
               USE SMConstants
1313
               IMPLICIT NONE
1314
               REAL(KIND=RP), DIMENSION(3) :: x
1315
               CHARACTER ( LEN = * ) :: inputLine
1316
            END FUNCTION GetRealArray
1317
         END INTERFACE
1318
!        ________________________________________________
1319
!
1320
         REAL(KIND=RP), EXTERNAL :: getRealValue
1321
!
1322
!        ------------
1323
!        Get the data
1324
!        ------------
1325
!
1326
         IF( ellipticArcBlockDict % containsKey(key = 'name') )     THEN
4✔
1327
            curveName = ellipticArcBlockDict % stringValueForKey(key             = "name", &
1328
                                                          requestedLength = SM_CURVE_NAME_LENGTH)
4✔
1329
         ELSE
1330
            curveName = "ellipticArc"
×
1331
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1332
                                           msg = "No name found in elliptic arc curve definition. Using 'ellipticArc' as default", &
1333
                                           typ = FT_ERROR_WARNING)
×
1334

1335
         END IF
1336
!
1337
!        -----------
1338
!        Start Angle
1339
!        -----------
1340
!
1341
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_START_ANGLE_KEY) )     THEN
4✔
1342
            inputLine = ellipticArcBlockDict % stringValueForKey(key              = ELLIPTIC_ARC_START_ANGLE_KEY, &
1343
                                                          requestedLength = LINE_LENGTH)
4✔
1344
            startAngle = getRealValue(inputLine)
4✔
1345
         ELSE
1346
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1347
                                           msg    = "No start angle in elliptic arc curve definition.", &
1348
                                           typ    = FT_ERROR_FATAL)
×
1349
            RETURN
×
1350
         END IF
1351
!
1352
!        ---------
1353
!        End Angle
1354
!        ---------
1355
!
1356
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_END_ANGLE_KEY) )     THEN
4✔
1357
            inputLine = ellipticArcBlockDict % stringValueForKey(key              = ELLIPTIC_ARC_END_ANGLE_KEY, &
1358
                                                          requestedLength = LINE_LENGTH)
4✔
1359
            endAngle = getRealValue(inputLine)
4✔
1360
         ELSE
1361
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1362
                                           msg    = "No end angle in elliptic arc curve definition.", &
1363
                                           typ    = FT_ERROR_FATAL)
×
1364
            RETURN
×
1365
         END IF
1366
!
1367
!        -----------
1368
!        Angle Units
1369
!        -----------
1370
!
1371
         units = "radians"
4✔
1372
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_UNITS_KEY) )     THEN
4✔
1373
            units = ellipticArcBlockDict % stringValueForKey(key              = ELLIPTIC_ARC_UNITS_KEY, &
1374
                                                          requestedLength = LINE_LENGTH)
4✔
1375
         END IF
1376
!
1377
!        -------
1378
!        xRadius
1379
!        -------
1380
!
1381
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_X_RADIUS_KEY) )     THEN
4✔
1382
            inputLine = ellipticArcBlockDict % stringValueForKey(key              = ELLIPTIC_ARC_X_RADIUS_KEY, &
1383
                                                          requestedLength = LINE_LENGTH)
4✔
1384
            xRadius = getRealValue(inputLine)
4✔
1385
         ELSE
1386
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1387
                                           msg    = "No xRadius in elliptic arc curve definition.", &
1388
                                           typ    = FT_ERROR_FATAL)
×
1389
            RETURN
×
1390
         END IF
1391
!
1392
!        -------
1393
!        yRadius
1394
!        -------
1395
!
1396
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_Y_RADIUS_KEY) )     THEN
4✔
1397
            inputLine = ellipticArcBlockDict % stringValueForKey(key              = ELLIPTIC_ARC_Y_RADIUS_KEY, &
1398
                                                          requestedLength = LINE_LENGTH)
4✔
1399
            yRadius = getRealValue(inputLine)
4✔
1400
         ELSE
1401
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1402
                                           msg    = "No yRadius in elliptic arc curve definition.", &
1403
                                           typ    = FT_ERROR_FATAL)
×
1404
            RETURN
×
1405
         END IF
1406
!
1407
!        ------
1408
!        Center
1409
!        ------
1410
!
1411
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_CENTER_KEY) )     THEN
4✔
1412
            inputLine = ellipticArcBlockDict % stringValueForKey(key              = ELLIPTIC_ARC_CENTER_KEY, &
1413
                                                          requestedLength = LINE_LENGTH)
4✔
1414
            center = GetRealArray(inputLine)
4✔
1415
         ELSE
1416
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1417
                                           msg    = "No center in elliptic arc curve definition.", &
1418
                                           typ    = FT_ERROR_FATAL)
×
1419
            RETURN
×
1420
         END IF
1421
!
1422
!        --------
1423
!        rotation
1424
!        --------
1425
!
1426
         IF( ellipticArcBlockDict % containsKey(key = ELLIPTIC_ARC_ROTATION_KEY) )     THEN
4✔
1427
            inputLine = ellipticArcBlockDict % stringValueForKey(key             = ELLIPTIC_ARC_ROTATION_KEY, &
1428
                                                          requestedLength = LINE_LENGTH)
4✔
1429
            rotation =  getRealValue(inputLine)
4✔
1430
         ELSE
1431
            rotation = 0.0_RP
×
1432
            CALL ThrowErrorExceptionOfType(poster = "ImportEllipticArcEquationBlock",&
1433
                                           msg = "No rotation found in elliptic arc curve definition. Setting rotation=0.0", &
1434
                                           typ = FT_ERROR_WARNING)
×
1435

1436
         END IF
1437
!
1438
!        ----------------
1439
!        Create the curve
1440
!        ----------------
1441
!
1442
         IF ( units == "degrees" )     THEN
4✔
1443
            startAngle = startAngle*DEGREES_TO_RADIANS
3✔
1444
            endAngle   = endAngle  *DEGREES_TO_RADIANS
3✔
1445
            rotation   = rotation  *DEGREES_TO_RADIANS
3✔
1446
         END IF
1447

1448
         ALLOCATE(cCurve)
4✔
1449
         CALL cCurve % initWithParametersNameAndID(center     = center,        &
1450
                                                   xRadius    = xRadius,       &
1451
                                                   yRadius    = yRadius,       &
1452
                                                   startAngle = startAngle,    &
1453
                                                   endAngle   = endAngle,      &
1454
                                                   rotation   = rotation,      &
1455
                                                   cName      = curveName,     &
1456
                                                   id = self % curveCount + 1)
4✔
1457

1458
         !SMEllipticArc does not throw exceptions on init
1459

1460
         curvePtr => cCurve
4✔
1461
         CALL chain  % addCurve(curvePtr)
4✔
1462
         obj => cCurve
4✔
1463
         CALL release(obj)
4✔
1464

1465
      END SUBROUTINE ImportEllipticArcEquationBlock
1466
!
1467
!///////////////////////////////////////////////////////////////////////
1468
!
1469
!     ----------------------------------------------------------------
1470
!!    Extracts the string within the parentheses  in an input file
1471
!     ----------------------------------------------------------------
1472
!
1473
      CHARACTER( LEN=LINE_LENGTH ) FUNCTION GetStringValue( inputLine )
×
1474
!
1475
      CHARACTER ( LEN = * ) :: inputLine
1476
      INTEGER               :: cStart, cEnd
1477
!
1478
      cStart = INDEX(inputLine,'"')
×
1479
      cEnd   = INDEX(inputLine, '"', .true. )
×
1480
      GetStringValue = inputLine( cStart+1: cEnd-1 )
×
1481
!
1482
      END FUNCTION GetStringValue
×
1483
!
1484
!////////////////////////////////////////////////////////////////////////
1485
!
1486
      SUBROUTINE MakeCurveToChainConnections(self)
22✔
1487
         IMPLICIT NONE
1488
!
1489
!        ---------
1490
!        Arguments
1491
!        ---------
1492
!
1493
         CLASS(SMModel) :: self
1494
!
1495
!        ---------------
1496
!        Local variables
1497
!        ---------------
1498
!
1499
         CLASS(SMChainedCurve)      , POINTER :: chain => NULL()
1500
         CLASS(SMCurve)             , POINTER :: currentCurve => NULL()
1501
         CLASS(FTObject)            , POINTER :: obj => NULL()
1502
         CLASS(FTLinkedListIterator), POINTER    :: iterator => NULL()
1503

1504
         INTEGER                        :: chainCount
1505
         INTEGER                        :: j
1506

1507
         IF( self%curveCount == 0 )     RETURN
22✔
1508

1509
         ALLOCATE( self%boundaryCurveMap(self%curveCount) )
21✔
1510
         ALLOCATE( self%curveType(self%curveCount) ) ! Number of chains is always <= number of curves
21✔
1511
         chainCount = 0
21✔
1512
!
1513
!        -----------
1514
!        Outer chain
1515
!        -----------
1516
!
1517
         IF( ASSOCIATED(self%outerBoundary) )     THEN
21✔
1518
            chain                          => self % outerBoundary
20✔
1519
            chainCount                     =  chainCount + 1
20✔
1520
            self % curveType(chainCount)   =  BOUNDARY_CURVE
20✔
1521

1522
            CALL self % outerBoundary % setID(chainCount)
20✔
1523

1524
            DO j = 1, chain % COUNT()
59✔
1525
                obj => chain % curvesArray % objectAtIndex(j)
39✔
1526
                CALL cast(obj,currentCurve)
39✔
1527
                self % boundaryCurveMap( currentCurve % id() ) = self % outerBoundary % id()
59✔
1528
            END DO
1529
         END IF
1530
!
1531
!        ----------------
1532
!        Inner boundaries
1533
!        ----------------
1534
!
1535
         IF( ASSOCIATED( self % innerBoundaries ) )     THEN
21✔
1536
            ALLOCATE(iterator)
10✔
1537
            CALL iterator % initWithFTLinkedList(self % innerBoundaries)
10✔
1538
            CALL iterator % setToStart()
10✔
1539

1540
            DO WHILE (.NOT.iterator % isAtEnd())
43✔
1541
!
1542
!              --------------------
1543
!              Set chain properties
1544
!              --------------------
1545
!
1546
               obj => iterator % object()
33✔
1547
               CALL castToSMChainedCurve(obj,chain)
33✔
1548

1549
               chainCount                   =  chainCount + 1
33✔
1550
               self % curveType(chainCount) =  BOUNDARY_CURVE
33✔
1551

1552
               CALL chain % setID(chainCount)
33✔
1553
!
1554
!              ------------------------
1555
!              Component curve settings
1556
!              ------------------------
1557
!
1558

1559
               DO j = 1, chain % COUNT()
83✔
1560
                   obj => chain % curvesArray % objectAtIndex(j)
50✔
1561
                   CALL cast(obj,currentCurve)
50✔
1562
                   self % boundaryCurveMap( currentCurve % id() ) = chain % id()
83✔
1563
               END DO
1564

1565
               CALL iterator % moveToNext()
33✔
1566
            END DO
1567
            obj => iterator
10✔
1568
           CALL release(obj)
10✔
1569
        END IF
1570
!!
1571
!!        --------------------
1572
!!        Interface boundaries
1573
!!        --------------------
1574
!!
1575
         IF( ASSOCIATED( self % interfaceBoundaries ) )     THEN
21✔
1576
            ALLOCATE(iterator)
1✔
1577
            CALL iterator % initWithFTLinkedList(self % interfaceBoundaries)
1✔
1578
            CALL iterator % setToStart()
1✔
1579

1580
            DO WHILE (.NOT.iterator % isAtEnd())
3✔
1581
!
1582
!              --------------------
1583
!              Set chain properties
1584
!              --------------------
1585
!
1586
               obj => iterator % object()
2✔
1587
               CALL castToSMChainedCurve(obj,chain)
2✔
1588

1589
               chainCount                   =  chainCount + 1
2✔
1590
               self % curveType(chainCount) =  INTERFACE_CURVE
2✔
1591

1592
               CALL chain % setID(chainCount)
2✔
1593
!
1594
!              ------------------------
1595
!              Component curve settings
1596
!              ------------------------
1597
!
1598

1599
               DO j = 1, chain % COUNT()
4✔
1600
                   obj => chain % curvesArray % objectAtIndex(j)
2✔
1601
                   CALL cast(obj,currentCurve)
2✔
1602
                   self % boundaryCurveMap( currentCurve % id() ) = chain % id()
4✔
1603
               END DO
1604

1605
               CALL iterator % moveToNext()
2✔
1606
            END DO
1607
            obj => iterator
1✔
1608
           CALL release(obj)
1✔
1609
        END IF
1610

1611
      END SUBROUTINE MakeCurveToChainConnections
1612
!
1613
!////////////////////////////////////////////////////////////////////////
1614
!
1615
      SUBROUTINE ThrowModelReadException(objectName,msg)
×
1616
         USE FTValueClass
1617
         IMPLICIT NONE
1618
!
1619
!        ---------
1620
!        Arguments
1621
!        ---------
1622
!
1623
         CHARACTER(LEN=*)  :: msg
1624
         CHARACTER(LEN=*)  :: objectName
1625
!
1626
!        ---------------
1627
!        Local variables
1628
!        ---------------
1629
!
1630
         TYPE (FTException)   , POINTER :: exception => NULL()
1631
         CLASS(FTDictionary)  , POINTER :: userDictionary => NULL()
1632
         CLASS(FTObject)      , POINTER :: obj => NULL()
1633
         CLASS(FTValue)       , POINTER :: v => NULL()
1634
!
1635
!        -----------------------------------------------------
1636
!        The userDictionary for this exception contains the
1637
!        message to be delivered under the name "message"
1638
!        and the object being created by the name "objectName"
1639
!        -----------------------------------------------------
1640
!
1641
         ALLOCATE(userDictionary)
×
1642
         CALL userDictionary % initWithSize(4)
×
1643

1644
         ALLOCATE(v)
×
1645
         CALL v % initWithValue(objectName)
×
1646
         obj => v
×
1647
         CALL userDictionary % addObjectForKey(obj,"objectName")
×
1648
         CALL release(obj)
×
1649

1650
         ALLOCATE(v)
×
1651
         CALL v % initWithValue(msg)
×
1652
         obj => v
×
1653
         CALL userDictionary % addObjectForKey(obj,"message")
×
1654
         CALL release(obj)
×
1655
!
1656
!        --------------------
1657
!        Create the exception
1658
!        --------------------
1659
!
1660
         ALLOCATE(exception)
×
1661

1662
         CALL exception % initFTException(FT_ERROR_FATAL, &
1663
                              exceptionName   = MODEL_READ_EXCEPTION, &
1664
                              infoDictionary  = userDictionary)
×
1665
         obj => userDictionary
×
1666
         CALL release(obj)
×
1667
!
1668
!        -------------------
1669
!        Throw the exception
1670
!        -------------------
1671
!
1672
         CALL throw(exception)
×
1673
         obj => exception
×
1674
         CALL release(obj)
×
1675

1676
      END SUBROUTINE ThrowModelReadException
×
1677
!@mark -
1678
!
1679
!////////////////////////////////////////////////////////////////////////
1680
!
1681
      FUNCTION chainWithID( self, chainID ) RESULT(chain)
218✔
1682
         IMPLICIT NONE
1683
!
1684
!        ---------
1685
!        Arguments
1686
!        ---------
1687
!
1688
         INTEGER                        :: chainID
1689
         CLASS(SMModel)                 :: self
1690
         CLASS(SMChainedCurve), POINTER :: chain
1691
!
1692
!        ---------------
1693
!        Local Variables
1694
!        ---------------
1695
!
1696
         CLASS(FTObject)            , POINTER :: obj => NULL()
1697
         CLASS(FTLinkedListIterator), POINTER :: iterator => NULL()
1698

1699
         chain => NULL()
218✔
1700

1701
         IF( ASSOCIATED(self % outerBoundary) )     THEN
218✔
1702
            IF( chainID ==  self % outerBoundary % id() )     THEN
214✔
1703
               chain => self % outerBoundary
80✔
1704
               RETURN
80✔
1705
            END IF
1706
         END IF
1707

1708
         IF( ASSOCIATED(self % innerBoundaries) )     THEN
138✔
1709
            iterator => self % innerBoundariesIterator
132✔
1710
            CALL iterator % setToStart()
132✔
1711
            DO WHILE( .NOT.iterator % isAtEnd() )
376✔
1712
               obj => iterator % object()
376✔
1713
               CALL castToSMChainedCurve(obj,chain)
376✔
1714

1715
               IF( chainID == chain % id()) RETURN
376✔
1716

1717
               CALL iterator % moveToNext()
244✔
1718
            END DO
1719
         END IF
1720

1721
         IF( ASSOCIATED(self % interfaceBoundaries) )     THEN
6✔
1722
            iterator => self % interfaceBoundariesIterator
6✔
1723
            CALL iterator % setToStart()
6✔
1724
            DO WHILE( .NOT.iterator % isAtEnd() )
9✔
1725
               obj => iterator % object()
9✔
1726
               CALL castToSMChainedCurve(obj,chain)
9✔
1727

1728
               IF( chainID == chain % id()) RETURN
9✔
1729

1730
               CALL iterator % moveToNext()
3✔
1731
            END DO
1732
         END IF
1733

1734
      END FUNCTION chainWithID
×
1735
!
1736
!////////////////////////////////////////////////////////////////////////
1737
!
1738
      FUNCTION curveInModelWithID( self, curveID, chain ) RESULT(curve)
12,109✔
1739
         IMPLICIT NONE
1740
!
1741
!        ---------
1742
!        Arguments
1743
!        ---------
1744
!
1745
         INTEGER                        :: curveID
1746
         CLASS(SMModel)                 :: self
1747
         CLASS(SMChainedCurve), POINTER :: chain
1748
         CLASS(SMCurve)       , POINTER :: curve
1749
!
1750
!        ---------------
1751
!        Local Variables
1752
!        ---------------
1753
!
1754
         INTEGER                              :: chainID
1755
         CLASS(FTObject)            , POINTER :: obj => NULL()
1756
         CLASS(FTLinkedListIterator), POINTER :: iterator => NULL()
1757

1758
         chain   => NULL()
12,109✔
1759
         curve   => NULL()
12,109✔
1760
         chainID = self % boundaryCurveMap(curveID)
12,109✔
1761

1762
         IF( ASSOCIATED(self % outerBoundary) )     THEN
12,109✔
1763
            IF( chainID ==  self % outerBoundary % id() )     THEN
11,970✔
1764
               chain => self % outerBoundary
5,176✔
1765
               curve => chain % curveWithID(curveID)
5,176✔
1766
               RETURN
5,176✔
1767
            END IF
1768
         END IF
1769

1770
         IF( ASSOCIATED(self % innerBoundaries) )     THEN
6,933✔
1771
            iterator => self % innerBoundariesIterator
3,399✔
1772
            CALL iterator % setToStart()
3,399✔
1773
            DO WHILE( .NOT.iterator % isAtEnd() )
10,443✔
1774
               obj => iterator % object()
10,443✔
1775
               CALL castToSMChainedCurve(obj,chain)
10,443✔
1776

1777
               IF( chainID == chain % id()) THEN
10,443✔
1778
                  curve => chain % curveWithID(curveID)
3,399✔
1779
                  RETURN
3,399✔
1780
               END IF
1781

1782
               CALL iterator % moveToNext()
7,044✔
1783
            END DO
1784
         END IF
1785

1786
         IF( ASSOCIATED(self % interfaceBoundaries) )     THEN
3,534✔
1787
            iterator => self % interfaceBoundariesIterator
3,534✔
1788
            CALL iterator % setToStart()
3,534✔
1789
            DO WHILE( .NOT.iterator % isAtEnd() )
4,446✔
1790
               obj => iterator % object()
4,446✔
1791
               CALL castToSMChainedCurve(obj,chain)
4,446✔
1792

1793
               IF( chainID == chain % id()) THEN
4,446✔
1794
                  curve => chain % curveWithID(curveID)
3,534✔
1795
                  RETURN
3,534✔
1796
               END IF
1797

1798
               CALL iterator % moveToNext()
912✔
1799
            END DO
1800
         END IF
1801

1802
      END FUNCTION curveInModelWithID
×
1803
!
1804
!////////////////////////////////////////////////////////////////////////
1805
!
1806
      FUNCTION symmetryCurve(self)  RESULT(curve)
24✔
1807
!
1808
!     ------------------------------------------------------------
1809
!     Returns the first curve in the outer boundary with the name
1810
!     SYMMETRY_CURVE_NAME
1811
!     ------------------------------------------------------------
1812
!
1813
         IMPLICIT NONE
1814
!
1815
!        ---------
1816
!        Arguments
1817
!        ---------
1818
!
1819
         CLASS(SMModel)                 :: self
1820
         CLASS(SMCurve)       , POINTER :: curve
1821
         CLASS(SMChainedCurve), POINTER :: chain
1822
!
1823
!        ---------------
1824
!        Local variables
1825
!        ---------------
1826
!
1827
         INTEGER :: i
1828
         CLASS(SMCurve)        , POINTER :: chainCurve
1829
         CHARACTER(SM_CURVE_NAME_LENGTH) :: str
1830

1831
         NULLIFY(curve)
24✔
1832
         chain => self % outerBoundary
24✔
1833
         IF(.NOT. ASSOCIATED( chain)) RETURN
24✔
1834

1835
         DO i = 1, chain % COUNT()
58✔
1836
            chainCurve => chain % curveAtIndex(i)
39✔
1837
            str = chainCurve % curveName()
39✔
1838
            CALL toLower(str)
39✔
1839
            IF( str == SYMMETRY_CURVE_NAME) THEN
58✔
1840
               curve => chainCurve
1✔
1841
               RETURN
1✔
1842
            END IF
1843
         END DO
1844

1845
      END FUNCTION symmetryCurve
19✔
1846
!
1847
!////////////////////////////////////////////////////////////////////////
1848
!
1849
      FUNCTION allSymmetryCurvesAreColinear(self) RESULT(r)
1✔
1850
         USE LineReflectionModule
1851
         IMPLICIT NONE
1852
!
1853
!        ---------
1854
!        Arguments
1855
!        ---------
1856
!
1857
         CLASS(SMModel)  :: self
1858
         LOGICAL         ::r
1859
!
1860
!        ---------------
1861
!        Local variables
1862
!        ---------------
1863
!
1864
         CLASS(SMCurve)       , POINTER :: firstCurve
1865
         CLASS(SMChainedCurve), POINTER :: chain
1866
         CLASS(SMCurve)       , POINTER :: chainCurve
1867
         INTEGER                        :: i, firstID
1868
         REAL(KIND=RP)                  :: a1, b1, c1
1869
         REAL(KIND=RP)                  :: a , b , c
1870
         REAL(KIND=RP)                  :: x0(3), x1(3)
1871

1872
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str
1873

1874
         r = .TRUE.
1✔
1875
         chain => self % outerBoundary
1✔
1876
         IF(.NOT. ASSOCIATED( chain)) RETURN
1✔
1877
         NULLIFY(firstCurve)
1✔
1878

1879
         DO i = 1, chain % COUNT()
5✔
1880
            chainCurve => chain % curveAtIndex(i)
4✔
1881

1882
            str = chainCurve % curveName()
4✔
1883
            CALL toLower(str)
4✔
1884
            IF( str == SYMMETRY_CURVE_NAME) THEN
5✔
1885

1886
               IF ( .NOT. curveIsStraight(chainCurve) )     THEN
1✔
1887
                  WRITE(str,'(A,i3,A)') "Symmetry curve ", i, " is not straight"
×
1888
                  CALL ThrowErrorExceptionOfType(poster = "allSymmetryCurvesAreColinear",&
1889
                                                 msg    = str                           , &
1890
                                                 typ    = FT_ERROR_WARNING)
×
1891
                  r = .FALSE.
×
1892
               END IF
1893

1894
               IF ( .NOT. ASSOCIATED(firstCurve) )     THEN
1✔
1895
                  firstCurve => chainCurve
1✔
1896
                  firstID = firstCurve % id()
1✔
1897
                  x0 = firstCurve % positionAt(t = 0.0_RP)
4✔
1898
                  x1 = firstCurve % positionAt(t = 1.0_RP)
4✔
1899
                  CALL ComputeLineCoefs(x0,x1,a1,b1,c1)
1✔
1900
                  CYCLE
1✔
1901
               END IF
1902

1903
               x0 = chainCurve % positionAt(t = 0.0_RP)
×
1904
               x1 = chainCurve % positionAt(t = 1.0_RP)
×
1905
               CALL ComputeLineCoefs(x0,x1,a,b,c)
×
1906

1907
               IF ( .NOT. linesAreColinear(a,b,c, a1,b1,c1) )     THEN
×
1908
                  WRITE(str,'(A,i3,i3,A)') "Symmetry curves ", firstID, i, " are not colinear"
×
1909
                  CALL ThrowErrorExceptionOfType(poster = "allSymmetryCurvesAreColinear",&
1910
                                                 msg    = str                           , &
1911
                                                 typ    = FT_ERROR_WARNING)
×
1912
                  r = .FALSE.
×
1913
               END IF
1914

1915
            END IF
1916
         END DO
1917

1918
      END FUNCTION allSymmetryCurvesAreColinear
1✔
1919
!
1920
!////////////////////////////////////////////////////////////////////////
1921
!
1922
      INTEGER FUNCTION numberOfChains(self)
364✔
1923
         IMPLICIT NONE
1924
         CLASS(SMModel)  :: self
1925
         numberOfChains = self % numberOfInnerCurves +     &
1926
                          self % numberOfInterfaceCurves + &
1927
                          self % numberOfOuterCurves
364✔
1928
      END FUNCTION numberOfChains
364✔
1929
!
1930
!////////////////////////////////////////////////////////////////////////
1931
!
1932
      SUBROUTINE GatherAllChains(self)
22✔
1933
!
1934
!     -----------------------------------------------------------------
1935
!     For convenience, gather all of the boundary curve chains into an
1936
!     array for easier stepping without needing separate iterators.
1937
!     Enables access by chainID
1938
!     -----------------------------------------------------------------
1939
!
1940
         IMPLICIT NONE
1941
!
1942
!        ---------
1943
!        Arguments
1944
!        ---------
1945
!
1946
         CLASS(SMModel)  :: self
1947
!
1948
!        ---------------
1949
!        Local variables
1950
!        ---------------
1951
!
1952
         CLASS(FTObject)            , POINTER :: obj
1953
         TYPE (FTMutableObjectArray), POINTER :: objArray
1954
         CLASS(FTMutableObjectArray), POINTER :: chains   !Used as an alias for self % allChains
1955
         CLASS(SMChainedCurve)      , POINTER :: chain
1956
         INTEGER                              :: j
1957

1958
         ALLOCATE(self % allChains)
22✔
1959
         CALL self % allChains % initWithSize(self % numberOfChains())
22✔
1960
         chains => self % allChains !Just an alias
22✔
1961
!
1962
!        -----------------------------------------------------------------
1963
!        TODO: FTMutableObjectArray needs a way to update the count to
1964
!        allow replacement rather than add. The following gets around that
1965
!        omission
1966
!        -----------------------------------------------------------------
1967
!
1968
         ALLOCATE(obj)
22✔
1969
         CALL obj % init()
22✔
1970
         DO j = 1, self % numberOfChains()
77✔
1971
            CALL chains % addObject(obj)
77✔
1972
         END DO
1973
!
1974
!        -----------------
1975
!        Gather the chains
1976
!        -----------------
1977
!
1978
         IF ( self % numberOfOuterCurves == 1 )     THEN !(There is either 0 or 1)
22✔
1979
            obj => self % outerBoundary
20✔
1980
            CALL chains % replaceObjectAtIndexWithObject(indx        = self % outerBoundary % id(), &
1981
                                                         replacement = obj)
20✔
1982
         END IF
1983

1984
         !TODO: Someday add a "append array" procedure to
1985
         ! FTMutableObjectArray to replace these two blocks
1986

1987
         IF ( self % numberOfInnerCurves > 0 )     THEN
22✔
1988
            objArray => self % innerBoundaries % allObjects()
10✔
1989
            DO j = 1, objArray % COUNT()! numberOfItems(objArray)
43✔
1990
               obj => objArray % objectAtIndex(j)
33✔
1991
               CALL castToSMChainedCurve(obj,chain)
33✔
1992
               CALL chains % replaceObjectAtIndexWithObject(chain % id(),obj)
43✔
1993
            END DO
1994
            CALL releaseFTMutableObjectArray(objArray)
10✔
1995
         END IF
1996

1997
         IF ( self % numberOfInterfaceCurves > 0 )     THEN
22✔
1998
            objArray => self % interfaceBoundaries % allObjects()
1✔
1999
            DO j = 1, objArray % COUNT() !numberOfItems(objArray)
3✔
2000
               obj => objArray % objectAtIndex(j)
2✔
2001
               CALL castToSMChainedCurve(obj,chain)
2✔
2002
               CALL chains % replaceObjectAtIndexWithObject(chain % id(),obj)
3✔
2003
            END DO
2004
            CALL releaseFTMutableObjectArray(objArray)
1✔
2005
         END IF
2006

2007
      END SUBROUTINE GatherAllChains
22✔
2008

2009
      END Module SMModelClass
48✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc