• 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

65.08
/Source/Project/MeshProject.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
!      MeshProject.f90
28
!      Created: August 19, 2013 11:19 AM
29
!      By: David Kopriva
30
!
31
!////////////////////////////////////////////////////////////////////////
32
!
33
   Module MeshProjectClass
34
      USE SMConstants
35
      USE SMModelClass
36
      USE MeshSizerClass
37
      USE SMMeshClass
38
      USE SharedExceptionManagerModule
39
      USE QuadTreeGridClass
40
      USE MeshSmootherClass
41
      USE FTValueDictionaryClass
42
      USE ErrorTypesModule
43
      USE ValueSettingModule
44
      USE HexMeshObjectsModule
45
      USE Geometry3DModule
46
      IMPLICIT NONE
47
!
48
!     ---------
49
!     Constants
50
!     ---------
51
!
52
      CHARACTER(LEN=18)         , PARAMETER :: PROJECT_READ_EXCEPTION     = "Project read error"
53

54
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: RUN_PARAMETERS_KEY         = "RUN_PARAMETERS"
55
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MESH_FILE_NAME_KEY         = "mesh file name"
56
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: PLOT_FILE_NAME_KEY         = "plot file name"
57
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: STATS_FILE_NAME_KEY        = "stats file name"
58
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: ERROR_FILE_NAME_KEY        = "error file name"
59
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MESH_FILE_FORMAT_NAME_KEY  = "mesh file format"
60
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: POLYNOMIAL_ORDER_KEY       = "polynomial order"
61
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: PLOT_FORMAT_KEY            = "plot file format"
62

63
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MESH_PARAMETERS_KEY         = "MESH_PARAMETERS"
64
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MESH_TYPE_KEY               = "mesh type"
65
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: GRID_SIZE_KEY               = "background grid size"
66
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: BACKGROUND_GRID_KEY         = "BACKGROUND_GRID"
67

68
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MATERIAL_BLOCK_KEY          = "MATERIALS"
69
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: BACKGROUND_MATERIAL_KEY     = "background material name"
70

71
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: X_START_NAME_KEY            = "x0"
72
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: X_END_NAME_KEY              = "x1"
73
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: DX_NAME_KEY                 = "dx"
74
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: SPACING_NAME_KEY            = "h"
75
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: EXTENT_NAME_KEY             = "w"
76
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: NUM_INTERVALS_NAME_KEY      = "N"
77
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: TYPE_NAME_KEY               = "type"
78

79
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: REFINEMENT_REGIONS_KEY      = "REFINEMENT_REGIONS"
80
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: REFINEMENT_CENTER_KEY       = "REFINEMENT_CENTER"
81
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: REFINEMENT_LINE_KEY         = "REFINEMENT_LINE"
82

83
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: ELEMENT_TYPE_KEY            = "element type"
84
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: SIMPLE_EXTRUSION_BLOCK_KEY  = "SIMPLE_EXTRUSION"
85
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: SIMPLE_ROTATION_BLOCK_KEY   = "SIMPLE_ROTATION"
86

87
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: SCALE_TRANSFORM_BLOCK_KEY   = "SCALE_TRANSFORM"
88
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: SCALE_TRANSFORM_SCALE_KEY   = "scale factor"
89
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: SCALE_TRANSFORM_ORIGIN_KEY  = "origin"
90

91
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: ROTATION_TRANSFORM_BLOCK_KEY       = "ROTATION_TRANSFORM"
92
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: ROTATION_TRANSFORM_TRANSLATION_KEY = "translation"
93
      CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: ROTATION_TRANSFORM_DIRECTION_KEY   = "direction"
94
!
95
!     ------------------
96
!     Private data types
97
!     ------------------
98
!
99
      TYPE RunParameters
100
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: MeshFileName
101
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: plotFileName
102
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: statsFileName
103
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: errorFileName
104
         INTEGER                                 :: meshFileFormat
105
         INTEGER                                 :: polynomialOrder
106
         INTEGER                                 :: plotFileFormat ! = SKELETON_FORMAT OR = SEM_FORMAT
107
      END TYPE RunParameters
108
      PRIVATE :: RunParameters
109

110
      TYPE MeshParameters
111
         INTEGER       :: meshType
112
      END TYPE MeshParameters
113
      PRIVATE :: MeshParameters
114

115
      TYPE BackgroundGridParameters
116
         REAL(KIND=RP) :: backgroundGridSize(3)
117
         INTEGER       :: N(3)
118
         REAL(KIND=RP) :: dx(3)
119
         REAL(KIND=RP) :: x0(3)
120
         REAL(KIND=RP) :: xMax(3)
121
      END TYPE backgroundGridParameters
122

123
      TYPE CentersParameters
124
         REAL(KIND=RP) :: x0(3)
125
         REAL(KIND=RP) :: centerMeshSize
126
         REAL(KIND=RP) :: centerExtent
127
         INTEGER       :: centerType
128
      END TYPE CentersParameters
129
      PRIVATE :: CentersParameters
130

131
      TYPE lineParameters
132
         REAL(KIND=RP) :: x0(3), x1(3)
133
         REAL(KIND=RP) :: lineMeshSize
134
         REAL(KIND=RP) :: lineExtent
135
         INTEGER       :: lineControlType
136
      END TYPE lineParameters
137
      PRIVATE :: lineParameters
138

139
      INTEGER, PARAMETER :: SKELETON_FORMAT = 0, SEM_FORMAT = 1
140
!
141
!     ------------------------
142
!     Project class definition
143
!     ------------------------
144
!
145
      TYPE, EXTENDS(FTObject) ::  MeshProject
146
         TYPE (SMModel)            , POINTER :: model    => NULL()
147
         TYPE (SMMesh)             , POINTER :: mesh     => NULL()
148
         TYPE (MeshSizer)          , POINTER :: sizer    => NULL()
149
         TYPE (QuadTreeGrid)       , POINTER :: grid     => NULL()
150
         CLASS(MeshSmoother)       , POINTER :: smoother => NULL()
151
         TYPE(StructuredHexMesh)   , POINTER :: hexMesh  => NULL()
152
         TYPE(FTMutableObjectArray), POINTER :: boundaryPolynomialsArray => NULL()
153
         TYPE(RunParameters)                 :: runParams
154
         TYPE(MeshParameters)                :: meshParams
155
         TYPE(BackgroundGridParameters)      :: backgroundParams
156
         TYPE(RotationTransform)             :: rotationTransformer
157
         TYPE(ScaleTransform)                :: scaleTransformer
158
         CHARACTER(LEN=32)                   :: backgroundMaterialName
159
         INTEGER                             :: numberOfLevelsUsed
160
         REAL(KIND=RP)                       :: boundaryErrorTolerance
161
         REAL(KIND=RP)         , ALLOCATABLE :: L2ErrorMax(:), H1ErrorMax(:)
162
         TYPE(JaggedRealArray) , ALLOCATABLE :: L2BoundaryError(:), H1BoundaryError(:)
163
!
164
!        ========
165
         CONTAINS
166
!        ========
167
!
168
         PROCEDURE :: initWithDictionary
169
         FINAL     :: DestructMeshProject
170
      END TYPE MeshProject
171
!
172
!     ========
173
      CONTAINS
174
!     ========
175
!
176
!
177
!////////////////////////////////////////////////////////////////////////
178
!
179
      SUBROUTINE initWithDictionary(self, masterControlDictionary )
24✔
180
         IMPLICIT NONE
181
!
182
!        ---------
183
!        Arguments
184
!        ---------
185
!
186
         CLASS(MeshProject)       :: self
187
         CLASS(FTValueDictionary) :: masterControlDictionary
188
!
189
!        ---------------
190
!        Local variables
191
!        ---------------
192
!
193
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: msg
194
         CLASS(FTValueDictionary)  , POINTER     :: controlDict, modelDict, matBlockdict, topoDict
195
         CLASS(FTObject)           , POINTER     :: obj
196
!
197
!        ----------
198
!        Interfaces
199
!        ----------
200
!
201
         LOGICAL, EXTERNAL :: ReturnOnFatalError
202
!
203
!        ---------------------------
204
!        Call superclass initializer
205
!        ---------------------------
206
!
207
         CALL self % FTObject % init()
24✔
208
!
209
!        ------------------------------------
210
!        Get run and model parameters
211
!        there must be a CONTROL_INPUT block,
212
!        but a model is optional
213
!        ------------------------------------
214
!
215
         self % numberOfLevelsUsed     = 0
24✔
216
         self % boundaryErrorTolerance = 1.0d-3 !DEBUG move this to a control file parameter
24✔
217

218
         obj         => masterControlDictionary % objectForKey(key = "CONTROL_INPUT")
24✔
219
         IF ( .NOT. ASSOCIATED(obj) )     THEN
24✔
220
            CALL ThrowErrorExceptionOfType(poster = "initWithDictionary",                            &
221
                                           msg = "CONTROL_INPUT block is missing from control file", &
222
                                           typ = FT_ERROR_FATAL)
×
223
            RETURN
2✔
224
         END IF
225
         controlDict => valueDictionaryFromObject(obj)
24✔
226

227
         modelDict => NULL()
24✔
228
         obj       => masterControlDictionary % objectForKey(key = "MODEL")
24✔
229
         IF ( .NOT. ASSOCIATED(obj) )     THEN
24✔
230
            CALL ThrowErrorExceptionOfType(poster = "initWithDictionary",                                    &
231
                  msg = "MODEL block is missing from the control file. A Cartesian mesh will be generated.", &
232
                  typ = FT_ERROR_WARNING)
2✔
233
         ELSE
234
            modelDict   => valueDictionaryFromObject(obj)
22✔
235
         END IF
236
!
237
!        --------------------------------------------------------------------
238
!        The MESH_PARAMETERS block is optional, but the BACKGROUND_GRID block
239
!        must be present
240
!        --------------------------------------------------------------------
241
!
242
         IF ( .NOT. controlDict % containsKey(key =  BACKGROUND_GRID_KEY) )     THEN
24✔
243
            CALL ThrowErrorExceptionOfType(poster = "initWithDictionary",                         &
244
                                           msg    = "Control file needs a BACKGROUND_GRID block", &
245
                                           typ    = FT_ERROR_FATAL)
×
246
            RETURN
×
247
         END IF
248

249
         CALL SetRunParametersBlock( self % runParams, controlDict )
24✔
250
         IF(ReturnOnFatalError())     RETURN
24✔
251
         CALL SetMeshParametersBlock( self % meshParams, controlDict )
24✔
252
         IF(ReturnOnFatalError())     RETURN
24✔
253
!
254
!        -------------------
255
!        Read the model file
256
!        -------------------
257
!
258
         ALLOCATE(self % model)
24✔
259
         CALL self % model % initWithContentsOfDictionary( modelDict )
24✔
260
         IF(ReturnOnFatalError())     RETURN
24✔
261
!
262
!        -----------------------------------------------------------------
263
!        If this is a multiple material mesh, as given by the ISM-MM flag,
264
!        read the background material name.
265
!        -----------------------------------------------------------------
266
!
267
         IF ( self % runParams % meshFileFormat == ISM_MM )     THEN
24✔
268
            IF ( .NOT.ASSOCIATED(modelDict) )     THEN
1✔
269
               msg = "A model is required to define materials to be used to output in the ISM_MM format"
×
270
               CALL ThrowErrorExceptionOfType(poster = "initWithDictionary", &
271
                                              msg    = msg, &
272
                                              typ    = FT_ERROR_FATAL)
×
273
               RETURN
×
274
            END IF
275

276
            IF ( modelDict % containsKey(key = MATERIAL_BLOCK_KEY) )     THEN
1✔
277
               obj => modelDict % objectForKey(key = MATERIAL_BLOCK_KEY)
1✔
278
               matBlockdict => valueDictionaryFromObject(obj)
1✔
279
               IF ( matBlockdict % containsKey(key = BACKGROUND_MATERIAL_KEY) )     THEN
