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

trixi-framework / HOHQMesh / 30318764346

28 Jul 2026 12:55AM UTC coverage: 76.972% (+1.1%) from 75.909%
30318764346

Pull #166

github

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

1631 of 1964 new or added lines in 40 files covered. (83.04%)

48 existing lines in 4 files now uncovered.

9563 of 12424 relevant lines covered (76.97%)

634449.32 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
         TYPE(FTLinkedList)         , POINTER     :: innerBoundaries     => NULL()
82
         TYPE(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
         !DEBUG
175
            CALL releaseFTMutableObjectArray(self % allChains)
22✔
176
         END IF
177

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

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

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

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

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

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

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

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

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

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

261
         END IF
262

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

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

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

284
         END IF
285

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

508
            END IF
509

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

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

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

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

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

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

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

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

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

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

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

666
            CASE("PARAMETRIC_EQUATION_CURVE")
667

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

671
            CASE("PARAMETRIC_EQUATION")
672

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

676
            CASE ("SPLINE_CURVE" )
677

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

680
            CASE ("END_POINTS_LINE" )
681

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

684
            CASE (CIRCULAR_ARC_CONTROL_KEY)
685

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

688
            CASE (ELLIPTIC_ARC_CONTROL_KEY)
689

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1001
!
1002
         ELSE
1003

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

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

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

1043
         ENDIF
1044

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

1095
         END IF
1096

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

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

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

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

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

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

1275
         !SMCircularArc does not throw exceptions on init
1276

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

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

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

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

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

1459
         !SMEllipticArc does not throw exceptions on init
1460

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

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

1505
         INTEGER                        :: chainCount
1506
         INTEGER                        :: j
1507

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1700
         chain => NULL()
218✔
1701

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1873
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str
1874

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

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

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

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

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

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

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

1916
            END IF
1917
         END DO
1918

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

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

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

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

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

2008
      END SUBROUTINE GatherAllChains
22✔
2009

2010
      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