1✔
280
                  self % backgroundMaterialName = matBlockdict % stringValueForKey(key = BACKGROUND_MATERIAL_KEY,&
281
                                                  requestedLength = DEFAULT_CHARACTER_LENGTH)
1✔
282
               ELSE
283
                  msg = "Background material name not found in control file. Using default name = 'base'"
×
284
                  CALL ThrowErrorExceptionOfType(poster = "initWithDictionary", &
285
                                                 msg    = msg, &
286
                                                 typ    = FT_ERROR_WARNING)
×
287
                  self % backgroundMaterialName = "base"
×
288
               END IF
289
            ELSE
290
               msg = "Background material block not found in control file. Using default name = 'base'"
×
291
               CALL ThrowErrorExceptionOfType(poster = "initWithDictionary", &
292
                                              msg    = msg, &
293
                                              typ    = FT_ERROR_WARNING)
×
294
               self % backgroundMaterialName = "base"
×
295
            END IF
296
         END IF
297
!
298
!        -----------------
299
!        Build the project
300
!        -----------------
301
!
302
         CALL BuildProject( self, controlDict )
24✔
303

304
         IF(.NOT.ASSOCIATED(modelDict))     RETURN
24✔
305
!
306
!        ----------------------------------------------------------------------
307
!        If the model has boundary curves (the only way we actually get to here),
308
!        then allocate the storage for the boundary curves that will be
309
!        used to compute the boundary errors, plus output
310
!        ----------------------------------------------------------------------
311
!
312
         IF ( self % model % numberOfChains() > 0 )     THEN
22✔
313
            ALLOCATE(self % boundaryPolynomialsArray)
21✔
314
            CALL self % boundaryPolynomialsArray % initWithSize(self % model % numberOfChains())
21✔
315
         END IF
316
!
317
!        ----------------------------------------------------------------
318
!        If there is topography and sizing is requested, add to the sizer
319
!        ----------------------------------------------------------------
320
!
321

322
         IF ( modelDict % containsKey(TOPOGRAPHY_BLOCK_KEY)) THEN
22✔
323
            obj => modelDict % objectForKey(TOPOGRAPHY_BLOCK_KEY)
4✔
324
            topoDict => valueDictionaryFromObject(obj)
4✔
325
            IF ( topoDict % containsKey(TOPOGRAPHY_SIZING_KEY) )     THEN
4✔
326
               IF ( topoDict % stringValueForKey(key = TOPOGRAPHY_SIZING_KEY,requestedLength = 6) == "ON" )     THEN
2✔
327
                  CALL self % sizer % setBottomTopography( self % model % topography )
4✔
328
               END IF
329
            END IF
330
         END IF
331
!
332
!        ----------------------------------------------------
333
!        Set the initial values of the global boundary errors
334
!        ----------------------------------------------------
335
!
336
         IF ( self % model % numberOfChains() > 0 )     THEN
22✔
337
            ALLOCATE(self % L2ErrorMax(self % model % numberOfChains()), source = HUGE(1.0d0))
76✔
338
            ALLOCATE(self % H1ErrorMax(self % model % numberOfChains()), source = HUGE(1.0d0))
76✔
339
         END IF
340

341
      END SUBROUTINE initWithDictionary
342
!
343
!////////////////////////////////////////////////////////////////////////
344
!
345
      SUBROUTINE DestructMeshProject(self)
24✔
346
         IMPLICIT NONE
347
         TYPE(MeshProject) :: self
348

349
         IF ( ASSOCIATED(self % model) )     THEN
24✔
350
            CALL releaseModel(self % model)
24✔
351
         END IF
352

353
         IF ( ASSOCIATED(self % mesh) )     THEN
24✔
354
            CALL releaseMesh(self % mesh)
24✔
355
         END IF
356

357
         IF ( ASSOCIATED(self % sizer) )     THEN
24✔
358
            CALL releaseSizer(self % sizer)
24✔
359
         END IF
360

361
         IF ( ASSOCIATED(self % grid) )     THEN
24✔
362
            CALL releaseGrid(self % grid)
×
363
         END IF
364

365
         IF ( ASSOCIATED(self % smoother) )     THEN
24✔
366
            DEALLOCATE(self % smoother)
46✔
367
         END IF
368

369
         IF (  ASSOCIATED(self % hexMesh) )     THEN
24✔
370
            CALL DestructStructuredHexMesh(hexMesh  = self % hexMesh)
9✔
371
         END IF
372

373
         IF ( ASSOCIATED( self % boundaryPolynomialsArray) )     THEN
24✔
374
            CALL releaseFTMutableObjectArray(self % boundaryPolynomialsArray)
21✔
375
         END IF
376

377
      END SUBROUTINE DestructMeshProject
24✔
378
!
379
!////////////////////////////////////////////////////////////////////////
380
!
381
      SUBROUTINE releaseMeshProject(self)
24✔
382
         IMPLICIT NONE
383
         CLASS(MeshProject), POINTER :: self
384
         CLASS(FTObject)   , POINTER :: obj
385

386
         IF(.NOT. ASSOCIATED(self)) RETURN
24✔
387

388
         obj => self
24✔
389
         CALL releaseFTObject(self = obj)
24✔
390
         IF ( .NOT. ASSOCIATED(obj) )     THEN
24✔
391
            self => NULL()
24✔
392
         END IF
393

394
      END SUBROUTINE releaseMeshProject
395
!
396
!////////////////////////////////////////////////////////////////////////
397
!
398
      SUBROUTINE ResetProject(self)
×
399
         IMPLICIT NONE
400
         CLASS(MeshProject)         , POINTER :: self
401

402
         IF ( ASSOCIATED(self % grid) )     THEN
×
403
            CALL releaseGrid(self % grid)
×
404
         END IF
405

406
         CALL BuildQuadtreeGrid(self)
×
407

408
         IF ( ASSOCIATED( self % mesh) )     THEN
×
409
            CALL releaseMesh(self % mesh)
×
410
         END IF
411

NEW
412
         CALL ResetProjectBoundaryObjects(self)
×
413

UNCOV
414
      END SUBROUTINE ResetProject
×
415
!
416
!////////////////////////////////////////////////////////////////////////
417
!
418
      SUBROUTINE ResetProjectBoundaryObjects(self)
24✔
419
         IMPLICIT NONE
420
         CLASS(MeshProject)         , POINTER :: self
421
         CLASS(FTMutableObjectArray), POINTER :: boundaryPolynomials !An alias
422
         CLASS(FTObject)            , POINTER :: obj
423

424
         IF(ALLOCATED(self % L2BoundaryError)) DEALLOCATE(self % L2BoundaryError)
103✔
425
         IF(ALLOCATED(self % H1BoundaryError)) DEALLOCATE(self % H1BoundaryError)
103✔
426
!
427
!        ---------------------------------------------------------------------
428
!        The FTMutableObjectArray has no method to clear the objects it holds,
429
!        so do that here manually
430
!        ---------------------------------------------------------------------
431
!
432
         CALL releaseFTMutableObjectArray(self % boundaryPolynomialsArray)
24✔
433
         IF ( self % model % numberOfChains() > 0 )     THEN
24✔
434
            ALLOCATE(self % boundaryPolynomialsArray)
21✔
435
            CALL self % boundaryPolynomialsArray % initWithSize(self % model % numberOfChains())
21✔
436
         END IF
437

438
      END SUBROUTINE ResetProjectBoundaryObjects
24✔
439
!@mark -
440
!
441
!////////////////////////////////////////////////////////////////////////
442
!
443
      SUBROUTINE BuildProject( self, controlDict )
24✔
444
         USE ChainedSegmentedCurveClass
445
         USE SizerControls
446
         USE SMChainedCurveClass
447
         USE CurveConversionsModule
448
         USE SpringMeshSmootherClass
449
         USE LaplaceMeshSmootherClass
450
         IMPLICIT NONE
451
!
452
!        ---------
453
!        Arguments
454
!        ---------
455
!
456
         CLASS(FTValueDictionary) :: controlDict
457
         TYPE(MeshProject)        :: self
458
!
459
!        ----------
460
!        Interfaces
461
!        ----------
462
!
463
         LOGICAL, EXTERNAL :: ReturnOnFatalError
464
!
465
!        ---------------
466
!        Local Variables
467
!        ---------------
468
!
469
         CLASS(FTValueDictionary)    , POINTER :: smootherDict, refinementsDict
470
         CLASS(FTValueDictionary)    , POINTER :: scaleTransformDict, rotationTransformDict
471
         CLASS(FTLinkedList)         , POINTER :: refinementsList
472
         CLASS(FTLinkedListIterator) , POINTER :: refinementIterator => NULL()
473
         CLASS(FTObject)             , POINTER :: obj => NULL()
474
         CLASS(SpringMeshSmoother)   , POINTER :: springSmoother => NULL()
475

476
         CHARACTER(LEN=SEGMENTED_CURVE_NAME_LENGTH) :: tightestCurveName
477
         REAL(KIND=RP)                              :: meshRatio
478
         INTEGER                                    :: levelsNeeded
479
         CHARACTER(LEN=256)                         :: limitMsg
480
         CHARACTER(LEN=2)                           :: levelsAsString, maxLevelsAsString, newLevelsAsString
481

482
         TYPE(SpringSmootherParameters) :: smootherParams
483

484
         NULLIFY( self % grid )
24✔
485
         NULLIFY( self % sizer )
24✔
486
         CALL ConstructIdentityScaleTransform(self = self % scaleTransformer)
24✔
487
         CALL ConstructIdentityRotationTransform(self = self % rotationTransformer)
24✔
488
!
489
         CALL BuildBackgroundGrid(self, controlDict )
24✔
490
         CALL BuildQuadtreeGrid(self)
24✔
491
!
492
!        -------------------------
493
!        Build up Sizer properties
494
!        -------------------------
495
!
496
         ALLOCATE(self % sizer)
24✔
497
         CALL self % sizer % initWithProperties( self % backgroundParams % dx, &
498
                                                 self % backgroundParams % x0, &
499
                                                 self % backgroundParams % xMax )
24✔
500
         IF(ReturnOnFatalError())     RETURN
24✔
501

502
         IF ( controlDict % containsKey(key = REFINEMENT_REGIONS_KEY) )     THEN
24✔
503

504
            ALLOCATE(refinementIterator)
2✔
505
            obj             => controlDict % objectForKey(key = REFINEMENT_REGIONS_KEY)
2✔
506
            refinementsDict => valueDictionaryFromObject(obj)
2✔
507
            obj             => refinementsDict % objectForKey(key = "LIST")
2✔
508
            refinementsList => linkedListFromObject(obj)
2✔
509

510
            CALL AddRefinementRegionsToSizer(refinementsList, sizer = self % sizer)
2✔
511

512
         END IF
513
         CALL BuildSizerBoundaryCurves(self)
24✔
514
!
515
!        -------------------------------------------------------
516
!        Check integrity of boundary curves: stop if any overlap
517
!        -------------------------------------------------------
518
!
519
         CALL CheckForBoundaryIntersections(self % sizer) !Development in progress
24✔
520
         IF(catch(FATAL_ERROR_EXCEPTION))     RETURN
24✔
521
!
522
!        --------------------------------------------------------------------------
523
!        Before going further, check to see how many subdivisions will be necessary
524
!        --------------------------------------------------------------------------
525
!
526
         CALL self % sizer % sizeRatio(ratio             = meshRatio, &
527
                                       worstOffenderName = tightestCurveName)
24✔
528
         IF ( meshRatio > 0.0_RP )     THEN
24✔
529
            levelsNeeded = CEILING(LOG(meshRatio)/LOG(2.0_RP))
21✔
530
            IF ( levelsNeeded > maxLevelLimit )     THEN
21✔
531
               WRITE(levelsAsString,'(I2)')     levelsNeeded - maxLevelLimit
×
532
               WRITE(maxLevelsAsString, '(I2)') maxLevelLimit
×
533
               WRITE(newLevelsAsString, '(I2)') levelsNeeded
×
534

535
               limitMsg = "Resolution on curve " // TRIM(tightestCurveName) // " needs " // &
536
                           levelsAsString // " subdivision(s) more than the currently allowed " // &
537
                           maxLevelsAsString // ". "// &
538
                           NEW_LINE(levelsAsString) // &
539
                           "To override, rerun with the command line flag '-sLimit " // &
540
                           newLevelsAsString // "'. But think before doing this."
×
541

542
               CALL ThrowErrorExceptionOfType(poster = "BuildProject", &
543
                                              msg    = limitMsg,       &
544
                                              typ    = FT_ERROR_FATAL)
×
545
               RETURN
×
546
            END IF
547
         END IF
548
!
549
!        ------------------
550
!        Construct smoother
551
!        ------------------
552
!
553
         NULLIFY(self % smoother)
24✔
554
         IF ( controlDict % containsKey(key = "SPRING_SMOOTHER") )     THEN
24✔
555

556
            obj          => controlDict % objectForKey(key = "SPRING_SMOOTHER")
24✔
557
            smootherDict => valueDictionaryFromObject(obj)
24✔
558

559
            CALL SetSpringSmootherBlock( smootherDict, smootherParams )
24✔
560
            IF(ReturnOnFatalError())     RETURN
24✔
561

562
            IF( smootherParams % smoothingOn )     THEN
24✔
563
               ALLOCATE(springSmoother)
23✔
564
               CALL springSmoother % init(  smootherParams % springConstant, &
565
                                            smootherParams % mass, &
566
                                            smootherParams % restLength, &
567
                                            smootherParams % dampingCoefficient, &
568
                                            smootherParams % springType, &
569
                                            smootherParams % deltaT, &
570
                                            smootherParams % numSteps )
23✔
571
               self % smoother => springSmoother
23✔
572
            END IF
573
         ELSE
574
            ! For other possibilities added later
575
         END IF
576
!
577
!        --------------------------
578
!        Construct Rotation transform
579
!        --------------------------
580
!
581
         IF ( controlDict % containsKey(key = ROTATION_TRANSFORM_BLOCK_KEY) )     THEN
24✔
582
            obj                => controlDict % objectForKey(key = ROTATION_TRANSFORM_BLOCK_KEY)
×
583
            rotationTransformDict => valueDictionaryFromObject(obj)
×
584
            CALL SetRotationTransformBlock(rotationBlockDict   = rotationTransformDict,     &
585
                                           rotationTransformer = self % rotationTransformer)
×
586
         END IF
587
!
588
!        ---------------------------
589
!        Construct Scaling transform
590
!        ---------------------------
591
!
592
         IF ( controlDict % containsKey(key = SCALE_TRANSFORM_BLOCK_KEY) )     THEN
24✔
593
            obj                => controlDict % objectForKey(key = SCALE_TRANSFORM_BLOCK_KEY)
×
594
            scaleTransformDict => valueDictionaryFromObject(obj)
×
595
            CALL SetScaleTransformBlock(scaleBlockDict   = scaleTransformDict, &
596
                                        scaleTransformer = self % scaleTransformer)
×
597
         END IF
598

599
      END SUBROUTINE BuildProject
24✔
600
!
601
!////////////////////////////////////////////////////////////////////////
602
!
603
      SUBROUTINE BuildBackgroundGrid(self, controlDict)
24✔
604
!
605
!-------------------------------------------------------------------------------
606
!     Construct the Background Grid and initialize Sizer
607
!     The background grid size can either be specified or inferred
608
!     from the model depending on if the background grid block is
609
!     present or not.
610
!-------------------------------------------------------------------------------
611
!
612
         IMPLICIT NONE
613
!
614
!        ---------
615
!        Arguments
616
!        ---------
617
!
618
         CLASS(FTValueDictionary) :: controlDict
619
         TYPE(MeshProject)        :: self
620
!
621
!        ---------------
622
!        Local variables
623
!        ---------------
624
!
625
         REAL(KIND=RP)                  ::xMax(3)
626
         TYPE(BackgroundGridParameters) :: backgroundGrid
627
         CLASS(FTObject)             , POINTER :: obj => NULL()
628
         CLASS(FTValueDictionary)    , POINTER :: backgroundGridDict
629
!
630
!        ----------
631
!        Interfaces
632
!        ----------
633
!
634
         LOGICAL, EXTERNAL :: ReturnOnFatalError
635

636
         obj => controlDict % objectForKey(key = BACKGROUND_GRID_KEY)
24✔
637
         backgroundGridDict => valueDictionaryFromObject(obj)
24✔
638
         CALL SetBackgroundGridBlock( backgroundGrid, backgroundGridDict )
24✔
639
         IF(ReturnOnFatalError())     RETURN
24✔
640

641
         IF( .NOT. backgroundGridDict % containsKey(key = GRID_SIZE_KEY))     THEN
24✔
642

643
            backgroundGrid % backgroundGridSize = 2*backgroundGrid % dx
16✔
644

645
            xMax                  = backgroundGrid % x0 + backgroundGrid % N*backgroundGrid % dx
16✔
646
            backgroundGrid % xMax = xMax
16✔
647

648
         ELSE
649

650
            CALL BuildbackgroundGridFromModel( backgroundGrid, self % model, &
651
                                               backgroundGrid % backgroundGridSize )
20✔
652
            IF(ReturnOnFatalError())     RETURN
20✔
653

654
            xMax = backgroundGrid % x0 + backgroundGrid % N*backgroundGrid % dx
80✔
655
            backgroundGrid % xMax = xMax
80✔
656

657
         END IF
658
         self % backgroundParams = backgroundGrid
24✔
659

660
      END SUBROUTINE BuildBackgroundGrid
24✔
661
!
662
!////////////////////////////////////////////////////////////////////////
663
!
664
      SUBROUTINE BuildQuadtreeGrid(self)
24✔
665
         IMPLICIT NONE
666
!
667
!        ---------
668
!        Arguments
669
!        ---------
670
!
671
         TYPE(MeshProject)        :: self
672
!
673
!        ---------------
674
!        Local Variables
675
!        ---------------
676
!
677
         TYPE (QuadTreeGrid), POINTER :: parent => NULL()
678
         NULLIFY(parent)
24✔
679

680
         IF(ASSOCIATED(self % grid))      THEN
24✔
681
            CALL releaseGrid(self % grid)
×
682
         END IF
683

684
         ALLOCATE(self % grid)
24✔
685
         CALL self % grid % initGridWithParameters( self % backgroundParams % dx, &
686
                                                    self % backgroundParams % x0, &
687
                                                    self % backgroundParams % N,  &
688
                                                     parent, (/0,0,0/), 0)
24✔
689
      END SUBROUTINE BuildQuadtreeGrid
24✔
690
!
691
!////////////////////////////////////////////////////////////////////////
692
!
693
      SUBROUTINE AddRefinementRegionsToSizer( refinementsList, sizer)
2✔
694
         IMPLICIT NONE
695
!
696
!        ---------
697
!        Arguments
698
!        ---------
699
!
700
         CLASS(FTLinkedList) , POINTER :: refinementsList
701
         TYPE (MeshSizer)    , POINTER :: sizer
702
!
703
!        ---------------
704
!        Local Variables
705
!        ---------------
706
!
707
         CLASS (FTLinkedListIterator), POINTER   :: refinementIterator => NULL()
708
         CLASS(FTObject)             , POINTER   :: obj => NULL()
709
         CLASS(FTValueDictionary)    , POINTER   :: refinementObjectDict
710

711
         CLASS(SizerCentercontrol), POINTER      :: c => NULL()
712
         CLASS(SizerLineControl)  , POINTER      :: L => NULL()
713

714
         TYPE(CentersParameters)                 :: centerParams
715
         TYPE(LineParameters)                    :: lineParams
716
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str
717
!
718
!        --------------------------------------------------------------
719
!        Refinement regions are stored in a linked list of dictionaries
720
!        --------------------------------------------------------------
721
!
722
         ALLOCATE(refinementIterator)
2✔
723
         CALL refinementIterator % initWithFTLinkedListClass(list = refinementsList)
2✔
724
         CALL refinementIterator % setToStart()
2✔
725

726
         DO WHILE (.NOT. refinementIterator % isAtEnd())
5✔
727

728
            obj                  => refinementIterator % object()
3✔
729
            refinementObjectDict => valueDictionaryFromObject(obj)
3✔
730
            str = refinementObjectDict % stringValueForKey(key = "TYPE", &
731
                                                           requestedLength = DEFAULT_CHARACTER_LENGTH)
3✔
732
            SELECT CASE ( str )
2✔
733

734
               CASE( REFINEMENT_CENTER_KEY )
735

736
                  CALL SetCenterMeshSizerBlock(centerParams = centerParams, centerDict = refinementObjectDict)
2✔
737

738
                  ALLOCATE(c)
2✔
739
                  CALL c % initWithProperties( centerParams % x0, centerParams % centerExtent, &
740
                                             centerParams % centerMeshSize, centerParams % centerType )
2✔
741
                  CALL sizer % addSizerCenterControl(c)
2✔
742
                  obj => c
2✔
743
                  CALL release(obj)
2✔
744

745
               CASE ( REFINEMENT_LINE_KEY)
746

747
                  CALL SetLineMeshSizerBlock(lineParams = lineParams, lineSizerDict = refinementObjectDict)
1✔
748

749
                  ALLOCATE(L)
1✔
750
                  CALL L    % initWithProperties( lineParams % x0, lineParams % x1, lineParams % lineExtent, &
751
                                                  lineParams % lineMeshSize, lineParams % lineControlType )
1✔
752
                  CALL sizer % addSizerLineControl(L)
1✔
753
                  obj => L
1✔
754
                  CALL release(obj)
1✔
755

756
               CASE DEFAULT
757
                  CALL ThrowErrorExceptionOfType(poster = "AddRefinementRegionsToSizer", &
758
                                                 msg    = "Unknown refinement region is ignored: "// TRIM(str), &
759
                                                 typ    = FT_ERROR_WARNING)
3✔
760
            END SELECT
761

762
            CALL refinementIterator % moveToNext()
3✔
763
         END DO
764

765
         CALL releaseFTLinkedListIteratorClass(refinementIterator)
2✔
766

767
      END SUBROUTINE AddRefinementRegionsToSizer
2✔
768
!
769
!////////////////////////////////////////////////////////////////////////
770
!
771
      SUBROUTINE BuildSizerBoundaryCurves(self)
24✔
772
         USE ChainedSegmentedCurveClass
773
         USE SMChainedCurveClass
774
         USE CurveConversionsModule
775
         IMPLICIT NONE
776
!
777
!        ---------
778
!        Arguments
779
!        ---------
780
!
781
         TYPE(MeshProject)        :: self
782
!
783
!        ---------------
784
!        Local Variables
785
!        ---------------
786
!
787
         INTEGER                                :: curveID, j
788
         REAL(KIND=RP)                          :: h
789
         CLASS(FTLinkedListIterator)  , POINTER :: iterator => NULL()
790
         CLASS(FTObject)              , POINTER :: obj => NULL()
791
         CLASS(ChainedSegmentedCurve) , POINTER :: segmentedOuterBoundary => NULL()
792
         CLASS(ChainedSegmentedCurve) , POINTER :: segmentedInnerBoundary => NULL()
793
         CLASS(SMChainedCurve)        , POINTER :: chain => NULL()
794
         CLASS(SMCurve)               , POINTER :: optimizedCurve, crv
795
         REAL(KIND=RP), ALLOCATABLE             :: segmentsSizes(:)
24✔
796
         REAL(KIND=RP), ALLOCATABLE             :: cuts(:)
24✔
797
         LOGICAL, EXTERNAL :: ReturnOnFatalError
798
!
799
!        ------------------------------------------------
800
!        Discretize boundary curves and add to sizer.
801
!        Use current sizer attributes to subdivide the
802
!        boundary curves. There is a relationship between
803
!        computing the discretization of the boundary
804
!        curves and the size to be associated with the
805
!        sizer.
806
!        ------------------------------------------------
807
!
808
         curveID = 0
24✔
809
         h       = MINVAL(self % backgroundParams % backgroundGridSize(1:2))
72✔
810

811
         IF( ASSOCIATED( self % model % outerBoundary ) )     THEN
24✔
812
            curveID                =  curveID + 1
20✔
813

814
            IF ( self % model % outerBoundary % optimization /= NONE )     THEN
20✔
815
               CALL ComputeOptimizedSegments(curve         = self % model % outerBoundary ,        &
816
                                             breaks        = self % model % outerBoundary % breaks,&
817
                                             cuts          = cuts,                                 &
818
                                             segmentsSizes = segmentsSizes,                        &
NEW
819
                                             polyOrder     = self % runParams % polynomialOrder)
×
820
               segmentedOuterBoundary => allocAndInitSegmentedChainFromChain( self % model % outerBoundary, curveID, &
NEW
821
                                                                             h, self % sizer % controlsList, segmentsSizes, cuts )
×
NEW
822
               IF(ALLOCATED(segmentsSizes)) DEALLOCATE(segmentsSizes)
×
NEW
823
               IF(ALLOCATED(cuts)) DEALLOCATE(cuts)
×
824
            ELSE
825
               segmentedOuterBoundary => allocAndInitSegmentedChainFromChain( self % model % outerBoundary, curveID, &
826
                                                                              h, self % sizer % controlsList )
20✔
827
            END IF
828

829
            CALL self % sizer % addBoundaryCurve(segmentedOuterBoundary,OUTER)
20✔
830
            CALL releaseChainChainedSegmentedCurve(segmentedOuterBoundary)
20✔
831
        END IF
832
!
833
!        --------------------------------------
834
!        Step through each inner boundary curve
835
!        and construct chains.
836
!        --------------------------------------
837
!
838
         IF( ASSOCIATED( self % model % innerBoundaries ) )     THEN
24✔
839
            iterator => self % model % innerBoundariesIterator
10✔
840
            CALL iterator % setToStart()
10✔
841
            j = 0
10✔
842
            DO WHILE (.NOT.iterator % isAtEnd())
43✔
843
               curveID =  curveID + 1
33✔
844
               obj     => iterator % object()
33✔
845
               CALL castToSMChainedCurve(obj,chain)
33✔
846

847
               IF ( chain % optimization /= NONE )     THEN
33✔
848
                  CALL ComputeOptimizedSegments(curve         = chain ,        &
849
                                                breaks        = chain % breaks,&
850
                                                cuts          = cuts,                                 &
851
                                                segmentsSizes = segmentsSizes,                        &
NEW
852
                                                polyOrder     = self % runParams % polynomialOrder)
×
853
                  segmentedInnerBoundary => allocAndInitSegmentedChainFromChain( chain, curveID,                 &
854
                                                                                 h, self % sizer % controlsList, &
NEW
855
                                                                                 segmentsSizes, cuts )
×
NEW
856
                  IF(ALLOCATED(segmentsSizes)) DEALLOCATE(segmentsSizes)
×
NEW
857
                  IF(ALLOCATED(cuts)) DEALLOCATE(cuts)
×
858
               ELSE
859
                  segmentedInnerBoundary => allocAndInitSegmentedChainFromChain( chain, curveID, h, self % sizer % controlsList )
33✔
860
               END IF
861

862
               CALL self % sizer % addBoundaryCurve(segmentedInnerBoundary,INNER)
33✔
863
               CALL releaseChainChainedSegmentedCurve(segmentedInnerBoundary)
33✔
864

865
               CALL iterator % moveToNext()
33✔
866
            END DO
867
         END IF
868
!
869
!        ------------------------------------------
870
!        Step through each interface boundary curve
871
!        and construct chains.
872
!        ------------------------------------------
873
!
874
         IF( ASSOCIATED( self % model % interfaceBoundaries ) )     THEN
24✔
875
            iterator => self % model % interfaceBoundariesIterator
1✔
876
            CALL iterator % setToStart
1✔
877
            j = 0
1✔
878
             DO WHILE (.NOT.iterator % isAtEnd())
3✔
879
                curveID =  curveID + 1
2✔
880
                obj     => iterator % object()
2✔
881
                CALL castToSMChainedCurve(obj,chain)
2✔
882

883
                IF ( chain % optimization /= NONE )     THEN
2✔
884
                  CALL ComputeOptimizedSegments(curve         = chain ,                             &
885
                                                breaks        = chain % breaks,                     &
886
                                                cuts          = cuts,                               &
887
                                                segmentsSizes = segmentsSizes,                      &
NEW
888
                                                polyOrder     = self % runParams % polynomialOrder)
×
889
                  segmentedInnerBoundary => allocAndInitSegmentedChainFromChain( chain, curveID,                 &
890
                                                                                 h, self % sizer % controlsList, &
NEW
891
                                                                                 segmentsSizes, cuts )
×
NEW
892
                  IF(ALLOCATED(segmentsSizes)) DEALLOCATE(segmentsSizes)
×
NEW
893
                  IF(ALLOCATED(cuts)) DEALLOCATE(cuts)
×
894
                ELSE
895
                  segmentedInnerBoundary => allocAndInitSegmentedChainFromChain( chain, curveID, h,              &
896
                                                                                 self % sizer % controlsList )
2✔
897
                END IF
898

899
                CALL self % sizer % addBoundaryCurve(segmentedInnerBoundary,INTERIOR_INTERFACE)
2✔
900
                CALL releaseChainChainedSegmentedCurve(segmentedInnerBoundary)
2✔
901

902
                CALL iterator % moveToNext()
2✔
903
             END DO
904
         END IF
905
!
906
!        -------------------------------------------------------
907
!        Make sure that there are enough elements between curves
908
!        Adjust the sizer to account for the curves.
909
!        -------------------------------------------------------
910
!
911
         IF ( ASSOCIATED( self % model % interfaceBoundaries ) .OR. &
912
              ASSOCIATED( self % model % innerBoundaries )     .OR. &
24✔
913
              ASSOCIATED(self % model % outerBoundary))        THEN
914
            CALL ComputeCurveDistanceScales( self % sizer )
21✔
915
         END IF
916

917
         IF ( ASSOCIATED( self % model % interfaceBoundaries ) ) THEN
24✔
918
            CALL ComputeInterfaceCurveScales( self % sizer )
1✔
919
         END IF
920
!
921
!        TODO: ResizeSegmentedCurves is introduced to solve the dilemma that
922
!              in order to determine the distances curves are from eachother,
923
!              they must be discetized, but once the distances are found, it
924
!              may be true that the spacing between the points is large in
925
!              comparison. ResizeSegmentedCurves goes back and compares the
926
!              spacing between the points in the segmented curves to the
927
!              computed spacing between the curves. This appears to be an
928
!              iterative process, but is only done once.
929
!              The procedure compiles and runs, but until a case arises where
930
!              it is necessary, the procedure has not been debugged. Hence,
931
!              it is skipped until then.
932
!
933
!         CALL ResizeSegmentedCurves(self)
934

935
      END SUBROUTINE BuildSizerBoundaryCurves
24✔
936
!
937
!////////////////////////////////////////////////////////////////////////
938
!
NEW
939
      SUBROUTINE ComputeOptimizedSegments(curve, breaks, cuts, segmentsSizes, polyOrder)
×
940
        USE MultiSegmentModalCurveClass
24✔
941
        USE ConstrainedMultiH1Optimization
942
        USE CurveOptimization
943
        IMPLICIT NONE
944
!
945
!        ---------
946
!        Arguments
947
!        ---------
948
!
949
         CLASS(SMChainedCurve), POINTER :: curve
950
         REAL(KIND=RP), ALLOCATABLE     :: segmentsSizes(:)
951
         INTEGER                        :: polyOrder
952
         REAL(KIND=RP)                  :: breaks(0:)         ! Location of forced cut points, starting with t = 0.0
953
         REAL(KIND=RP), ALLOCATABLE     :: cuts(:)
954
!
955
!        ---------------
956
!        Local Variables
957
!        ---------------
958
!
NEW
959
         INTEGER      , ALLOCATABLE :: breakIndices(:)    ! index in optimizedCuts where break boundaries occur
×
NEW
960
         REAL(KIND=RP), ALLOCATABLE :: arcLengths(:)
×
961
         TYPE(OptimizerOptions)     :: options
962
         CLASS(SMCurve), POINTER    :: crv
963
         REAL(KIND=RP)              :: minSegment
964
         INTEGER                    :: j, nSegments
NEW
965
         TYPE(GaussQuadratureType)  :: gQuad
×
966
         REAL(KIND=RP)              :: x1(3),x2(3)
967

NEW
968
         CALL SetDefaultOptions(options)
×
NEW
969
         options % internalConstraint = curve % continuity
×
NEW
970
         options % toler              = curve % tolerance
×
NEW
971
         options % whichNorm          = curve % optimization
×
972

NEW
973
         CALL ConstructGaussQuadrature(gQuad, 4*polyOrder) ! For error computation. The 4 is arbitrary
×
974

NEW
975
         crv => curve
×
976
         CALL FindOptimizedCuts(crv, polyOrder, breaks, options, gQuad, &
NEW
977
                                cuts, breakIndices)
×
NEW
978
         CALL curveSegmentLengths(crv, polyOrder, cuts, options, gQuad, arcLengths)
×
979

NEW
980
         nSegments = UBOUND(cuts,1)
×
NEW
981
         ALLOCATE(segmentsSizes(nSegments))
×
982

NEW
983
         x1 = curve % positionAt(cuts(0))
×
NEW
984
         minSegment = HUGE(minSegment)
×
985

NEW
986
         DO j = 1, nSegments
×
NEW
987
            x2 = curve % positionAt(cuts(j))
×
988
!
989
!           ------------------------------------------------------------------
990
!           Choose the segment size to be the largest of the x or y projection
991
!           of the vector between the two segment points
992
!           ------------------------------------------------------------------
993
!
NEW
994
            segmentsSizes(j) = sqrt((x2(1) - x1(1))**2 + (x2(2) - x1(2))**2)
×
NEW
995
            minSegment = MIN(minSegment, segmentsSizes(j))
×
NEW
996
            x1 = x2
×
997
         END DO
998

NEW
999
         IF ( printMessage )     THEN
×
NEW
1000
            PRINT *, "Minimum size for for accurate approximation of the curve ", &
×
NEW
1001
            TRIM(curve % curveName()), " is ", minSegment
×
1002
         END IF
1003

NEW
1004
      END SUBROUTINE ComputeOptimizedSegments
×
1005
!
1006
!////////////////////////////////////////////////////////////////////////
1007
!
1008
      SUBROUTINE ResizeSegmentedCurves( self )
×
1009
!
1010
!     -----------------------------------------------------------
1011
!     After the spacing between a curve and itself, and a curve
1012
!     with other curves is computed, the distance between points
1013
!     on the segmented curves might be too large in comparison.
1014
!     If so, subdivide the segmented curves further.
1015
!     -----------------------------------------------------------
1016
!
1017
         IMPLICIT NONE
1018
!
1019
!        ---------
1020
!        Arguments
1021
!        ---------
1022
!
1023
         TYPE (MeshProject) :: self
1024
!
1025
!        ---------------
1026
!        Local variables
1027
!        ---------------
1028
!
1029
         CLASS(MeshSizer)            , POINTER :: sizer
1030
         CLASS(FRSegmentedCurve)     , POINTER :: frsCurve
1031
         CLASS(SMChainedCurve)       , POINTER :: outerBoundary
1032
         CLASS(SMCurve)              , POINTER :: cCurve
1033
         CLASS(FTLinkedListIterator) , POINTER :: curveIterator, segmentedIterator
1034
         CLASS(FTObject)             , POINTER :: obj
1035
         CLASS(SMChainedCurve)       , POINTER :: innerCurveChain
1036
         CLASS(ChainedSegmentedCurve), POINTER :: innerSegmentedCurveChain
1037
         INTEGER                              :: j
1038

1039
         sizer => self % sizer
×
1040
!
1041
!        --------------
1042
!        Outer boundary
1043
!        --------------
1044
!
1045
         IF ( ASSOCIATED( sizer % outerBoundary) )     THEN
×
1046
            outerBoundary => self % model % outerBoundary
×
1047
            DO j = 1, sizer % outerBoundary % curveCount()
×
1048
               cCurve   => outerBoundary % curveAtIndex(j)
×
1049
               frsCurve => sizer % outerBoundary % segmentedCurveAtIndex(j)
×
1050
               CALL ResizeFRSegmentedCurve(self = frsCurve, curve = cCurve)
×
1051
            END DO
1052
         END IF
1053
!
1054
!        ----------------
1055
!        Inner boundaries
1056
!        ----------------
1057
!
1058
         IF( ASSOCIATED( self % model % innerBoundaries ) )     THEN
×
1059
            curveIterator => self % model % innerBoundariesIterator
×
1060
            ALLOCATE(segmentedIterator)
×
NEW
1061
            CALL segmentedIterator % initWithFTLinkedListClass(sizer % innerBoundariesList)
×
1062

1063
            CALL curveIterator % setToStart()
×
1064
            CALL segmentedIterator % setToStart()
×
1065

1066
            DO WHILE (.NOT.curveIterator % isAtEnd())
×
1067
               obj     => curveIterator % object()
×
1068
               CALL castToSMChainedCurve(obj,innerCurveChain)
×
1069

1070
               obj     => segmentedIterator % object()
×
1071
               CALL castToChainedSegmentedCurve(obj,innerSegmentedCurveChain)
×
1072

1073
               DO j = 1, innerSegmentedCurveChain % curveCount()
×
1074
                  cCurve   => innerCurveChain % curveAtIndex(j)
×
1075
                  frsCurve => innerSegmentedCurveChain % segmentedCurveAtIndex(j)
×
1076
                  CALL ResizeFRSegmentedCurve(self = frsCurve, curve = cCurve)
×
1077
               END DO
1078

1079
               CALL curveIterator % moveToNext()
×
1080
               CALL segmentedIterator % moveToNext()
×
1081
            END DO
1082
         END IF
1083

UNCOV
1084
      END SUBROUTINE ResizeSegmentedCurves
×
1085
!
1086
!////////////////////////////////////////////////////////////////////////
1087
!
1088
      SUBROUTINE ResetInverseScales( self, needsRemesh )
24✔
1089
      USE MultiSegmentCurveClass
1090
!
1091
!     -----------------------------------------------------------
1092
!     From the errors computed along the boundaries, reset the
1093
!     invScale values along the segmented curves to help meet
1094
!     the project's error tolerance. Previous calls to
1095
!     ComputeBoundaryApproximations and ComputeBoundaryErrors
1096
!     must be made before calling this procedure, or nothing will
1097
!     happen.
1098
!     -----------------------------------------------------------
1099
!
1100
         IMPLICIT NONE
1101
!
1102
!        ---------
1103
!        Arguments
1104
!        ---------
1105
!
1106
         TYPE (MeshProject) :: self
1107
         LOGICAL            :: needsRemesh
1108
!
1109
!        ---------------
1110
!        Local variables
1111
!        ---------------
1112
!
1113
         CLASS(MeshSizer)            , POINTER :: sizer
1114
         CLASS(FRSegmentedCurve)     , POINTER :: frsCurve
1115
         CLASS(SMChainedCurve)       , POINTER :: outerBoundary
1116
         CLASS(SMCurve)              , POINTER :: cCurve
1117
         CLASS(FTLinkedListIterator) , POINTER :: curveIterator, segmentedIterator
1118
         CLASS(FTObject)             , POINTER :: obj
1119
         CLASS(SMChainedCurve)       , POINTER :: innerCurveChain
1120
         CLASS(ChainedSegmentedCurve), POINTER :: innerSegmentedCurveChain
1121
         CLASS(MultiSegmentCurve)    , POINTER :: boundaryPolynomial
1122
         INTEGER                               :: j, curveID
1123
         REAL(KIND=RP), ALLOCATABLE            :: hFactorArray(:)
24✔
1124
         REAL(KIND=RP)                         :: aMap(2), d
1125
!
1126
!        -----------------------------------------------------------
1127
!        Do nothing if errors are not available by previous calls
1128
!        to ComputeBoundaryApproximations and ComputeBoundaryErrors
1129
!        -----------------------------------------------------------
1130
!
1131
         needsRemesh = .FALSE.
24✔
1132
         IF(.NOT.ALLOCATED(self % H1BoundaryError)) RETURN
24✔
1133

1134
         sizer => self % sizer
24✔
1135
!
1136
!        --------------
1137
!        Outer boundary
1138
!        --------------
1139
!
1140
         IF ( ASSOCIATED( self % model % outerBoundary) )     THEN
24✔
1141
!
1142
!           ------------------------------------------------------
1143
!           Segmented chained curve along outer boundary, chain of
1144
!           FRSegmented curves
1145
!           ------------------------------------------------------
1146
!
1147
            outerBoundary => self % model % outerBoundary
20✔
1148
            curveID = outerBoundary % id()
20✔
1149
!
1150
!           ------------------------------------------
1151
!           The model curve associated with this chain
1152
!           Only resize if the bound is requested
1153
!           ------------------------------------------
1154
!
1155
            obj => self % model % allChains % objectAtIndex(curveID)
20✔
1156
            CALL castToSMChainedCurve(obj, outerBoundary)
20✔
1157

1158
            IF(outerBoundary % optimization .ne. NONE) THEN
20✔
1159
!
1160
!              -------------------------------------------------------------
1161
!              The boundary polynomials are segmented curves along which the
1162
!              error norms have been computed
1163
!              -------------------------------------------------------------
1164
!
NEW
1165
               obj => self % boundaryPolynomialsArray % objectAtIndex(curveID)
×
NEW
1166
               CALL castObjToMultiSegmentCurve(obj,boundaryPolynomial)
×
1167
!
1168
!              ---------------------------------------------------
1169
!              For each segmented curve in the boundary chain
1170
!              adjust the local scale according to the size of the
1171
!              error
1172
!              ---------------------------------------------------
1173
!
NEW
1174
               IF ( outerBoundary % optimization == L2_NORM )     THEN
×
NEW
1175
                  hFactorArray = self % L2BoundaryError(curveID) % array
×
1176
               ELSE
NEW
1177
                  hFactorArray = self % H1BoundaryError(curveID) % array
×
1178
               END IF
1179
               CALL ComputeNewSizeFactor(hFactorArray, self % runParams % polynomialOrder, &
NEW
1180
                                         outerBoundary % tolerance)
×
1181
!
1182
!              --------------------------------------------------------------
1183
!              Apply the boundary factor to the current scales stored in the
1184
!              FTSegmented curve in the sizer
1185
!              --------------------------------------------------------------
1186
!
NEW
1187
               IF ( MAXVAL(hFactorArray) > 1.0_RP )     THEN
×
NEW
1188
                   needsRemesh = .TRUE.
×
NEW
1189
                   d = REAL(sizer % outerBoundary % curveCount(),RP)
×
NEW
1190
                   DO j = 1, sizer % outerBoundary % curveCount()
×
NEW
1191
                     aMap     = [REAL(j-1,RP)/d, 1.0_RP/d]
×
NEW
1192
                     frsCurve => sizer % outerBoundary % segmentedCurveAtIndex(j)
×
NEW
1193
                     CALL RescaleFRSegmentedCurve(frsCurve, hFactorArray, aMap, boundaryPolynomial % cuts)
×
1194
                  END DO
1195
               END IF
1196

NEW
1197
               DEALLOCATE(hFactorArray)
×
1198
            END IF
1199

1200
         END IF
1201
!
1202
!        ----------------
1203
!        Inner boundaries
1204
!        ----------------
1205
!
1206
         IF( ASSOCIATED( self % model % innerBoundaries ) )     THEN
24✔
1207
!
1208
!           ------------------------------------------------------------
1209
!           innerBoundaries is a linked list. Step through each boundary
1210
!           and the associated segmented curves
1211
!           ------------------------------------------------------------
1212
!
1213
            curveIterator => self % model % innerBoundariesIterator
10✔
1214
            ALLOCATE(segmentedIterator)
10✔
1215
            CALL segmentedIterator % initWithFTLinkedListClass(sizer % innerBoundariesList)
10✔
1216

1217
            CALL curveIterator % setToStart()
10✔
1218
            CALL segmentedIterator % setToStart()
10✔
1219
!
1220
!           ---------------------------
1221
!           For each curve in the model
1222
!           ---------------------------
1223
!
1224
            DO WHILE (.NOT.curveIterator % isAtEnd())
43✔
1225
!
1226
!              ----------------
1227
!              Access the curve
1228
!              ----------------
1229
!
1230
               obj     => curveIterator % object()
33✔
1231
               CALL castToSMChainedCurve(obj,innerCurveChain)
33✔
1232
               curveID = innerCurveChain % id()
33✔
1233
!
1234
!              ----------------------------------
1235
!              And its associated segmented curve
1236
!              ----------------------------------
1237
!
1238
               obj     => segmentedIterator % object()
33✔
1239
               CALL castToChainedSegmentedCurve(obj,innerSegmentedCurveChain)
33✔
1240

1241
               IF(innerCurveChain % optimization .ne. NONE) THEN
33✔
1242
!
1243
!                 -------------------------------------------------------------
1244
!                 The boundary polynomials are segmented curves along which the
1245
!                 error norms have been computed
1246
!                 -------------------------------------------------------------
1247
!
NEW
1248
                  obj => self % boundaryPolynomialsArray % objectAtIndex(curveID)
×
NEW
1249
                  CALL castObjToMultiSegmentCurve(obj,boundaryPolynomial)
×
1250
!
1251
!                 ---------------------------------------------------
1252
!                 For each segmented curve in the boundary chain
1253
!                 adjust the local scale according to the size of the
1254
!                 error
1255
!                 ---------------------------------------------------
1256
!
NEW
1257
                  IF ( innerCurveChain % optimization == L2_NORM )     THEN
×
NEW
1258
                     hFactorArray = self % L2BoundaryError(curveID) % array
×
1259
                  ELSE
NEW
1260
                     hFactorArray = self % H1BoundaryError(curveID) % array
×
1261
                  END IF
1262
                  CALL ComputeNewSizeFactor(hFactorArray, self % runParams % polynomialOrder, &
NEW
1263
                                            innerCurveChain % tolerance)
×
1264
!
1265
!                 --------------------------------------------------------------
1266
!                 Apply the boundary factor to the current scales stored in the
1267
!                 FTSegmented curve in the sizer
1268
!                 --------------------------------------------------------------
1269
!
NEW
1270
                  IF ( MAXVAL(hFactorArray) > 1.0_RP )     THEN
×
NEW
1271
                      needsRemesh = .TRUE.
×
NEW
1272
                      d = REAL(innerSegmentedCurveChain % curveCount(),RP)
×
NEW
1273
                      DO j = 1, innerSegmentedCurveChain % curveCount()
×
NEW
1274
                        aMap     = [REAL(j-1,RP)/d, 1.0_RP/d]
×
NEW
1275
                        frsCurve => innerSegmentedCurveChain % segmentedCurveAtIndex(j)
×
NEW
1276
                        CALL RescaleFRSegmentedCurve(frsCurve, hFactorArray, aMap, boundaryPolynomial % cuts)
×
1277
                     END DO
1278
                  END IF
1279

NEW
1280
                  DEALLOCATE(hFactorArray)
×
1281
               END IF
1282

1283
               CALL curveIterator % moveToNext()
33✔
1284
               CALL segmentedIterator % moveToNext()
33✔
1285
            END DO
1286
         END IF
1287
         !TODO Add interface boundaries
1288

1289
      END SUBROUTINE ResetInverseScales
24✔
1290
!
1291
!////////////////////////////////////////////////////////////////////////
1292
!
NEW
1293
      SUBROUTINE ComputeNewSizeFactor(hFactorArray, N, tol)
×
1294
         IMPLICIT NONE
1295
!
1296
!        ---------
1297
!        Arguments
1298
!        ---------
1299
!
1300
         REAL(KIND=RP) :: hFactorArray(:)
1301
         INTEGER       :: N
1302
         REAL(KIND=RP) :: tol
1303
!
1304
!        ---------------
1305
!        Local Variables
1306
!        ---------------
1307
!
1308
         INTEGER       :: j
1309
         REAL(KIND=RP) :: alpha
1310
         REAL(KIND=RP) :: q
1311
         INTEGER       :: ip
1312
!
1313
!        -----------------------------------------------------------------------
1314
!        Under the assumption for smooth functions that the error varies as h^p,
1315
!        estimate the factor by which the element size needs to be reduced for
1316
!        the error to match the tolerance, tol. If the error for any index is
1317
!        already less than the tolerance, then set the factor to unity so that
1318
!        nothing will change. Since the grid refinement works in powers of two,
1319
!        the factor is chosen to trigger the next factor of two refinement.
1320
!        Since it will be used on the inverse scale length, the reciprocal of
1321
!        the factor is computed and stored.
1322
!        -----------------------------------------------------------------------
1323
!
NEW
1324
         DO j = 1, SIZE(hFactorArray)
×
NEW
1325
            alpha = hFactorArray(j)/tol
×
NEW
1326
            IF(alpha .le. 1.0_RP)  THEN
×
NEW
1327
               hFactorArray(j) = 1.0_RP
×
1328
            ELSE
NEW
1329
               alpha           = alpha**(1.0_RP/N)
×
NEW
1330
               q               = LOG(alpha)/LOG(2.0_RP)
×
NEW
1331
               ip              = CEILING(q)
×
NEW
1332
               alpha           = 2.0_RP**ip !+ 1.0_RP
×
NEW
1333
               hFactorArray(j) = alpha
×
1334
            END IF
1335
         END DO
1336

NEW
1337
      END SUBROUTINE ComputeNewSizeFactor
×
1338
!
1339
!////////////////////////////////////////////////////////////////////////
1340
!
NEW
1341
      SUBROUTINE RescaleFRSegmentedCurve(frsCurve, hFactorArray, aMap, cuts)
×
1342
!
1343
!        ---------------------------------------------------------------
1344
!        For each point along the segmented curve, find the scale factor
1345
!        in the hFactor array for that location and adjust the invScale
1346
!        accordingly
1347
!        ---------------------------------------------------------------
1348
!
1349
         USE IntervalSearchModule
1350
         IMPLICIT NONE
1351
!
1352
!        ---------
1353
!        Arguments
1354
!        ---------
1355
!
1356
         CLASS(FRSegmentedCurve), POINTER :: frsCurve
1357
         REAL(KIND=RP)                    :: hFactorArray(:)
1358
         REAL(KIND=RP)                    :: aMap(2)
1359
         REAL(KIND=RP)                    :: cuts(0:)
1360
!
1361
!        ---------------
1362
!        Local variables
1363
!        ---------------
1364
!
1365
         INTEGER       :: j, k
1366
         REAL(KIND=RP) :: t, s
1367

NEW
1368
         DO j = 1, frsCurve % COUNT()
×
NEW
1369
            s = frsCurve % argumentAtIndex(j) !Local location along this curve
×
NEW
1370
            t = aMap(1) + s*aMap(2)           !Affine map to the chain curve location
×
NEW
1371
            k = findInterval(cuts, t)
×
NEW
1372
            s = frsCurve % invScaleAtIndex(j)
×
NEW
1373
            s = s*hFactorArray(k)
×
NEW
1374
            CALL frsCurve % setCurveInvScaleForIndex(s,j)
×
1375
         END DO
1376

NEW
1377
      END SUBROUTINE RescaleFRSegmentedCurve
×
1378
!
1379
!////////////////////////////////////////////////////////////////////////
1380
!
1381
      SUBROUTINE BuildbackgroundGridFromModel( backgroundGrid, model, backgroundGridSize )
20✔
1382
!
1383
!     -----------------------------------------------------------------------
1384
!     This routine will take the background grid size and the model to
1385
!     generate a background mesh that bounds the outer boundary of the model.
1386
!     -----------------------------------------------------------------------
1387
!
1388
         USE CurveConversionsModule
1389
         IMPLICIT NONE
1390
!
1391
!        ---------
1392
!        Arguments
1393
!        ---------
1394
!
1395
         TYPE(BackgroundGridParameters) :: backgroundGrid
1396
         CLASS(SMModel)                 :: model
1397
         REAL(KIND=RP)                  :: backgroundGridSize(3)
1398
!
1399
!        ---------------
1400
!        Local variables
1401
!        ---------------
1402
!
1403
         CLASS(ChainedSegmentedCurve), POINTER :: segmentedOuterBoundary => NULL()
1404
         INTEGER                               :: curveID
1405
         CHARACTER(LEN=128)                    :: msg
1406
         CLASS(FTLinkedList)         , POINTER :: controlsList => NULL()
1407

1408
         INTEGER       :: nX, nY
1409
         REAL(KIND=RP) :: heightB, widthB
1410
         REAL(KIND=RP) :: leftB, rightB, topB, bottomB, h
1411

1412
         leftB   = HUGE(leftB)
20✔
1413
         rightB  = -leftB
20✔
1414
         topB    =  rightB
20✔
1415
         bottomB =  leftB
20✔
1416
         controlsList => NULL()
20✔
1417
!
1418
!        ----------------------------------------------------
1419
!        Create a discrete curve to determine the extents of
1420
!        the background mesh
1421
!        ----------------------------------------------------
1422
!
1423
         h = MAXVAL( backgroundGridSize(1:2) )
60✔
1424
         IF( ASSOCIATED( model % outerBoundary ) )     THEN
20✔
1425
            curveID = 1
20✔
1426
            segmentedOuterBoundary => allocAndInitSegmentedChainFromChain( model % outerBoundary, curveID, h, controlsList )
20✔
1427
!
1428
!           ----------------------------------
1429
!           Find the bounds on the outer curve
1430
!           ----------------------------------
1431
!
1432
            leftB   = segmentedOuterBoundary % boundingBox(BBOX_LEFT)
20✔
1433
            rightB  = segmentedOuterBoundary % boundingBox(BBOX_RIGHT)
20✔
1434
            topB    = segmentedOuterBoundary % boundingBox(BBOX_TOP)
20✔
1435
            bottomB = segmentedOuterBoundary % boundingBox(BBOX_BOTTOM)
20✔
1436
         ELSE
1437
            msg = "To automatically create background grid, the model needs an outer boundary curve"
×
1438
            CALL ThrowErrorExceptionOfType(poster = "BuildbackgroundGridFromModel",msg = msg,typ = FT_ERROR_FATAL)
×
1439
            RETURN
×
1440
         END IF
1441
!
1442
!        ---------------------------
1443
!        Compute the background grid
1444
!        ---------------------------
1445
!
1446
         widthB    = rightB  - leftB
20✔
1447
         heightB   = topB    - bottomB
20✔
1448
         leftB     = leftB   - backgroundGridSize(1)
20✔
1449
         bottomB   = bottomB - backgroundGridSize(2)
20✔
1450
         nX        = INT(widthB/backgroundGridSize(1)) + 2
20✔
1451
         nY        = INT(heightB/backgroundGridSize(2)) + 2
20✔
1452

1453
         backgroundGrid % N  = (/nX, nY, 0/)
80✔
1454
         backgroundGrid % dx = backgroundGridSize
80✔
1455
         backgroundGrid % x0 = (/leftB, bottomB, 0.0_RP /)
80✔
1456

1457
      END SUBROUTINE BuildbackgroundGridFromModel
20✔
1458
!@mark -
1459
!
1460
!////////////////////////////////////////////////////////////////////////
1461
!
1462
      SUBROUTINE SetRunParametersBlock( params, controlDict )
24✔
1463
!
1464
!        Example block is:
1465
!
1466
!         \begin{RunParameters}
1467
!            model file name = "model.gm"
1468
!            mesh file name = "fname.mesh"
1469
!            stats file name = "fname.txt" (Optional)
1470
!            mesh file format = "Basic", ...
1471
!            plot file name = "tName.tec"  (Optional)
1472
!            plot file format = "skeleton" OR "sem"
1473
!         \end{RunParameters}
1474
!
1475
         IMPLICIT NONE
1476
!
1477
!        ---------
1478
!        Arguments
1479
!        ---------
1480
!
1481
         TYPE(RunParameters)               :: params
1482
         CLASS(FTValueDictionary), POINTER :: controlDict
1483
!
1484
!        ---------------
1485
!        Local variables
1486
!        ---------------
1487
!
1488
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: fileFormat
1489
         CLASS(FTValueDictionary), POINTER       :: paramsDict
1490
         CLASS(FTObject)         , POINTER       :: obj
1491
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: msg
1492

1493
         obj        => controlDict % objectForKey(key = RUN_PARAMETERS_KEY)
24✔
1494
         IF ( .NOT. ASSOCIATED(obj) )     THEN
24✔
1495
            msg = "Control file is missing the block: " // TRIM(RUN_PARAMETERS_KEY)
×
1496
            CALL ThrowErrorExceptionOfType(poster = "SetRunParametersBlock", &
1497
                                           msg    = msg,                     &
1498
                                           typ    = FT_ERROR_FATAL)
×
1499
            RETURN
×
1500
         END IF
1501

1502
         paramsDict => valueDictionaryFromObject(obj)
24✔
1503

1504
         params % MeshFileName = "MeshFile.mesh"
24✔
1505
         msg = "Control file is missing the Mesh file name. Using default name, MeshFile.mesh."
24✔
1506
         CALL SetStringValueFromDictionary(valueToSet = params % MeshFileName,  &
1507
                                           sourceDict = paramsDict,             &
1508
                                           key        = MESH_FILE_NAME_KEY,     &
1509
                                           errorLevel = FT_ERROR_WARNING,       &
1510
                                           message    = msg,                    &
1511
                                           poster     = "SetRunParametersBlock")
24✔
1512

1513

1514
         params % plotFileName = "PlotFile.tec"
24✔
1515
         msg = "Control file is missing the plot file name. Using default name, PlotFile.tec."
24✔
1516
         CALL SetStringValueFromDictionary(valueToSet = params % plotFileName,  &
1517
                                           sourceDict = paramsDict,             &
1518
                                           key        = PLOT_FILE_NAME_KEY,     &
1519
                                           errorLevel = FT_ERROR_WARNING,       &
1520
                                           message    = msg,                    &
1521
                                           poster     = "SetRunParametersBlock")
24✔
1522

1523
         params % statsFileName = "none"
24✔
1524
         msg = "Control file is missing the stats file name. Stats not written."
24✔
1525
         CALL SetStringValueFromDictionary(valueToSet = params % statsFileName, &
1526
                                           sourceDict = paramsDict,             &
1527
                                           key        = STATS_FILE_NAME_KEY,    &
1528
                                           errorLevel = FT_ERROR_WARNING,       &
1529
                                           message    = msg,                    &
1530
                                           poster     = "SetRunParametersBlock")
24✔
1531

1532
         msg = "Unknown mesh file format or mesh file format not set. Set to ISM"
24✔
1533
         CALL SetStringValueFromDictionary(valueToSet = fileFormat,                &
1534
                                           sourceDict = paramsDict,                &
1535
                                           key        = MESH_FILE_FORMAT_NAME_KEY, &
1536
                                           errorLevel = FT_ERROR_WARNING,          &
1537
                                           message    = msg,                       &
1538
                                           poster     = "SetRunParametersBlock")
24✔
1539
!
1540
!        --------------------------------------------------------------------------------
1541
!        For now, no warnings or anything for not requesting the errors to be written out
1542
!        --------------------------------------------------------------------------------
1543
!
1544
         params % errorFileName = "none"
24✔
1545
         msg = "Control file is missing the errors file name. Errors not written."
24✔
1546
         CALL SetStringValueFromDictionary(valueToSet = params % errorFileName, &
1547
                                           sourceDict = paramsDict,             &
1548
                                           key        = ERROR_FILE_NAME_KEY,    &
1549
                                           errorLevel = FT_ERROR_NONE,          &
1550
                                           message    = msg,                    &
1551
                                           poster     = "SetRunParametersBlock")
24✔
1552

1553
         IF( fileFormat == "Basic" )     THEN
24✔
1554
            params % meshFileFormat = BASIC_MESH_FORMAT
×
1555
         ELSE IF ( fileFormat == "BasicWithEdges" )     THEN
24✔
1556
            params % meshFileFormat = BASIC_PLUS_EDGES_FORMAT
×
1557
         ELSE IF( fileFormat == "ISM" .OR. fileFormat == "ISM-V1" )     THEN
24✔
1558
            params % meshFileFormat = ISM
20✔
1559
         ELSE IF( fileFormat == "ISM-v2" .OR. fileFormat == "ISM-V2" )     THEN
4✔
1560
            params % meshFileFormat = ISM2
1✔
1561
         ELSE IF( fileFormat == "ISM-MM" )     THEN
3✔
1562
            params % meshFileFormat = ISM_MM
1✔
1563
         ELSE IF( fileFormat == "ABAQUS" )     THEN
2✔
1564
            params % meshFileFormat = ABAQUS
2✔
1565
         ELSE
1566
            params % meshFileFormat = ISM
×
1567
         END IF
1568

1569
         msg = "Control file is missing the polynomial order. Using default N = 5."
24✔
1570
         params % polynomialOrder = 5
24✔
1571
         CALL SetIntegerValueFromDictionary(valueToSet = params % polynomialOrder, &
1572
                                           sourceDict = paramsDict,               &
1573
                                           key        = POLYNOMIAL_ORDER_KEY,     &
1574
                                           errorLevel = FT_ERROR_WARNING,         &
1575
                                           message    = msg,                      &
1576
                                           poster     = "SetRunParametersBlock")
24✔
1577

1578
         msg        = "Unknown plot file format or plot file format not set. Set to skeleton"
24✔
1579
         fileFormat = "skeleton"
24✔
1580
         CALL SetStringValueFromDictionary(valueToSet = fileFormat,                &
1581
                                           sourceDict = paramsDict,                &
1582
                                           key        = PLOT_FORMAT_KEY, &
1583
                                           errorLevel = FT_ERROR_WARNING,          &
1584
                                           message    = msg,                       &
1585
                                           poster     = "SetRunParametersBlock")
24✔
1586
         IF ( fileFormat == "skeleton" )     THEN
24✔
1587
            params % plotFileFormat = SKELETON_FORMAT
22✔
1588
         ELSE IF(fileFormat == "sem")     THEN
2✔
1589
            params % plotFileFormat = SEM_FORMAT
2✔
1590
         ELSE
1591
            params % plotFileFormat = SEM_FORMAT
×
1592
         END IF
1593

1594
      END SUBROUTINE SetRunParametersBlock
20✔
1595
!
1596
!////////////////////////////////////////////////////////////////////////
1597
!
1598
      SUBROUTINE SetMeshParametersBlock( params, controlDict )
24✔
1599
!
1600
!        Example block is:
1601
!
1602
!         \begin{MESH_PARAMETERS}
1603
!            element type = quad OR hex
1604
!         \end{MESH_PARAMETERS}
1605
!
1606
         IMPLICIT NONE
1607
!
1608
!        ---------
1609
!        Arguments
1610
!        ---------
1611
!
1612
         TYPE(MeshParameters)              :: params
1613
         CLASS(FTValueDictionary), POINTER :: controlDict
1614
!
1615
!        ---------------
1616
!        Local variables
1617
!        ---------------
1618
!
1619
         CLASS(FTValueDictionary), POINTER       :: paramsDict
1620
         CLASS(FTObject)         , POINTER       :: obj
1621

1622
         obj        => controlDict % objectForKey(key = MESH_PARAMETERS_KEY)
24✔
1623
         paramsDict => valueDictionaryFromObject(obj)
24✔
1624
!
1625
!        ---------------------------
1626
!        Mesh parameters is optional
1627
!        ---------------------------
1628
!
1629
         params % meshType = 0! CONFORMING
24✔
1630
         IF(.NOT.ASSOCIATED(paramsDict)) THEN
24✔
1631
            params % meshType = 0! CONFORMING
16✔
1632
         END IF
1633

1634
      END SUBROUTINE SetMeshParametersBlock
24✔
1635
!
1636
!////////////////////////////////////////////////////////////////////////
1637
!
1638
      SUBROUTINE SetBackgroundGridBlock( backgroundGrid, backgroundGridDict )
24✔
1639
!
1640
!        Example block is:
1641
!
1642
!         \begin{BACKGROUND_GRID}
1643
!            x0 = [-15.0, -15.0, 0.0]
1644
!            dx = [1.0, 1.0, 0.0]
1645
!            N  = [10,10, 0]
1646
!         \end{BACKGROUND_GRID}
1647
!
1648
!         OR
1649
!
1650
!         \begin{BACKGROUND_GRID}
1651
!            background grid size = [1.0, 1.0, 1.0]
1652
!         \end{BACKGROUND_GRID}
1653
!
1654
!
1655
         IMPLICIT NONE
1656
!
1657
!        ---------
1658
!        Arguments
1659
!        ---------
1660
!
1661
         CLASS(FTValueDictionary), POINTER :: backgroundGridDict
1662
         TYPE(BackgroundGridParameters)    :: backgroundGrid
1663
!
1664
!        ---------------
1665
!        Local variables
1666
!        ---------------
1667
!
1668
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: msg
1669
!
1670
!
1671
!        ----------
1672
!        Interfaces
1673
!        ----------
1674
!
1675
         LOGICAL, EXTERNAL :: ReturnOnFatalError
1676
!
1677
!        ------------------------------------------------
1678
!
1679
!
1680
!        ---------
1681
!        Mesh size
1682
!        ---------
1683
!
1684
         IF ( backgroundGridDict % containsKey(key = GRID_SIZE_KEY) )     THEN
24✔
1685
            msg      = "Control file is missing the mesh size."
20✔
1686
            CALL SetRealArrayValueFromDictionary(arrayToSet = backgroundGrid % backgroundGridSize, &
1687
                                                 sourceDict = backgroundGridDict,                  &
1688
                                                 key        = GRID_SIZE_KEY,                       &
1689
                                                 errorLevel = FT_ERROR_NONE,                       &
1690
                                                 message    = msg,                                 &
1691
                                                 poster     = "SetBackgroundGridBlock")
20✔
1692
         ELSE
1693
            msg = "Background grid block missing parameter " // TRIM(X_START_NAME_KEY)
4✔
1694
            CALL SetRealArrayValueFromDictionary(arrayToSet =  backgroundGrid % x0,      &
1695
                                                 sourceDict = backgroundGridDict,        &
1696
                                                 key        = X_START_NAME_KEY,          &
1697
                                                 errorLevel = FT_ERROR_FATAL,            &
1698
                                                 message    = msg,                       &
1699
                                                 poster     = "SetBackgroundGridBlock")
4✔
1700
            IF(ReturnOnFatalError()) RETURN
4✔
1701

1702
            msg = "Background grid block missing parameter " // TRIM(DX_NAME_KEY)
4✔
1703
            CALL SetRealArrayValueFromDictionary(arrayToSet = backgroundGrid % dx,       &
1704
                                                 sourceDict = backgroundGridDict,        &
1705
                                                 key        = DX_NAME_KEY,               &
1706
                                                 errorLevel = FT_ERROR_FATAL,            &
1707
                                                 message    = msg,                       &
1708
                                                 poster     = "SetBackgroundGridBlock")
4✔
1709
            IF(ReturnOnFatalError()) RETURN
4✔
1710

1711
            msg = "Background grid block missing parameter " // TRIM(NUM_INTERVALS_NAME_KEY)
4✔
1712
            CALL SetIntegerArrayValueFromDictionary(arrayToSet = backgroundGrid % N,        &
1713
                                                    sourceDict = backgroundGridDict,        &
1714
                                                    key        = NUM_INTERVALS_NAME_KEY,    &
1715
                                                    errorLevel = FT_ERROR_FATAL,            &
1716
                                                    message    = msg,                       &
1717
                                                    poster     = "SetBackgroundGridBlock")
4✔
1718
            IF(ReturnOnFatalError()) RETURN
4✔
1719
         END IF
1720

1721
      END SUBROUTINE SetBackgroundGridBlock
1722
!
1723
!////////////////////////////////////////////////////////////////////////
1724
!
1725
      SUBROUTINE SetCenterMeshSizerBlock( centerParams, centerDict )
2✔
1726
!
1727
!        Example block is:
1728
!
1729
!         \begin{RefinementCenter}
1730
!            type = "smooth"
1731
!            x0 = [0.0,0.0, 0.0]
1732
!            h  = 0.1
1733
!            w  = 0.5
1734
!         \end{RefinementCenter}
1735
!
1736
      IMPLICIT NONE
1737
!
1738
!        ---------
1739
!        Arguments
1740
!        ---------
1741
!
1742
         CLASS(FTValueDictionary), POINTER :: centerDict
1743
         TYPE(CentersParameters)           :: centerParams
1744
!
1745
!        ----------
1746
!        Interfaces
1747
!        ----------
1748
!
1749
         logical, EXTERNAL :: ReturnOnFatalError
1750
!
1751
!        ----------------
1752
!        Local variables
1753
!        ---------------
1754
!
1755
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str, msg
1756
!
1757
!        ---------------------------------
1758
!        Smooth OR sharp center variation
1759
!        ---------------------------------
1760
!
1761
         str = "smooth"
2✔
1762
         msg = "Refinement center block missing smooth parameter. Using default smooth"
2✔
1763
         CALL SetStringValueFromDictionary(valueToSet = str,              &
1764
                                           sourceDict = centerDict,       &
1765
                                           key = TYPE_NAME_KEY,           &
1766
                                           errorLevel = FT_ERROR_WARNING, &
1767
                                           message = msg,                 &
1768
                                           poster = "SetCenterMeshSizerBlock")
2✔
1769

1770
         IF( str == "smooth" )     THEN
2✔
1771
            centerParams % centerType = CENTER_SMOOTH
2✔
1772
         ELSE
1773
            centerParams % centerType = CENTER_SHARP
×
1774
         END IF
1775
!
1776
!        --------
1777
!        Location
1778
!        --------
1779
!
1780
         msg = "Refinement center block missing parameter " // TRIM(X_START_NAME_KEY)
2✔
1781
         CALL SetRealArrayValueFromDictionary(arrayToSet = centerParams % x0,         &
1782
                                              sourceDict = centerDict,                &
1783
                                              key        = X_START_NAME_KEY,          &
1784
                                              errorLevel = FT_ERROR_FATAL,            &
1785
                                              message    = msg,                       &
1786
                                              poster     = "SetCenterMeshSizerBlock")
2✔
1787
         IF(ReturnOnFatalError()) RETURN
2✔
1788
!
1789
!        -----
1790
!        Size
1791
!        -----
1792
!
1793
         msg = "Refinement center block missing parameter " // TRIM(SPACING_NAME_KEY)
2✔
1794
         CALL SetRealValueFromDictionary(valueToSet = centerParams % centerMeshSize, &
1795
                                         sourceDict = centerDict,                    &
1796
                                         key        = SPACING_NAME_KEY,              &
1797
                                         errorLevel = FT_ERROR_FATAL,                &
1798
                                         message    = msg,                           &
1799
                                         poster     = "SetCenterMeshSizerBlock")
2✔
1800
         IF(ReturnOnFatalError()) RETURN
2✔
1801
!
1802
!        ------
1803
!        Extent
1804
!        ------
1805
!
1806
         msg = "Refinement center block missing parameter " // TRIM(EXTENT_NAME_KEY)
2✔
1807
         CALL SetRealValueFromDictionary(valueToSet = centerParams % centerExtent,   &
1808
                                         sourceDict = centerDict,                    &
1809
                                         key        = EXTENT_NAME_KEY,               &
1810
                                         errorLevel = FT_ERROR_FATAL,                &
1811
                                         message    = msg,                           &
1812
                                         poster     = "SetCenterMeshSizerBlock")
2✔
1813
         IF(ReturnOnFatalError()) RETURN
2✔
1814

1815
      END SUBROUTINE SetCenterMeshSizerBlock
1816
!
1817
!////////////////////////////////////////////////////////////////////////
1818
!
1819
      SUBROUTINE SetLineMeshSizerBlock( lineParams, lineSizerDict )
1✔
1820
!
1821
!        Example block is:
1822
!
1823
!         \begin{Refinementline}
1824
!            type = "smooth"
1825
!            x0 = [0.0,0.0, 0.0]
1826
!            x1 = [1.0,1.0, 0.0]
1827
!            h  = 0.1
1828
!            w  = 0.5
1829
!         \end{Refinementline}
1830
!
1831
      IMPLICIT NONE
1832
!
1833
!        ---------
1834
!        Arguments
1835
!        ---------
1836
!
1837
         CLASS(FTValueDictionary), POINTER :: lineSizerDict
1838
         TYPE(lineParameters)              :: lineParams
1839
!
1840
!        ----------
1841
!        Interfaces
1842
!        ----------
1843
!
1844
         logical, EXTERNAL :: ReturnOnFatalError
1845
!
1846
!        ---------------
1847
!        Local variables
1848
!        ---------------
1849
!
1850
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str, msg
1851
!
1852
!        --------------------
1853
!        Smooth or sharp type
1854
!        --------------------
1855
!
1856
         str = "smooth"
1✔
1857
         msg = "Refinement line block missing smooth type parameter. Using default smooth"
1✔
1858
         CALL SetStringValueFromDictionary(valueToSet = str,                 &
1859
                                           sourceDict = lineSizerDict,       &
1860
                                           key        = TYPE_NAME_KEY,       &
1861
                                           errorLevel = FT_ERROR_WARNING,    &
1862
                                           message    = msg,                 &
1863
                                           poster = "SetLineMeshSizerBlock")
1✔
1864

1865
         IF( str == "smooth" )     THEN
1✔
1866
            lineParams % lineControlType = CENTER_SMOOTH
1✔
1867
         ELSE
1868
            lineParams % lineControlType = CENTER_SHARP
×
1869
         END IF
1870
!
1871
!        --------------
1872
!        Start location
1873
!        --------------
1874
!
1875
         msg = "Refinement line block missing parameter " // TRIM(X_START_NAME_KEY)
1✔
1876
         CALL SetRealArrayValueFromDictionary(arrayToSet = lineParams % x0,           &
1877
                                              sourceDict = lineSizerDict,             &
1878
                                              key        = X_START_NAME_KEY,          &
1879
                                              errorLevel = FT_ERROR_FATAL,            &
1880
                                              message    = msg,                       &
1881
                                              poster     = "SetLineMeshSizerBlock")
1✔
1882
!
1883
!        ------------
1884
!        End location
1885
!        ------------
1886
!
1887
         msg = "Refinement line block missing parameter " // TRIM(X_END_NAME_KEY)
1✔
1888
         CALL SetRealArrayValueFromDictionary(arrayToSet = lineParams % x1,           &
1889
                                              sourceDict = lineSizerDict,             &
1890
                                              key        = X_END_NAME_KEY,            &
1891
                                              errorLevel = FT_ERROR_FATAL,            &
1892
                                              message    = msg,                       &
1893
                                              poster     = "SetLineMeshSizerBlock")
1✔
1894

1895
!
1896
!        ---------
1897
!        Mesh size
1898
!        ---------
1899
!
1900
         msg = "Refinement line block missing parameter " // TRIM(SPACING_NAME_KEY)
1✔
1901
         CALL SetRealValueFromDictionary(valueToSet = lineParams % lineMeshSize  ,   &
1902
                                         sourceDict = lineSizerDict,                 &
1903
                                         key        = SPACING_NAME_KEY,              &
1904
                                         errorLevel = FT_ERROR_FATAL,                &
1905
                                         message    = msg,                           &
1906
                                         poster     = "SetLineMeshSizerBlock")
1✔
1907
!
1908
!        ------
1909
!        Extent
1910
!        ------
1911
!
1912
         msg = "Refinement line block missing parameter " // TRIM(EXTENT_NAME_KEY)
1✔
1913
         CALL SetRealValueFromDictionary(valueToSet = lineParams % lineExtent,       &
1914
                                         sourceDict = lineSizerDict,                 &
1915
                                         key        = EXTENT_NAME_KEY,               &
1916
                                         errorLevel = FT_ERROR_FATAL,                &
1917
                                         message    = msg,                           &
1918
                                         poster     = "SetLineMeshSizerBlock")
1✔
1919

1920
      END SUBROUTINE SetLineMeshSizerBlock
1✔
1921
!
1922
!////////////////////////////////////////////////////////////////////////
1923
!
1924
      SUBROUTINE SetScaleTransformBlock(scaleBlockDict, scaleTransformer)
×
1925
         IMPLICIT NONE
1926
!
1927
!        ---------
1928
!        Arguments
1929
!        ---------
1930
!
1931
         CLASS(FTValueDictionary), POINTER :: scaleBlockDict
1932
         TYPE(ScaleTransform)              :: scaleTransformer
1933
!
1934
!        ---------------
1935
!        Local Variables
1936
!        ---------------
1937
!
1938
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: msg
1939
         REAL(KIND=RP)                           :: s, c(3)
1940
!
1941
!        ----------
1942
!        Interfaces
1943
!        ----------
1944
!
1945
         logical, EXTERNAL :: ReturnOnFatalError
1946
!
1947
!        ------
1948
!        Origin
1949
!        ------
1950
!
1951
         msg = "Scale transform block missing parameter " // TRIM(SCALE_TRANSFORM_ORIGIN_KEY)
×
1952

1953
         CALL SetRealArrayValueFromDictionary(arrayToSet = c, &
1954
                                              sourceDict = scaleBlockDict,                  &
1955
                                              key        = SCALE_TRANSFORM_ORIGIN_KEY,      &
1956
                                              errorLevel = FT_ERROR_FATAL,                  &
1957
                                              message    = msg,                             &
1958
                                              poster     = "SetScaleTransformBlock")
×
1959
!
1960
!        ------------
1961
!        Scale factor
1962
!        ------------
1963
!
1964
         msg = "Scale transform block missing parameter " // TRIM(SCALE_TRANSFORM_SCALE_KEY)
×
1965
         CALL SetRealValueFromDictionary(valueToSet = s,                             &
1966
                                         sourceDict = scaleBlockDict,                &
1967
                                         key        = SCALE_TRANSFORM_SCALE_KEY,     &
1968
                                         errorLevel = FT_ERROR_FATAL,                &
1969
                                         message    = msg,                           &
1970
                                         poster     = "SetScaleTransformBlock")
×
1971
         IF(ReturnOnFatalError()) RETURN
×
1972

1973
         CALL ConstructScaleTransform(self = scaleTransformer,         &
1974
                                      origin = c,                      &
1975
                                      factor = s,                      &
1976
                                      normal = [0.0_RP,0.0_RP,1.0_RP])
×
1977

1978
      END SUBROUTINE SetScaleTransformBlock
1979
!
1980
!////////////////////////////////////////////////////////////////////////
1981
!
1982
      SUBROUTINE SetRotationTransformBlock(rotationBlockDict, rotationTransformer)
×
1983
         IMPLICIT NONE
1984
!
1985
!        ---------
1986
!        Arguments
1987
!        ---------
1988
!
1989
         CLASS(FTValueDictionary), POINTER :: rotationBlockDict
1990
         TYPE(RotationTransform)             :: rotationTransformer
1991
!
1992
!        ---------------
1993
!        Local Variables
1994
!        ---------------
1995
!
1996
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: msg
1997
         REAL(KIND=RP)                           :: t(3), d(3)
1998
!
1999
!        ----------
2000
!        Interfaces
2001
!        ----------
2002
!
2003
         logical, EXTERNAL :: ReturnOnFatalError
2004
!
2005
!        ------
2006
!        Origin
2007
!        ------
2008
!
2009
         msg = "Rotation transform block missing parameter " // TRIM(ROTATION_TRANSFORM_TRANSLATION_KEY)
×
2010

2011
         CALL SetRealArrayValueFromDictionary(arrayToSet = t, &
2012
                                              sourceDict = rotationBlockDict,                 &
2013
                                              key        = ROTATION_TRANSFORM_TRANSLATION_KEY,&
2014
                                              errorLevel = FT_ERROR_FATAL,                  &
2015
                                              message    = msg,                             &
2016
                                              poster     = "SetRotationTransformBlock")
×
2017
!
2018
!        ------------
2019
!        Direction
2020
!        ------------
2021
!
2022
         msg = "Rotation transform block missing parameter " // TRIM(ROTATION_TRANSFORM_DIRECTION_KEY)
×
2023
         CALL SetRealArrayValueFromDictionary(arrayToSet = d, &
2024
                                              sourceDict = rotationBlockDict,                 &
2025
                                              key        = ROTATION_TRANSFORM_DIRECTION_KEY,  &
2026
                                              errorLevel = FT_ERROR_FATAL,                  &
2027
                                              message    = msg,                             &
2028
                                              poster     = "SetRotationTransformBlock")
×
2029
         IF(ReturnOnFatalError()) RETURN
×
2030

2031
         CALL ConstructRotationTransform(self           = rotationTransformer,        &
2032
                                         rotationPoint  = t,                          &
2033
                                         startDirection = [0.0_RP,0.0_RP,1.0_RP],     &
2034
                                         newDirection   = d)
×
2035

2036
      END SUBROUTINE SetRotationTransformBlock
2037
!
2038
!////////////////////////////////////////////////////////////////////////
2039
!
2040
      SUBROUTINE AddPathToProjectFiles(self, path)
23✔
2041
         IMPLICIT NONE
2042
         CLASS(MeshProject)                      :: self
2043
         CHARACTER(LEN=*)                        :: path
2044
         CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: str
2045

2046
         IF ( path /= "" )     THEN
23✔
2047

2048
            str = self % runParams % MeshFileName
×
2049
            CALL toLower(str)
×
2050
            IF(str /= "none")      THEN
×
2051
               self % runParams % MeshFileName = TRIM(path) // self % runParams % MeshFileName
×
2052
            END IF
2053

2054
            str = self % runParams % plotFileName
×
2055
            CALL toLower(str)
×
2056
            IF(str /= "none")      THEN
×
2057
               self % runParams % plotFileName = TRIM(path) // self % runParams % plotFileName
×
2058
            END IF
2059

2060
            str = self % runParams % statsFileName
×
2061
            CALL toLower(str)
×
2062
            IF(str /= "none")      THEN
×
2063
               self % runParams % statsFileName = TRIM(path) // self % runParams % statsFileName
×
2064
            END IF
2065
         END IF
2066

2067
      END SUBROUTINE AddPathToProjectFiles
23✔
2068

2069
   END MODULE MeshProjectClass
72✔
2070

2071

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