Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/ElmerSolver.F90
5218 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer, A Finite Element Software for Multiphysical Problems
4
! *
5
! * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
! *
7
! * This library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library is distributed in the hope that it will be useful,
13
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
!
24
!/******************************************************************************
25
! *
26
! * ELMER/FEM Solver main program
27
! *
28
! ******************************************************************************
29
! *
30
! * Authors: Juha Ruokolainen
31
! * Email: [email protected]
32
! * Web: http://www.csc.fi/elmer
33
! * Address: CSC - IT Center for Science Ltd.
34
! * Keilaranta 14
35
! * 02101 Espoo, Finland
36
! *
37
! * Original Date: 02 Jun 1997
38
! *
39
! *****************************************************************************/
40
41
!> \defgroup Solvers Dynamically linked solvers
42
43
!> \defgroup UDF Dynamically linked functions
44
45
!> \defgroup Programs Utility programs
46
47
!> \degroup ElmerLib Elmer library routines
48
49
!> \ingroup ElmerLib
50
!> \{
51
52
#include "../config.h"
53
54
!------------------------------------------------------------------------------
55
!> The main program for Elmer. Solves the equations as defined by the input files.
56
!------------------------------------------------------------------------------
57
SUBROUTINE ElmerSolver(initialize, args, NoArgs)
58
!------------------------------------------------------------------------------
59
60
USE Lists
61
USE SParIterGlobals
62
USE ParallelUtils, ONLY : ParallelInit, ParallelFinalize
63
USE ElementUtils, ONLY: FreeMatrix, TangentDirections, CreateMatrix
64
USE ElementDescription, ONLY : InitializeElementDescriptions, NormalVector
65
#ifdef HAVE_EXTOPTIM
66
USE OptimizationUtils, ONLY : ControlParameters, ControlResetMesh, &
67
ExternalOptimization_minpack, ExternalOptimization_newuoa, &
68
ExternalOptimization_bobyqa, GetCostFunction
69
USE ModelDescription , ONLY : SaveResult, OutputPath, InFileUnit, LoadInputFile, &
70
ReloadInputFile, LoadRestartFile, GetProcAddr, LoadModel, FreeModel, WritePostFile, &
71
CompleteModelKeywords, SetIntegerParametersMatc, SetRealParametersMatc, &
72
SetRealParametersKeywordCoeff
73
#else
74
USE OptimizationUtils, ONLY : ControlParameters, ControlResetMesh, GetCostFunction
75
USE ModelDescription , ONLY : SaveResult, OutputPath, InFileUnit, LoadInputFile, &
76
ReloadInputFile, LoadRestartFile, GetProcAddr, LoadModel, FreeModel, WritePostFile, &
77
CompleteModelKeywords, SetIntegerParametersMatc, SetRealParametersMatc
78
#endif
79
USE SolverUtils, ONLY: GetControlValue, FinalizeLumpedMatrix, UpdateExportedVariables, &
80
UpdateIpPerm, VectorValuesRange
81
USE MeshUtils, ONLY : MeshExtrude, MeshExtrudeSlices, &
82
CoordinateTransformation, InitializeElementDescriptions, ReleaseMesh, &
83
CalculateMeshPieces, SetActiveElementsTable, SetCurrentMesh, &
84
MarkSharpEdges, TagBodiesUsingCondition
85
USE MortarUtils, ONLY : PeriodicProjector
86
USE MainUtils, ONLY : AddEquationBasics, AddEquationSolution, AddExecWhenFlag, &
87
PredictorCorrectorControl, SingleSolver, SolveEquations, SolverActivate, &
88
SwapMesh
89
USE DefUtils, ONLY : GetSimulation, GetCompilationDate, GetRevision, GetVersion, GetBranch, &
90
GetReal, GetCReal, GetLogical, GetElementNOFNodes, GetElementDOFs, GetBC, &
91
GetElementFamily, GetElementNodes, VectorElementEdgeDOFs
92
93
IMPLICIT NONE
94
!------------------------------------------------------------------------------
95
96
INTEGER :: Initialize
97
INTEGER :: NoArgs
98
TYPE(ArgStr_t) :: args(:)
99
100
!------------------------------------------------------------------------------
101
! Local variables
102
!------------------------------------------------------------------------------
103
104
INTEGER :: i,j,k,n,l,t,k1,k2,iter,Ndeg,istat,nproc,tlen,nthreads
105
CHARACTER(LEN=MAX_STRING_LEN) :: threads
106
CHARACTER(:), ALLOCATABLE :: CoordTransform
107
108
REAL(KIND=dp) :: s,dt,dtfunc
109
REAL(KIND=dP), POINTER :: WorkA(:,:,:) => NULL()
110
REAL(KIND=dp), POINTER, SAVE :: sTime(:), sStep(:), sInterval(:), sSize(:), &
111
steadyIt(:),nonlinIt(:),sPrevSizes(:,:),sPeriodicTime(:),sPeriodicCycle(:),&
112
sScan(:),sSweep(:),sPar(:),sFinish(:),sProduce(:),sSlice(:),sSliceRatio(:),&
113
sSliceWeight(:), sAngle(:), sAngleVelo(:),sSector(:)
114
115
LOGICAL :: GotIt,Transient,Scanning, LastSaved, MeshMode = .FALSE.
116
117
INTEGER :: TimeIntervals,interval,timestep, &
118
TotalTimesteps,SavedSteps,CoupledMaxIter,CoupledMinIter
119
120
INTEGER, POINTER, SAVE :: Timesteps(:),OutputIntervals(:) => NULL(), ActiveSolvers(:)
121
REAL(KIND=dp), POINTER, SAVE :: TimestepSizes(:,:),TimestepRatios(:,:)
122
123
INTEGER(KIND=AddrInt) :: ControlProcedure
124
125
LOGICAL :: InitDirichlet, ExecThis, GotTimestepRatios = .FALSE.
126
127
TYPE(ElementType_t),POINTER :: elmt
128
129
TYPE(ParEnv_t), POINTER :: ParallelEnv
130
131
CHARACTER(:), ALLOCATABLE :: ModelName, OptionString, eq
132
133
CHARACTER(:), ALLOCATABLE :: str, PostFile, ExecCommand, OutputFile, RestartFile, &
134
OutputName, PostName, When
135
136
TYPE(Variable_t), POINTER :: Var
137
TYPE(Mesh_t), POINTER :: Mesh
138
TYPE(Solver_t), POINTER :: Solver, iSolver
139
140
REAL(KIND=dp) :: CT0,RT0,tt
141
142
LOGICAL :: Silent=.FALSE., Version=.FALSE., GotModelName, FinishEarly=.FALSE.
143
LOGICAL :: FirstLoad = .TRUE., FirstTime=.TRUE., Found
144
145
INTEGER :: iostat, iSweep = 1, OptimIters
146
LOGICAL :: GotOptimIters
147
INTEGER :: MeshIndex
148
TYPE(Mesh_t), POINTER :: ExtrudedMesh
149
150
TYPE(Model_t), POINTER, SAVE :: Control
151
LOGICAL :: DoControl=.FALSE., ProcControl=.FALSE., GotParams=.FALSE., DoIt
152
INTEGER :: nr,ni,ExtMethod
153
INTEGER, ALLOCATABLE :: ipar(:)
154
REAL(KIND=dp), ALLOCATABLE :: rpar(:)
155
CHARACTER(LEN=MAX_PATH_LEN) :: MeshDir, MeshName
156
157
! Start the watches, store later
158
!--------------------------------
159
RT0 = RealTime()
160
CT0 = CPUTime()
161
162
! If parallel execution requested, initialize parallel environment:
163
!------------------------------------------------------------------
164
IF(FirstTime) ParallelEnv => ParallelInit()
165
166
OutputPE = -1
167
IF( ParEnv % MyPe == 0 ) THEN
168
OutputPE = 0
169
END IF
170
171
IF ( FirstTime ) THEN
172
!
173
! Print banner to output:
174
! -----------------------
175
! Info Level is always true until the model has been read!
176
! This makes it possible to cast something
177
Silent = .FALSE.
178
Version = .FALSE.
179
180
IF( NoArgs > 0 ) THEN
181
i = 0
182
DO WHILE( i < NoArgs )
183
i = i + 1
184
OptionString = args(i) % astr
185
IF( OptionString=='-rpar' ) THEN
186
! Followed by number of parameters + the parameter values
187
i = i + 1
188
OptionString = args(i) % astr
189
READ( OptionString,*) nr
190
ALLOCATE( rpar(nr) )
191
DO j=1,nr
192
i = i + 1
193
OptionString = args(i) % astr
194
READ( OptionString,*) rpar(j)
195
END DO
196
CALL Info('MAIN','Read '//I2S(nr)//' real parameters from command line!')
197
CALL SetRealParametersMATC(nr,rpar)
198
END IF
199
200
IF( OptionString=='-ipar' ) THEN
201
! Followed by number of parameters + the parameter values
202
i = i + 1
203
OptionString = args(i) % astr
204
PRINT *, OptionString
205
READ( OptionString,*) ni
206
ALLOCATE( ipar(nr) )
207
DO j=1,ni
208
i = i + 1
209
OptionString = args(i) % astr
210
READ( OptionString,*) ipar(j)
211
END DO
212
CALL Info('MAIN','Read '//I2S(ni)//' integer parameters from command line!')
213
CALL SetIntegerParametersMATC(ni,ipar)
214
END IF
215
216
Silent = Silent .OR. &
217
( OptionString=='-s' .OR. OptionString=='--silent' )
218
Version = Version .OR. &
219
( OptionString=='-v' .OR. OptionString == '--version' )
220
END DO
221
END IF
222
223
! Set number of OpenMP threads
224
nthreads = 1
225
!$ nthreads = omp_get_max_threads()
226
IF (nthreads > 1 ) THEN
227
! Check if OMP_NUM_THREADS environment variable is set
228
CALL envir( 'OMP_NUM_THREADS', threads, tlen )
229
230
IF (tlen==0) THEN
231
CALL Info('MAIN','OMP_NUM_THREADS not set. Using only 1 thread per task.',Level=6)
232
nthreads = 1
233
! Set number of threads to 1
234
!$ CALL omp_set_num_threads(nthreads)
235
#ifdef HAVE_MKL
236
CALL mkl_set_num_threads(nthreads)
237
#endif
238
END IF
239
END IF
240
ParEnv % NumberOfThreads = nthreads
241
242
243
IF( .NOT. Silent ) THEN
244
CALL Info( 'MAIN', ' ')
245
CALL Info( 'MAIN', '=============================================================')
246
CALL Info( 'MAIN', 'ElmerSolver finite element software, Welcome! ')
247
CALL Info( 'MAIN', 'This program is free software licensed under (L)GPL ')
248
CALL Info( 'MAIN', 'Copyright 1st April 1995 - , CSC - IT Center for Science Ltd.')
249
CALL Info( 'MAIN', 'Webpage http://www.csc.fi/elmer, Email [email protected] ')
250
CALL Info( 'MAIN', 'Version: ' // GetVersion() //'-'// GetBranch() // ' (Rev: ' // GetRevision() // &
251
', Compiled: ' // GetCompilationDate() // ')' )
252
253
IF ( ParEnv % PEs > 1 ) THEN
254
CALL Info( 'MAIN', ' Running in parallel using ' // &
255
i2s(ParEnv % PEs) // ' tasks.')
256
ELSE
257
CALL Info('MAIN', ' Running one task without MPI parallelization.',Level=10)
258
END IF
259
260
! Print out number of threads in use
261
IF ( nthreads > 1 ) THEN
262
CALL Info('MAIN', ' Running in parallel with ' // &
263
i2s(nthreads) // ' threads per task.')
264
ELSE
265
CALL Info('MAIN', ' Running with just one thread per task.',Level=10)
266
END IF
267
268
#ifdef HAVE_FETI4I
269
CALL Info( 'MAIN', ' FETI4I library linked in.')
270
#endif
271
#ifdef HAVE_HYPRE
272
CALL Info( 'MAIN', ' HYPRE library linked in.')
273
#endif
274
#ifdef HAVE_MUMPS
275
CALL Info( 'MAIN', ' MUMPS library linked in.')
276
#endif
277
#ifdef HAVE_CHOLMOD
278
CALL Info( 'MAIN', ' CHOLMOD library linked in.')
279
#endif
280
#ifdef HAVE_SUPERLU
281
CALL Info( 'MAIN', ' SUPERLU library linked in.')
282
#endif
283
#ifdef HAVE_PARDISO
284
CALL Info( 'MAIN', ' PARDISO library linked in.')
285
#endif
286
#ifdef HAVE_MMG
287
CALL Info( 'MAIN', ' MMG library linked in.')
288
#endif
289
#ifdef HAVE_PARMMG
290
CALL Info( 'MAIN', ' ParMMG library linked in.')
291
#endif
292
#ifdef HAVE_MKL
293
CALL Info( 'MAIN', ' Intel MKL linked in.' )
294
#endif
295
#ifdef HAVE_LUA
296
CALL Info( 'MAIN', ' Lua interpreter linked in.' )
297
#endif
298
#ifdef HAVE_EXTOPTIM
299
CALL Info( 'MAIN', ' External optimization routines linked in.' )
300
#endif
301
#ifdef HAVE_ZOLTAN
302
CALL Info( 'MAIN', ' Zoltan library linked in.' )
303
#endif
304
#ifdef HAVE_AMGX
305
CALL Info( 'MAIN', ' AMGX library linked in.' )
306
#endif
307
#ifdef HAVE_ROCALUTION
308
CALL Info( 'MAIN', ' ROCALUTION library linked in.' )
309
#endif
310
CALL Info( 'MAIN', '=============================================================')
311
END IF
312
313
IF( Version ) RETURN
314
315
CALL InitializeElementDescriptions()
316
END IF
317
318
! Read input file name either as an argument, or from the default file:
319
!----------------------------------------------------------------------
320
GotModelName = .FALSE.
321
IF ( NoArgs > 0 ) THEN
322
ModelName = args(1) % astr
323
IF( ModelName(1:1) /= '-') THEN
324
GotModelName = .TRUE.
325
IF (NoArgs > 1) eq = args(2) % astr
326
END IF
327
END IF
328
329
IF( .NOT. GotModelName ) THEN
330
OPEN( 1, File='ELMERSOLVER_STARTINFO', STATUS='OLD', IOSTAT=iostat )
331
IF( iostat /= 0 ) THEN
332
CALL Fatal( 'MAIN', 'Unable to find ELMERSOLVER_STARTINFO, can not execute.' )
333
END IF
334
ALLOCATE(CHARACTER(MAX_PATH_LEN)::ModelName)
335
READ(1,'(a)') ModelName
336
CLOSE(1)
337
END IF
338
339
! This sets optionally some internal parameters for doing scanning
340
! over a parameter space / optimization.
341
!-----------------------------------------------------------------
342
IF( FirstTime ) THEN
343
OPEN( Unit=InFileUnit, Action='Read',File=ModelName,Status='OLD',IOSTAT=iostat)
344
IF( iostat /= 0 ) THEN
345
CALL Fatal( 'MAIN', 'Unable to find input file [' // &
346
TRIM(Modelname) // '], can not execute.' )
347
END IF
348
ALLOCATE( Control )
349
! Read only the "Run Control" section of the sif file.
350
CALL LoadInputFile( Control,InFileUnit,ModelName,MeshDir,MeshName, &
351
.FALSE., .TRUE., ControlOnly = .TRUE.)
352
DoControl = ASSOCIATED( Control % Control )
353
354
IF( DoControl ) THEN
355
CALL Info('MAIN','Run Control section active!')
356
OptimIters = ListGetInteger( Control % Control,'Run Control Iterations', GotOptimIters )
357
IF(.NOT. GotOptimIters) OptimIters = 1
358
359
! If there are no parameters this does nothing
360
CALL ControlParameters(Control % Control,1,GotParams,FinishEarly)
361
ELSE
362
OptimIters = 1
363
END IF
364
END IF
365
366
!------------------------------------------------------------------------------
367
! Read element definition file, and initialize element types
368
!------------------------------------------------------------------------------
369
IF ( Initialize==1 ) THEN
370
CALL FreeModel(CurrentModel)
371
FirstLoad=.TRUE.
372
END IF
373
374
!------------------------------------------------------------------------------
375
! Read Model and mesh from Elmer mesh data base
376
!------------------------------------------------------------------------------
377
MeshIndex = 0
378
DO WHILE( .TRUE. )
379
380
IF ( initialize==2 ) GOTO 1
381
382
IF(MeshMode) THEN
383
CALL FreeModel(CurrentModel)
384
MeshIndex = MeshIndex + 1
385
FirstLoad = .TRUE.
386
END IF
387
388
IF ( FirstLoad ) THEN
389
IF( .NOT. Silent ) THEN
390
CALL Info( 'MAIN', ' ')
391
CALL Info( 'MAIN', ' ')
392
CALL Info( 'MAIN', '-------------------------------------')
393
CALL Info( 'MAIN', 'Reading Model: '//TRIM( ModelName) )
394
END IF
395
396
INQUIRE(Unit=InFileUnit, Opened=GotIt)
397
IF ( gotIt ) CLOSE(inFileUnit)
398
399
! Here we read the whole model including command file and default mesh file
400
!---------------------------------------------------------------------------------
401
OPEN( Unit=InFileUnit, Action='Read',File=ModelName,Status='OLD',IOSTAT=iostat)
402
IF( iostat /= 0 ) THEN
403
CALL Fatal( 'MAIN', 'Unable to find input file [' // &
404
TRIM(Modelname) // '], can not execute.' )
405
END IF
406
407
CurrentModel => LoadModel(ModelName,.FALSE.,ParEnv % PEs,ParEnv % MyPE,MeshIndex)
408
IF(.NOT.ASSOCIATED(CurrentModel)) EXIT
409
410
411
IF( nthreads > 1 ) THEN
412
MaxOutputThread = ListGetInteger( CurrentModel % Simulation,'Max Output Thread',GotIt)
413
IF(.NOT. GotIt) MaxOutputThread = 1
414
END IF
415
416
!----------------------------------------------------------------------------------
417
! Set namespace searching mode
418
!----------------------------------------------------------------------------------
419
CALL SetNamespaceCheck( ListGetLogical( CurrentModel % Simulation, &
420
'Additive namespaces', Found ) )
421
422
!----------------------------------------------------------------------------------
423
MeshMode = ListGetLogical( CurrentModel % Simulation, 'Mesh Mode', Found)
424
425
!------------------------------------------------------------------------------
426
! Some keywords automatically require other keywords to be set
427
! We could complain on the missing keywords later on, but sometimes
428
! it may be just as simple to add them directly.
429
!------------------------------------------------------------------------------
430
CALL CompleteModelKeywords( )
431
432
!----------------------------------------------------------------------------------
433
! Optionally perform simple extrusion to increase the dimension of the mesh
434
!----------------------------------------------------------------------------------
435
CALL CreateExtrudedMesh()
436
DO j=1,CurrentModel % NumberOfSolvers
437
CALL CreateExtrudedMesh(j)
438
END DO
439
440
!----------------------------------------------------------------------------------
441
! If requested perform coordinate transformation directly after is has been obtained.
442
! Don't maintain the original mesh.
443
!----------------------------------------------------------------------------------
444
CoordTransform=ListGetString(CurrentModel % Simulation,'Coordinate Transformation',GotIt)
445
IF( GotIt ) THEN
446
CALL CoordinateTransformation( CurrentModel % Meshes, CoordTransform, &
447
CurrentModel % Simulation, .TRUE. )
448
END IF
449
450
IF( ListGetLogical( CurrentModel % Simulation,'Mark Sharp Edges',GotIt) ) THEN
451
BLOCK
452
LOGICAL, ALLOCATABLE :: SharpEdge(:)
453
REAL(KIND=dp) :: phi
454
phi = ListGetConstReal( CurrentModel % Simulation,'Sharp Edge',GotIt)
455
IF(.NOT. GotIt) phi = 30.0_dp
456
CALL MarkSharpEdges( CurrentModel % Meshes, SharpEdge, phi )
457
END BLOCK
458
END IF
459
460
IF(.NOT. Silent ) THEN
461
CALL Info( 'MAIN', '-------------------------------------')
462
END IF
463
ELSE
464
IF ( Initialize==3 ) THEN
465
INQUIRE(Unit=InFileUnit, Opened=GotIt)
466
IF ( gotIt ) CLOSE(inFileUnit)
467
OPEN( Unit=InFileUnit, Action='Read', &
468
File=ModelName,Status='OLD',IOSTAT=iostat)
469
IF( iostat /= 0 ) THEN
470
CALL Fatal( 'MAIN', 'Unable to find input file [' // &
471
TRIM(Modelname) // '], can not execute.' )
472
END IF
473
END IF
474
475
IF ( .NOT.ReloadInputFile(CurrentModel) ) EXIT
476
477
Mesh => CurrentModel % Meshes
478
DO WHILE( ASSOCIATED(Mesh) )
479
Mesh % SavesDone = 0
480
Mesh => Mesh % Next
481
END DO
482
END IF
483
484
1 CONTINUE
485
486
CALL ListAddLogical( CurrentModel % Simulation, &
487
'Initialization Phase', .TRUE. )
488
489
! Save the start time to the list so that it may be retrieved when necessary
490
! This could perhaps also be a global variable etc, but this will do for now.
491
!-------------------------------------------------------------------------
492
IF( ListGetLogical( CurrentModel % Simulation,'Simulation Timing',GotIt) ) THEN
493
CALL ListAddConstReal( CurrentModel % Simulation,'cputime0',ct0 )
494
CALL ListAddConstReal( CurrentModel % Simulation,'realtime0',rt0 )
495
END IF
496
497
!------------------------------------------------------------------------------
498
! Check for transient case
499
!------------------------------------------------------------------------------
500
eq = ListGetString( CurrentModel % Simulation, 'Simulation Type', GotIt )
501
Scanning = ( eq == 'scanning' )
502
Transient = ( eq == 'transient' )
503
504
!------------------------------------------------------------------------------
505
! To more conveniently support the use of VTK based visualization there
506
! is a hack that recognizes VTU suffix and creates a instance of output solver.
507
! Note that this is really quite a dirty hack, and is not a good example.
508
!-----------------------------------------------------------------------------
509
CALL AddVtuOutputSolverHack()
510
511
! Support easily saving scalars to a file activated by "Scalars File" keyword.
512
!-----------------------------------------------------------------------------
513
CALL AddSaveScalarsHack()
514
515
516
!------------------------------------------------------------------------------
517
! Add coordinates such that if there is a solver that is run on creation
518
! the coordinates are already usable then.
519
!------------------------------------------------------------------------------
520
IF ( FirstLoad ) THEN
521
CALL AddMeshCoordinates()
522
523
! We can toggle with the body indexes already at this moment.
524
CALL TagBodiesUsingCondition( CurrentModel, CurrentModel % Meshes )
525
END IF
526
527
!------------------------------------------------------------------------------
528
! Figure out what (flow,heat,stress,...) should be computed, and get
529
! memory for the dofs
530
!------------------------------------------------------------------------------
531
CALL AddSolvers()
532
533
!------------------------------------------------------------------------------
534
! Time integration and/or steady state steps
535
!------------------------------------------------------------------------------
536
CALL InitializeIntervals()
537
538
!------------------------------------------------------------------------------
539
! Add time and other global variables so that we can have dependence on these.
540
!------------------------------------------------------------------------------
541
IF ( FirstLoad ) CALL AddTimeEtc()
542
543
!------------------------------------------------------------------------------
544
! Initialize the random seeds so that all simulation depending on that
545
! give consistent results.
546
!------------------------------------------------------------------------------
547
IF( FirstLoad ) CALL InitializeRandomSeed()
548
549
!------------------------------------------------------------------------------
550
! Get Output File Options
551
!------------------------------------------------------------------------------
552
553
! Initial Conditions:
554
! -------------------
555
IF ( FirstLoad ) THEN
556
CALL SetInitialConditions()
557
558
DO i=1,CurrentModel % NumberOfSolvers
559
Solver => CurrentModel % Solvers(i)
560
IF( ListGetLogical( Solver % Values, 'Initialize Exported Variables', GotIt ) ) THEN
561
CurrentModel % Solver => Solver
562
CALL UpdateExportedVariables( Solver )
563
END IF
564
END DO
565
END IF
566
567
! Compute the total number of steps that will be saved to the files
568
! Particularly look if the last step will be saved, or if it has
569
! to be saved separately.
570
!------------------------------------------------------------------
571
CALL CountSavedTimesteps()
572
573
CALL ListAddLogical( CurrentModel % Simulation, &
574
'Initialization Phase', .FALSE. )
575
576
FirstLoad = .FALSE.
577
IF ( Initialize == 1 ) EXIT
578
579
! Check whether we are using external optimization routine that
580
! needs to have basically Elmer given as a function that returns
581
! the cost function. Hence this is treated separately from the internal
582
! optimization methods.
583
!---------------------------------------------------------------------
584
ExtMethod = 0
585
str = ListGetString( CurrentModel % Control,'Optimization Method',Found)
586
IF( Found ) THEN
587
IF( SEQL(str, 'hybrd') ) THEN
588
ExtMethod = 1
589
ELSE IF( SEQL(str,'newuoa') ) THEN
590
ExtMethod = 2
591
ELSE IF( SEQL(str,'bobyqa') ) THEN
592
ExtMethod = 3
593
END IF
594
END IF
595
596
ExecCommand = ListGetString( CurrentModel % Simulation, &
597
'Control Procedure', ProcControl )
598
IF ( ProcControl ) THEN
599
ControlProcedure = GetProcAddr( ExecCommand )
600
CALL ExecSimulationProc( ControlProcedure, CurrentModel )
601
602
ELSE IF( ExtMethod > 0 ) THEN
603
#ifdef HAVE_EXTOPTIM
604
SELECT CASE( ExtMethod )
605
CASE(1)
606
CALL ExternalOptimization_minpack(ExecSimulationFunVec)
607
CASE(2)
608
CALL ExternalOptimization_newuoa(ExecSimulationFunCost)
609
CASE(3)
610
CALL ExternalOptimization_bobyqa(ExecSimulationFunCost)
611
END SELECT
612
#else
613
CALL Fatal('MAIN','Compile WITH_EXTOPTIM to activate method: '//TRIM(str))
614
#endif
615
616
ELSE IF( DoControl ) THEN
617
618
! This sets optionally some internal parameters for doing scanning
619
! over a parameter space / optimization.
620
!-----------------------------------------------------------------
621
iSweep = 0
622
DO WHILE (.TRUE.)
623
iSweep = iSweep + 1
624
CALL Info('MAIN','========================================================',Level=5)
625
CALL Info('MAIN','Control Loop '//I2S(iSweep))
626
CALL Info('MAIN','========================================================',Level=5)
627
628
sSweep = 1.0_dp * iSweep
629
! If there are no parameters this does nothing
630
CALL ControlResetMesh(CurrentModel % Control, iSweep )
631
IF( iSweep > 1 ) THEN
632
CALL ControlParameters(CurrentModel % Control,iSweep,&
633
GotParams,FinishEarly)
634
IF( FinishEarly ) EXIT
635
Found = ReloadInputFile(CurrentModel,RewindFile=.TRUE.)
636
CALL InitializeIntervals()
637
END IF
638
639
! This is another calling slot as here we have formed the model structure and
640
! may toggle with the keyword coefficients.
641
CALL ControlParameters(CurrentModel % Control,iSweep,&
642
GotParams,FinishEarly,SetCoeffs=.TRUE.)
643
644
IF( iSweep > 1 ) THEN
645
IF( ListGetLogical( CurrentModel % Control,'Reset Adaptive Mesh',Found ) ) THEN
646
CALL ResetAdaptiveMesh()
647
END IF
648
IF( ListGetLogical( CurrentModel % Control,'Reset Initial Conditions',Found ) ) THEN
649
CALL SetInitialConditions()
650
END IF
651
END IF
652
653
CALL ExecSimulation( TimeIntervals, CoupledMinIter, &
654
CoupledMaxIter, OutputIntervals, Transient, Scanning)
655
656
! This evaluates the cost function and saves the results of control
657
CALL ControlParameters(CurrentModel % Control, &
658
iSweep,GotParams,FinishEarly,.TRUE.)
659
660
IF( iSweep == 1 ) THEN
661
DO i=1,CurrentModel % NumberOfSolvers
662
iSolver => CurrentModel % Solvers(i)
663
j = iSolver % NumberOfConstraintModes
664
IF( j <= 0 ) CYCLE
665
IF( ListGetLogical( iSolver % Values,'Run Control Constraint Modes', Found ) .OR. &
666
ListGetLogical( CurrentModel % Control,'Constraint Modes Analysis',Found ) ) THEN
667
IF( GotOptimIters ) THEN
668
IF( OptimIters /= j ) THEN
669
CALL Warn('MAIN','Incompatible number of run control iterations and constraint modes!')
670
END IF
671
ELSE
672
CALL Info('MAIN','Setting run control iterations to constraint modes count: '//I2S(j))
673
OptimIters = j
674
END IF
675
EXIT
676
END IF
677
END DO
678
END IF
679
680
! We use this type of condition so that OptimIters can be changed on-the-fly
681
IF(iSweep == OptimIters) EXIT
682
END DO
683
684
DO i=1,CurrentModel % NumberOfSolvers
685
iSolver => CurrentModel % Solvers(i)
686
IF( iSolver % NumberOfConstraintModes > 0 ) THEN
687
IF( ListGetLogical( iSolver % Values,'Run Control Constraint Modes', Found ) .OR. &
688
ListGetLogical( CurrentModel % Control,'Constraint Modes Analysis',Found ) ) THEN
689
CALL FinalizeLumpedMatrix( iSolver )
690
END IF
691
END IF
692
END DO
693
694
DO i=1,CurrentModel % NumberOfSolvers
695
iSolver => CurrentModel % Solvers(i)
696
IF ( iSolver % PROCEDURE == 0 ) CYCLE
697
When = ListGetString( iSolver % Values, 'Exec Solver', Found )
698
IF ( Found ) THEN
699
DoIt = ( When == 'after control' )
700
ELSE
701
DoIt = ( iSolver % SolverExecWhen == SOLVER_EXEC_AFTER_CONTROL )
702
END IF
703
IF(DoIt) CALL SolverActivate( CurrentModel,iSolver,dt,Transient )
704
END DO
705
ELSE
706
CALL ExecSimulation( TimeIntervals, CoupledMinIter, &
707
CoupledMaxIter, OutputIntervals, Transient, Scanning)
708
END IF
709
710
! Comparison to reference is done to enable consistency test under ctest.
711
!-------------------------------------------------------------------------
712
CALL CompareToReferenceSolution( )
713
714
IF ( Initialize >= 2 ) EXIT
715
END DO
716
717
IF( ListGetLogical( CurrentModel % Simulation,'Echo Keywords at End', GotIt ) ) THEN
718
CALL ListEchoKeywords( CurrentModel )
719
END IF
720
721
CALL CompareToReferenceSolution( Finalize = .TRUE. )
722
723
#ifdef DEVEL_LISTUSAGE
724
IF(InfoActive(10) .AND. ParEnv % MyPe == 0 ) THEN
725
CALL Info('MAIN','Reporting unused list entries for sif improvement!')
726
CALL Info('MAIN','If you do not want these lines undefine > DEVEL_LISTUSAGE < !')
727
CALL ReportListCounters( CurrentModel, 2 )
728
END IF
729
#endif
730
#ifdef DEVEL_LISTCOUNTER
731
IF( ParEnv % MyPe == 0 ) THEN
732
CALL Info('MAIN','Reporting list counters for code optimization purposes only!')
733
CALL Info('MAIN','If you get these lines with production code undefine > DEVEL_LISTCOUNTER < !')
734
CALL ReportListCounters( CurrentModel, 3 )
735
END IF
736
#endif
737
738
!------------------------------------------------------------------------------
739
! THIS IS THE END (...,at last, the end, my friend,...)
740
!------------------------------------------------------------------------------
741
IF ( Initialize /= 1 ) CALL Info( 'MAIN', '*** Elmer Solver: ALL DONE ***',Level=3 )
742
743
! This may be used to study problems at the finish
744
IF( ListGetLogical( CurrentModel % Simulation,'Dirty Finish', GotIt ) ) THEN
745
CALL Info('MAIN','Skipping freeing of the Model structure',Level=4)
746
RETURN
747
END IF
748
749
IF ( Initialize <= 0 ) CALL FreeModel(CurrentModel)
750
751
752
IF ( FirstTime ) CALL ParallelFinalize()
753
FirstTime = .FALSE.
754
755
CALL Info('MAIN','The end',Level=3)
756
757
RETURN
758
759
CONTAINS
760
761
762
! If we want to start a new adaptive simulation with the original mesh
763
! call this subroutine.
764
!---------------------------------------------------------------------
765
SUBROUTINE ResetAdaptiveMesh()
766
767
TYPE(Mesh_t), POINTER :: pMesh, pMesh0
768
TYPE(Solver_t), POINTER :: iSolver
769
TYPE(Variable_t), POINTER :: pVar
770
LOGICAL :: GB, BO
771
CHARACTER(*), PARAMETER :: Caller = 'ResetAdaptiveMesh'
772
773
! Find the 1st mesh
774
pMesh0 => CurrentModel % Mesh
775
DO WHILE( ASSOCIATED(pMesh0 % Parent) )
776
pMesh0 => pMesh0 % Parent
777
END DO
778
!PRINT *,'First mesh:',pMesh0 % AdaptiveDepth, TRIM(pMesh0 % Name)
779
780
! Find the last mesh
781
pMesh => CurrentModel % Mesh
782
DO WHILE( ASSOCIATED(pMesh % Child) )
783
pMesh => pMesh % Child
784
END DO
785
!PRINT *,'Last mesh:',pMesh % AdaptiveDepth, TRIM(pMesh % Name)
786
787
! Move point to the 1st mesh and related fields
788
CALL SetCurrentMesh( CurrentModel, pMesh0 )
789
790
DO i=1,CurrentModel % NumberOfSolvers
791
iSolver => CurrentModel % Solvers(i)
792
793
IF(.NOT. ASSOCIATED(iSolver % Variable)) THEN
794
CALL Info(Caller,'No Variable in this mesh for solver index '//I2S(i),Level=10)
795
CYCLE
796
END IF
797
798
! Set Solver mesh
799
IF(ASSOCIATED(iSolver % Mesh)) iSolver % Mesh => pMesh0
800
801
! Set Solver variable point to the field in the original mesh
802
IF(ASSOCIATED(iSolver % Variable)) THEN
803
pVar => VariableGet(pMesh0 % Variables, &
804
iSolver % Variable % Name, ThisOnly = .TRUE.)
805
IF(.NOT. ASSOCIATED(pVar)) THEN
806
CALL Info(Caller,'No Variable in coarsest mesh for solver index '//I2S(i),Level=10)
807
CYCLE
808
END IF
809
iSolver % Variable => pVar
810
END IF
811
812
! Reset active element table
813
IF( iSolver % NumberOfActiveElements == 0 ) THEN
814
CALL Info(Caller,'No active elements for solver index '//I2S(i),Level=10)
815
CYCLE
816
END IF
817
818
iSolver % NumberOfActiveElements = 0
819
CALL SetActiveElementsTable( CurrentModel, iSolver )
820
821
! Create the matrix related to the original mesh
822
IF( .NOT. ASSOCIATED( iSolver % Matrix ) ) THEN
823
CALL Info(Caller,'No matrix for solver index '//I2S(i),Level=10)
824
CYCLE
825
END IF
826
827
CALL FreeMatrix( iSolver % Matrix)
828
829
GB = ListGetLogical( iSolver % Values,'Bubbles in Global System', Found )
830
IF ( .NOT. Found ) GB = .TRUE.
831
832
BO = ListGetLogical( iSolver % Values,'Optimize Bandwidth', Found )
833
IF ( .NOT. Found ) BO = .TRUE.
834
835
iSolver % Matrix => CreateMatrix( CurrentModel, iSolver, iSolver % Mesh, &
836
iSolver % Variable % Perm, iSolver % Variable % DOFs, MATRIX_CRS, &
837
BO, ListGetString( iSolver % Values, 'Equation' ), GlobalBubbles=GB )
838
ALLOCATE( iSolver % Matrix % rhs(iSolver % Matrix % NumberOfRows ) )
839
iSolver % Matrix % rhs = 0.0_dp
840
END DO
841
842
! Release the old adaptive meshes
843
DO WHILE( ASSOCIATED(pMesh % Parent))
844
pMesh => pMesh % Parent
845
CALL ReleaseMesh( pMesh % Child )
846
END DO
847
pMesh % Child => NULL()
848
849
END SUBROUTINE ResetAdaptiveMesh
850
851
852
853
SUBROUTINE InitializeRandomSeed()
854
INTEGER :: i,n
855
INTEGER, ALLOCATABLE :: seeds(:)
856
857
CALL RANDOM_SEED() ! initialize with system generated seed
858
859
i = ListGetInteger( CurrentModel % Simulation,'Random Number Seed',Found )
860
IF( .NOT. Found ) i = 314159265
861
862
CALL RANDOM_SEED(size=j) ! find out size of seed
863
ALLOCATE(seeds(j))
864
!CALL RANDOM_SEED(get=seeds) ! get system generated seed
865
!WRITE(*,*) seeds ! writes system generated seed
866
seeds = i
867
CALL RANDOM_SEED(put=seeds) ! set current seed
868
!CALL RANDOM_SEED(get=seeds) ! get current seed
869
!WRITE(*,*) seeds ! writes 314159265
870
DEALLOCATE(seeds)
871
872
CALL Info('MAIN','Random seed initialized to: '//I2S(i),Level=10)
873
END SUBROUTINE InitializeRandomSeed
874
875
876
! Optionally create extruded mesh on-the-fly.
877
!--------------------------------------------------------------------
878
SUBROUTINE CreateExtrudedMesh(SolverId)
879
INTEGER, OPTIONAL :: SolverId
880
881
LOGICAL :: SliceVersion
882
TYPE(ValueList_t), POINTER :: VList
883
TYPE(Mesh_t), POINTER :: Mesh_in, pMesh, prevMesh
884
LOGICAL :: PrimaryMesh
885
886
IF(PRESENT(SolverId)) THEN
887
Vlist => CurrentModel % Solvers(SolverId) % Values
888
Mesh_in => CurrentModel % Solvers(SolverId) % Mesh
889
PrimaryMesh = .FALSE.
890
ELSE
891
Vlist => CurrentModel % Simulation
892
Mesh_in => CurrentModel % Meshes
893
PrimaryMesh = .TRUE.
894
END IF
895
896
IF(.NOT. ListCheckPrefix(VList,'Extruded Mesh') ) RETURN
897
IF(.NOT. PrimaryMesh) THEN
898
CALL Info('CreateExtrudedMesh','Extruding mesh associated to solver '//I2S(SolverId))
899
END IF
900
901
SliceVersion = GetLogical(Vlist,'Extruded Mesh Slices',Found )
902
IF( SliceVersion ) THEN
903
ExtrudedMesh => MeshExtrudeSlices(Mesh_in, Vlist )
904
ELSE
905
ExtrudedMesh => MeshExtrude(Mesh_in, Vlist )
906
END IF
907
908
! Make the solvers point to the extruded mesh, not the original mesh
909
!-------------------------------------------------------------------
910
DO i=1,CurrentModel % NumberOfSolvers
911
IF(ASSOCIATED(CurrentModel % Solvers(i) % Mesh,Mesh_in)) THEN
912
CALL Info('CreateExtrudedMesh','Pointing solver '//I2S(i)//' to the new extruded mesh!')
913
CurrentModel % Solvers(i) % Mesh => ExtrudedMesh
914
END IF
915
END DO
916
917
! Put the extruded mesh in a correct place in the list of meshes.
918
i = 0
919
NULLIFY(prevMesh)
920
pMesh => CurrentModel % Meshes
921
DO WHILE(ASSOCIATED(pMesh))
922
i = i+1
923
IF(ASSOCIATED(pMesh,Mesh_in)) EXIT
924
prevMesh => pMesh
925
pMesh => pMesh % Next
926
END DO
927
CALL Info('CreateExtrudedMesh','Extruded mesh order is '//I2S(i),Level=25)
928
929
ExtrudedMesh % Next => Mesh_in % Next
930
IF(ASSOCIATED(prevMesh)) THEN
931
prevMesh % Next => ExtrudedMesh
932
ELSE
933
CurrentModel % Meshes => ExtrudedMesh
934
END IF
935
936
! If periodic BC given, compute boundary mesh projector:
937
! but only for the primary mesh.
938
! ------------------------------------------------------
939
IF(.NOT. PrimaryMesh) RETURN
940
941
DO i = 1,CurrentModel % NumberOfBCs
942
IF(ASSOCIATED(CurrentModel % Bcs(i) % PMatrix)) &
943
CALL FreeMatrix( CurrentModel % BCs(i) % PMatrix )
944
CurrentModel % BCs(i) % PMatrix => NULL()
945
k = ListGetInteger( CurrentModel % BCs(i) % Values, 'Periodic BC', GotIt )
946
IF( GotIt ) THEN
947
CurrentModel % BCs(i) % PMatrix => PeriodicProjector( CurrentModel, ExtrudedMesh, i, k )
948
END IF
949
END DO
950
951
END SUBROUTINE CreateExtrudedMesh
952
953
954
! Given geometric ratio of timesteps redistribute them so that the ratio
955
! is met as closely as possible, maintaining total time and sacrificing
956
! number of timesteps.
957
!----------------------------------------------------------------------
958
SUBROUTINE GeometricTimesteps(m,n0,dt0,r)
959
INTEGER :: m
960
INTEGER :: n0(:)
961
REAL(KIND=dp) :: dt0(:),r(:)
962
963
INTEGER :: i,n
964
REAL(KIND=dp) :: q
965
LOGICAL :: Visited = .FALSE.
966
967
! Only do this once since it tampers stuff in lists.
968
IF(Visited) RETURN
969
Visited = .TRUE.
970
971
CALL Info('MAIN','Creating geometric timestepping strategy',Level=6)
972
973
DO i=1,m
974
! Some users may give zero ratio, assume that they mean one.
975
IF(ABS(r(i)) < EPSILON(q) ) r(i) = 1.0_dp
976
! Ratio one means even distribution.
977
IF(ABS(r(i)-1.0) < EPSILON(q) ) CYCLE
978
979
q = 1 + (r(i)-1)/n0(i)
980
n = NINT( LOG(1+(q-1)*n0(i)) / LOG(q) )
981
dt = n0(i)*dt0(i)*(1-q)/(1-q**n)
982
983
!PRINT *,'ratio:',i,n0(i),dt0(i),r(i),n,dt,q
984
985
! Replace the new distribution
986
r(i) = q
987
dt0(i) = dt
988
n0(i) = n
989
END DO
990
991
END SUBROUTINE GeometricTimesteps
992
993
994
! Initialize intervals for steady state, transient and scanning types.
995
!----------------------------------------------------------------------
996
SUBROUTINE InitializeIntervals()
997
998
IF ( Transient .OR. Scanning ) THEN
999
Timesteps => ListGetIntegerArray( CurrentModel % Simulation, &
1000
'Timestep Intervals', GotIt )
1001
1002
IF ( .NOT.GotIt ) THEN
1003
CALL Fatal('MAIN', 'Keyword > Timestep Intervals < MUST be ' // &
1004
'defined for transient and scanning simulations' )
1005
END IF
1006
1007
TimestepSizes => ListGetConstRealArray( CurrentModel % Simulation, &
1008
'Timestep Sizes', GotIt )
1009
IF ( .NOT.GotIt ) THEN
1010
IF( Scanning .OR. ListCheckPresent( CurrentModel % Simulation,'Timestep Size') ) THEN
1011
ALLOCATE(TimestepSizes(SIZE(Timesteps),1))
1012
TimestepSizes = 1.0_dp
1013
ELSE
1014
CALL Fatal( 'MAIN', 'Keyword [Timestep Sizes] MUST be ' // &
1015
'defined for time dependent simulations' )
1016
END IF
1017
END IF
1018
1019
CoupledMaxIter = ListGetInteger( CurrentModel % Simulation, &
1020
'Steady State Max Iterations', GotIt, minv=1 )
1021
IF ( .NOT. GotIt ) CoupledMaxIter = 1
1022
1023
TimeIntervals = SIZE(Timesteps)
1024
1025
TimestepRatios => ListGetConstRealArray( CurrentModel % Simulation, &
1026
'Timestep Ratios', GotTimestepRatios )
1027
1028
1029
IF ( GotTimestepRatios ) THEN
1030
CALL GeometricTimesteps(TimeIntervals,Timesteps,TimestepSizes(:,1),TimestepRatios(:,1))
1031
END IF
1032
1033
1034
ELSE
1035
! Steady state
1036
!------------------------------------------------------------------------------
1037
IF( .NOT. ASSOCIATED(Timesteps) ) THEN
1038
ALLOCATE(Timesteps(1))
1039
END IF
1040
Timesteps(1) = ListGetInteger( CurrentModel % Simulation, &
1041
'Steady State Max Iterations', GotIt,minv=1 )
1042
IF ( .NOT. GotIt ) Timesteps(1) = 1
1043
CoupledMaxIter = 1
1044
1045
ALLOCATE(TimestepSizes(1,1))
1046
TimestepSizes(1,1) = 1.0_dp
1047
TimeIntervals = 1
1048
END IF
1049
1050
1051
CoupledMinIter = ListGetInteger( CurrentModel % Simulation, &
1052
'Steady State Min Iterations', GotIt )
1053
IF( .NOT. GotIt ) CoupledMinIter = 1
1054
1055
OutputIntervals => ListGetIntegerArray( CurrentModel % Simulation, &
1056
'Output Intervals', GotIt )
1057
IF( GotIt ) THEN
1058
IF( SIZE(OutputIntervals) /= SIZE(TimeSteps) ) THEN
1059
CALL Fatal('MAIN','> Output Intervals < should have the same size as > Timestep Intervals < !')
1060
END IF
1061
ELSE
1062
IF( .NOT. ASSOCIATED( OutputIntervals ) ) THEN
1063
ALLOCATE( OutputIntervals(SIZE(TimeSteps)) )
1064
OutputIntervals = 1
1065
END IF
1066
END IF
1067
1068
1069
IF ( FirstLoad ) &
1070
ALLOCATE( sTime(1), sStep(1), sInterval(1), sSize(1), &
1071
steadyIt(1), nonLinit(1), sPrevSizes(1,5), sPeriodicTime(1), &
1072
sPeriodicCycle(1), sPar(1), sScan(1), sSweep(1), sFinish(1), &
1073
sProduce(1),sSlice(1), sSector(1), sSliceRatio(1), sSliceWeight(1), sAngle(1), &
1074
sAngleVelo(1) )
1075
1076
dt = 0._dp
1077
sTime = 0._dp
1078
sStep = 0
1079
sPeriodicTime = 0._dp
1080
sPeriodicCycle = 0._dp
1081
sScan = 0._dp
1082
sSize = dt
1083
sPrevSizes = 0_dp
1084
sInterval = 0._dp
1085
steadyIt = 0
1086
nonlinIt = 0
1087
sPar = 0
1088
sFinish = -1.0_dp
1089
sProduce = -1.0_dp
1090
sSlice = 0._dp
1091
sSector = 0._dp
1092
sSliceRatio = 0._dp
1093
sSliceWeight = 1.0_dp
1094
sAngle = 0.0_dp
1095
sAngleVelo = 0.0_dp
1096
1097
END SUBROUTINE InitializeIntervals
1098
1099
1100
! Calculate the number of timesteps for saving.
1101
! This is needed for some legacy formats.
1102
!-----------------------------------------------------------------
1103
SUBROUTINE CountSavedTimesteps()
1104
1105
INTEGER :: i
1106
1107
TotalTimesteps = 0
1108
LastSaved = .FALSE.
1109
DO i=1,TimeIntervals
1110
DO timestep = 1,Timesteps(i)
1111
IF( OutputIntervals(i) == 0 ) CYCLE
1112
LastSaved = .FALSE.
1113
IF ( MOD(Timestep-1, OutputIntervals(i))==0 ) THEN
1114
LastSaved = .TRUE.
1115
TotalTimesteps = TotalTimesteps + 1
1116
END IF
1117
END DO
1118
END DO
1119
1120
DO i=1,CurrentModel % NumberOfSolvers
1121
Solver => CurrentModel % Solvers(i)
1122
IF(.NOT.ASSOCIATED(Solver % Variable)) CYCLE
1123
IF(.NOT.ASSOCIATED(Solver % Variable % Values)) CYCLE
1124
When = ListGetString( Solver % Values, 'Exec Solver', GotIt )
1125
IF ( GotIt ) THEN
1126
IF ( When == 'after simulation' .OR. When == 'after all' ) THEN
1127
LastSaved = .FALSE.
1128
END IF
1129
ELSE
1130
IF ( Solver % SolverExecWhen == SOLVER_EXEC_AFTER_ALL ) THEN
1131
LastSaved = .FALSE.
1132
END IF
1133
END IF
1134
END DO
1135
1136
IF ( .NOT.LastSaved ) TotalTimesteps = TotalTimesteps + 1
1137
IF( TotalTimesteps == 0 ) TotalTimesteps = 1
1138
1139
CALL Info('MAIN','Number of timesteps to be saved: '//I2S(TotalTimesteps))
1140
1141
END SUBROUTINE CountSavedTimesteps
1142
1143
1144
! The user may request unit tests to be performed.
1145
! This will be done if any reference norm is given.
1146
! The success will be written to file TEST.PASSED as 0/1.
1147
!--------------------------------------------------------
1148
SUBROUTINE CompareToReferenceSolution( Finalize )
1149
LOGICAL, OPTIONAL :: Finalize
1150
1151
INTEGER :: i, j, k, n, solver_id, TestCount=0, PassCount=0, FailCount, Dofs
1152
REAL(KIND=dp) :: Norm, RefNorm, Tol, Err, val, refval, dt
1153
TYPE(Solver_t), POINTER :: Solver
1154
TYPE(Variable_t), POINTER :: Var
1155
LOGICAL :: Found, Success = .TRUE., FinalizeOnly, CompareNorm, CompareSolution, AbsoluteErr
1156
CHARACTER(:), ALLOCATABLE :: PassedMsg
1157
1158
SAVE TestCount, PassCount
1159
1160
IF( ParEnv % MyPe > 0 ) RETURN
1161
1162
! Write the success to a file for further use e.g. by cmake
1163
!----------------------------------------------------------
1164
FinalizeOnly = .FALSE.
1165
IF( PRESENT( Finalize ) ) FinalizeOnly = .TRUE.
1166
1167
IF( FinalizeOnly ) THEN
1168
1169
! Nothing tested
1170
IF( TestCount == 0 ) RETURN
1171
1172
Success = ( PassCount == TestCount )
1173
FailCount = TestCount - PassCount
1174
1175
IF( Success ) THEN
1176
CALL Info('CompareToReferenceSolution',&
1177
'PASSED all '//I2S(TestCount)//' tests!',Level=3)
1178
ELSE
1179
CALL Warn('CompareToReferenceSolution','FAILED '//I2S(FailCount)//&
1180
' tests out of '//I2S(TestCount)//'!')
1181
END IF
1182
1183
IF( FinalizeOnly ) THEN
1184
IF( ParEnv % MyPe == 0 ) THEN
1185
IF( ParEnv % PEs > 1 ) THEN
1186
! Parallel test, add the number of tasks as a suffix
1187
PassedMsg = "TEST.PASSED_"//I2S(ParEnv % PEs)
1188
OPEN( 10, FILE = PassedMsg )
1189
ELSE
1190
OPEN( 10, FILE = 'TEST.PASSED' )
1191
END IF
1192
IF( Success ) THEN
1193
WRITE( 10,'(I1)' ) 1
1194
ELSE
1195
WRITE( 10,'(I1)' ) 0
1196
END IF
1197
CALL FLUSH( 10 )
1198
CLOSE( 10 )
1199
1200
dt = ListGetConstReal(CurrentModel % Simulation,'Test Passed Delay', Found )
1201
IF(Found) CALL WaitSec(dt)
1202
END IF
1203
END IF
1204
1205
RETURN
1206
END IF
1207
1208
1209
DO solver_id=1,CurrentModel % NumberOfSolvers
1210
Solver => CurrentModel % Solvers(solver_id)
1211
1212
RefNorm = ListGetConstReal( Solver % Values,'Reference Norm', CompareNorm )
1213
CompareSolution = ListCheckPrefix( Solver % Values,'Reference Solution')
1214
1215
IF(.NOT. ( CompareNorm .OR. CompareSolution ) ) CYCLE
1216
1217
Var => Solver % Variable
1218
IF( .NOT. ASSOCIATED( Var ) ) THEN
1219
CALL Warn('CompareToReferenceSolution','Variable in Solver '&
1220
//I2S(i)//' not associated, cannot compare')
1221
CYCLE
1222
END IF
1223
1224
TestCount = TestCount + 1
1225
Success = .TRUE.
1226
1227
! Compare either to existing norm (ensures consistency)
1228
! or to existing solution (may also be used to directly verify)
1229
! Usually only either of these is given but for the sake of completeness
1230
! both may be used at the same time.
1231
IF( CompareNorm ) THEN
1232
Tol = ListGetConstReal( Solver % Values,'Reference Norm Tolerance', Found )
1233
IF(.NOT. Found ) Tol = 1.0d-5
1234
Norm = Var % Norm
1235
AbsoluteErr = ListGetLogical( Solver % Values,'Reference Norm Absolute', Found )
1236
Err = ABS( Norm - RefNorm )
1237
1238
IF(.NOT. AbsoluteErr ) THEN
1239
IF( RefNorm < TINY( RefNorm ) ) THEN
1240
CALL Warn('CompareToReferenceSolution','Refenrece norm too small for relative error')
1241
AbsoluteErr = .TRUE.
1242
ELSE
1243
Err = Err / RefNorm
1244
END IF
1245
END IF
1246
1247
! Compare to given reference norm
1248
IF( Err > Tol .OR. Err /= Err ) THEN
1249
! Warn only in the main core
1250
IF( ParEnv % MyPe == 0 ) THEN
1251
WRITE( Message,'(A,I0,A,ES15.8,A,ES15.8)') &
1252
'Solver ',solver_id,' FAILED: Norm =',Norm,' RefNorm =',RefNorm
1253
CALL Warn('CompareToReferenceSolution',Message)
1254
END IF
1255
Success = .FALSE.
1256
ELSE
1257
WRITE( Message,'(A,I0,A,ES15.8,A,ES15.8)') &
1258
'Solver ',solver_id,' PASSED: Norm =',Norm,' RefNorm =',RefNorm
1259
CALL Info('CompareToReferenceSolution',Message,Level=3)
1260
END IF
1261
IF( AbsoluteErr ) THEN
1262
WRITE( Message,'(A,ES13.6)') 'Absolute Error to reference norm:',Err
1263
ELSE
1264
WRITE( Message,'(A,ES13.6)') 'Relative Error to reference norm:',Err
1265
END IF
1266
CALL Info('CompareToReferenceSolution',Message, Level = 3 )
1267
END IF
1268
1269
IF( CompareSolution ) THEN
1270
Tol = ListGetConstReal( Solver % Values,'Reference Solution Tolerance', Found )
1271
IF(.NOT. Found ) Tol = 1.0d-5
1272
Dofs = Var % Dofs
1273
n = 0
1274
RefNorm = 0.0_dp
1275
Norm = 0.0_dp
1276
Err = 0.0_dp
1277
DO i=1,Solver % Mesh % NumberOfNodes
1278
j = Var % Perm(i)
1279
IF( j == 0 ) CYCLE
1280
DO k=1,Dofs
1281
IF( Dofs == 1 ) THEN
1282
refval = ListGetRealAtNode( Solver % Values,'Reference Solution',i,Found )
1283
ELSE
1284
refval = ListGetRealAtNode( Solver % Values,'Reference Solution '//I2S(k),i,Found )
1285
END IF
1286
IF( Found ) THEN
1287
val = Var % Values( Dofs*(j-1)+k)
1288
RefNorm = RefNorm + refval**2
1289
Norm = Norm + val**2
1290
Err = Err + (refval-val)**2
1291
n = n + 1
1292
END IF
1293
END DO
1294
END DO
1295
IF( ParEnv % PEs > 1 ) CALL Warn('CompareToReferefenSolution','Not implemented in parallel!')
1296
IF( n == 0 ) CALL Fatal('CompareToReferenceSolution','Could not find any reference solution')
1297
RefNorm = SQRT( RefNorm / n )
1298
Norm = SQRT( Norm / n )
1299
Err = SQRT( Err / n )
1300
1301
IF( Err > Tol ) THEN
1302
! Normally warning is done for every partition but this time it is the same for all
1303
IF( ParEnv % MyPe == 0 ) THEN
1304
WRITE( Message,'(A,I0,A,ES15.8,A,ES15.8)') &
1305
'Solver ',solver_id,' FAILED: Solution = ',Norm,' RefSolution =',RefNorm
1306
CALL Warn('CompareToReferenceSolution',Message)
1307
WRITE( Message,'(A,ES13.6)') 'Relative Error to reference solution:',Err
1308
CALL Info('CompareToReferenceSolution',Message, Level = 3 )
1309
END IF
1310
Success = .FALSE.
1311
ELSE
1312
WRITE( Message,'(A,I0,A,ES15.8,A,ES15.8)') &
1313
'Solver ',solver_id,' PASSED: Solution =',Norm,' RefSolution =',RefNorm
1314
CALL Info('CompareToReferenceSolution',Message,Level=3)
1315
END IF
1316
END IF
1317
1318
IF( Success ) PassCount = PassCount + 1
1319
END DO
1320
1321
END SUBROUTINE CompareToReferenceSolution
1322
1323
1324
SUBROUTINE AppendNewSolver(Model,pSolver)
1325
TYPE(Model_t) :: Model
1326
TYPE(Solver_t), POINTER :: pSolver
1327
1328
TYPE(Solver_t), POINTER :: OldSolvers(:),NewSolvers(:)
1329
INTEGER :: i, j,j2,j3,n, AllocStat
1330
1331
n = Model % NumberOfSolvers+1
1332
ALLOCATE( NewSolvers(n), STAT = AllocStat )
1333
IF( AllocStat /= 0 ) CALL Fatal('AppendNewSolver','Allocation error 1')
1334
1335
OldSolvers => Model % Solvers
1336
1337
CALL Info('AppendNewSolver','Increasing number of solvers to: '&
1338
//I2S(n),Level=8)
1339
DO i=1,n-1
1340
! Def_Dofs is the only allocatable structure within Solver_t:
1341
IF( ALLOCATED( OldSolvers(i) % Def_Dofs ) ) THEN
1342
j = SIZE(OldSolvers(i) % Def_Dofs,1)
1343
j2 = SIZE(OldSolvers(i) % Def_Dofs,2)
1344
j3 = SIZE(OldSolvers(i) % Def_Dofs,3)
1345
ALLOCATE( NewSolvers(i) % Def_Dofs(j,j2,j3), STAT = AllocStat )
1346
IF( AllocStat /= 0 ) CALL Fatal('AppendNewSolver','Allocation error 2')
1347
END IF
1348
1349
! Copy the content of the Solver structure
1350
NewSolvers(i) = OldSolvers(i)
1351
1352
! Nullify the old structure since otherwise bad things may happen at deallocation
1353
NULLIFY( OldSolvers(i) % ActiveElements )
1354
NULLIFY( OldSolvers(i) % Mesh )
1355
NULLIFY( OldSolvers(i) % BlockMatrix )
1356
NULLIFY( OldSolvers(i) % Matrix )
1357
NULLIFY( OldSolvers(i) % Variable )
1358
END DO
1359
1360
! Deallocate the old structure and set the pointer to the new one
1361
DEALLOCATE( Model % Solvers )
1362
Model % Solvers => NewSolvers
1363
Model % NumberOfSolvers = n
1364
1365
pSolver => NewSolvers(n)
1366
1367
NULLIFY( pSolver % Matrix )
1368
NULLIFY( pSolver % Mesh )
1369
NULLIFY( pSOlver % BlockMatrix )
1370
NULLIFY( pSolver % Variable )
1371
NULLIFY( pSolver % ActiveElements )
1372
1373
pSolver % PROCEDURE = 0
1374
pSolver % NumberOfActiveElements = 0
1375
j = CurrentModel % NumberOfBodies
1376
ALLOCATE( pSolver % Def_Dofs(10,j,6),STAT=AllocStat)
1377
IF( AllocStat /= 0 ) CALL Fatal('AppendNewSolver','Allocation error 3')
1378
pSolver % Def_Dofs = -1
1379
pSolver % Def_Dofs(:,:,1) = 1
1380
1381
! Create empty list to add some keywords to
1382
pSolver % Values => ListAllocate()
1383
1384
END SUBROUTINE AppendNewSolver
1385
1386
1387
!------------------------------------------------------------------------
1388
!> Given name of a solver module find it among the active solvers and
1389
!> upon success return its index.
1390
!------------------------------------------------------------------------
1391
FUNCTION FindSolverByProcName(Model,ProcName) RESULT (solver_id)
1392
IMPLICIT NONE
1393
1394
TYPE(Model_t), POINTER :: Model
1395
CHARACTER(*) :: ProcName
1396
INTEGER :: solver_id
1397
1398
LOGICAL :: Found
1399
INTEGER :: i,j
1400
CHARACTER(:), ALLOCATABLE :: str
1401
TYPE(Solver_t), POINTER :: pSolver
1402
1403
solver_id = 0
1404
Found = .FALSE.
1405
1406
DO i=1, Model % NumberOfSolvers
1407
pSolver => CurrentModel % Solvers(i)
1408
str = ListGetString(pSolver % Values,'Procedure',Found)
1409
IF(.NOT. Found) CYCLE
1410
1411
j = INDEX(str,ProcName)
1412
IF( j > 0 ) THEN
1413
solver_id = i
1414
EXIT
1415
END IF
1416
END DO
1417
1418
END FUNCTION FindSolverByProcName
1419
!------------------------------------------------------------------------------
1420
1421
1422
1423
! This is a dirty hack that adds an instance of ResultOutputSolver to the list of Solvers.
1424
! The idea is that it is much easier for the end user to take into use the vtu output this way.
1425
! The solver itself has limited set of parameters needed and is therefore approapriate for this
1426
! kind of hack. It can of course be also added as a regular solver also.
1427
!----------------------------------------------------------------------------------------------
1428
SUBROUTINE AddVtuOutputSolverHack()
1429
TYPE(Solver_t), POINTER :: pSolver
1430
CHARACTER(:), ALLOCATABLE :: str
1431
INTEGER :: j,k
1432
TYPE(ValueList_t), POINTER :: Params, Simu
1433
LOGICAL :: Found, VtuFormat
1434
INTEGER :: AllocStat
1435
LOGICAL, SAVE :: Visited = .FALSE.
1436
1437
Simu => CurrentModel % Simulation
1438
str = ListGetString( Simu,'Post File',Found)
1439
IF(.NOT. Found) RETURN
1440
1441
k = INDEX( str,'.vtu' )
1442
VtuFormat = ( k /= 0 )
1443
IF(.NOT. VtuFormat ) RETURN
1444
1445
! No use to create the same solver twice
1446
IF( Visited ) RETURN
1447
Visited = .TRUE.
1448
1449
CALL Info('AddVtuOutputSolverHack','Adding ResultOutputSolver to write VTU output in file: '&
1450
//TRIM(str(1:k-1)))
1451
1452
j = FindSolverByProcName(CurrentModel,'ResultOutputSolver')
1453
IF(j>0) THEN
1454
pSolver => CurrentModel % Solvers(j)
1455
IF( ListGetLogical( pSolver % Values,'Vtu Format',Found) .OR. &
1456
ListGetString(pSolver % Values,'Output Format',Found) == 'vtu' ) THEN
1457
CALL Warn('AddVtuOutputSolverHack','ResultOutputSolver instance with VTU format already exists, doing nothing!')
1458
RETURN
1459
END IF
1460
END IF
1461
1462
! Remove the post file from the simulation list as it will be dealt by the solver section
1463
CALL ListRemove( Simu,'Post File')
1464
1465
! Allocate one new solver to the end of list and get pointer to it
1466
CALL AppendNewSolver(CurrentModel,pSolver)
1467
1468
! Now create the ResultOutputSolver instance on-the-fly
1469
Params => pSolver % Values
1470
CALL ListAddString(Params,'Procedure', 'ResultOutputSolve ResultOutputSolver',.FALSE.)
1471
CALL ListAddString(Params,'Equation','InternalVtuOutputSolver')
1472
CALL ListAddString(Params,'Output Format','vtu')
1473
CALL ListAddString(Params,'Output File Name',str(1:k-1),.FALSE.)
1474
CALL ListAddLogical(Params,'No Matrix',.TRUE.)
1475
CALL ListAddNewString(Params,'Variable','-global vtu_internal_dummy')
1476
CALL ListAddString(Params,'Exec Solver','after saving')
1477
CALL ListAddLogical(Params,'Save Geometry IDs',.TRUE.)
1478
1479
! Add a few often needed keywords also if they are given in simulation section
1480
CALL ListCopyPrefixedKeywords( Simu, Params, 'vtu:' )
1481
1482
! It makes sense to inherit global ascii/binary flags if not given
1483
CALL ListCompareAndCopy(CurrentModel % Simulation, Params, 'ascii output', nooverwrite = .TRUE. )
1484
CALL ListCompareAndCopy(CurrentModel % Simulation, Params, 'binary output', nooverwrite = .TRUE. )
1485
1486
CALL Info('AddVtuOutputSolverHack','Finished appending VTU output solver',Level=12)
1487
1488
END SUBROUTINE AddVtuOutputSolverHack
1489
1490
1491
! This is a dirty hack that adds an instance of SaveScalars to the list of Solvers.
1492
! The idea is that it is much easier for the end user to add a basic instance.
1493
!----------------------------------------------------------------------------------------------
1494
SUBROUTINE AddSaveScalarsHack()
1495
TYPE(Solver_t), POINTER :: ABC(:), PSolver
1496
CHARACTER(:), ALLOCATABLE :: str
1497
INTEGER :: k
1498
TYPE(ValueList_t), POINTER :: Params, Simu
1499
LOGICAL :: Found, VtuFormat
1500
INTEGER :: AllocStat
1501
LOGICAL, SAVE :: Visited = .FALSE.
1502
1503
Simu => CurrentModel % Simulation
1504
str = ListGetString( Simu,'Scalars File',Found)
1505
IF(.NOT. Found) RETURN
1506
1507
! No use to create the same solver twice
1508
IF( Visited ) RETURN
1509
Visited = .TRUE.
1510
1511
CALL Info('AddSaveScalarsHack','Adding SaveScalars solver to write scalars into file: '&
1512
//TRIM(str))
1513
1514
k = FindSolverByProcName(CurrentModel,'SaveScalars')
1515
IF(k>0) THEN
1516
CALL Warn('AddSaveScalarsHack','SaveScalars instance already exists, doing nothing!')
1517
RETURN
1518
END IF
1519
1520
! Allocate one new solver to the end of list and get pointer to it
1521
CALL AppendNewSolver(CurrentModel,pSolver)
1522
1523
! Add some keywords to the list
1524
Params => pSolver % Values
1525
CALL ListAddString(Params,'Procedure', 'SaveData SaveScalars',.FALSE.)
1526
CALL ListAddString(Params,'Equation','InternalSaveScalars')
1527
CALL ListAddString(Params,'Filename',TRIM(str),.FALSE.)
1528
CALL ListAddString(Params,'Exec Solver','after saving')
1529
1530
! Add a few often needed keywords also if they are given in simulation section
1531
CALL ListCopyPrefixedKeywords( Simu, Params, 'scalars:' )
1532
1533
CALL Info('AddSaveScalarsHack','Finished appending SaveScalars solver',Level=12)
1534
1535
END SUBROUTINE AddSaveScalarsHack
1536
1537
1538
1539
!------------------------------------------------------------------------------
1540
!> Adds flags for active solvers.
1541
!------------------------------------------------------------------------------
1542
SUBROUTINE AddSolvers()
1543
!------------------------------------------------------------------------------
1544
INTEGER :: i,j,k,n,nlen
1545
LOGICAL :: InitSolver, Found, DoTiming
1546
TYPE(Mesh_t), POINTER :: pMesh
1547
!------------------------------------------------------------------------------
1548
1549
CALL Info('AddSolvers','Setting up '//I2S(CurrentModel % NumberOfSolvers)//&
1550
' solvers',Level=10)
1551
1552
! This is a hack that sets Equation flags True for the "Active Solvers".
1553
! The Equation flag is the legacy way of setting a Solver active and is still
1554
! used internally. Also set WhenExec flag since we might want to call some
1555
! solvers immediately.
1556
!----------------------------------------------------------------------------
1557
DO i=1,CurrentModel % NumberOfSolvers
1558
Solver => CurrentModel % Solvers(i)
1559
1560
eq = ListGetString( Solver % Values,'Equation', Found )
1561
IF ( Found ) THEN
1562
nlen = LEN_TRIM(eq)
1563
DO j=1,CurrentModel % NumberOFEquations
1564
ActiveSolvers => ListGetIntegerArray( CurrentModel % Equations(j) % Values, &
1565
'Active Solvers', Found )
1566
IF ( Found ) THEN
1567
DO k=1,SIZE(ActiveSolvers)
1568
IF ( ActiveSolvers(k) == i ) THEN
1569
CALL ListAddLogical( CurrentModel % Equations(j) % Values, eq(1:nlen), .TRUE. )
1570
EXIT
1571
END IF
1572
END DO
1573
END IF
1574
END DO
1575
END IF
1576
1577
CALL AddExecWhenFlag( Solver )
1578
END DO
1579
1580
1581
! Add the dynamically linked solver to be called later
1582
! First do the initialization for solvers that other solvers except
1583
! before initialization having the "when created" slot.
1584
!---------------------------------------------------------------------
1585
DO i=1,CurrentModel % NumberOfSolvers
1586
Solver => CurrentModel % Solvers(i)
1587
IF ( Solver % SolverExecWhen /= SOLVER_EXEC_WHENCREATED ) CYCLE
1588
1589
eq = ListGetString( Solver % Values,'Equation', Found )
1590
CALL Info('AddSolvers','Setting up solver '//I2S(i)//': '//TRIM(eq),Level=10)
1591
1592
InitSolver = ListGetLogical( Solver % Values, 'Initialize', Found )
1593
IF ( Found .AND. InitSolver ) THEN
1594
CALL FreeMatrix( Solver % Matrix )
1595
CALL ListAddLogical( Solver % Values, 'Initialize', .FALSE. )
1596
END IF
1597
1598
IF ( Solver % PROCEDURE == 0 .OR. InitSolver ) THEN
1599
IF ( .NOT. ASSOCIATED( Solver % Mesh ) ) THEN
1600
Solver % Mesh => CurrentModel % Meshes
1601
END IF
1602
1603
n = ListGetInteger( Solver % Values,'Relative Mesh Level',Found )
1604
IF( Found .AND. n /= 0) THEN
1605
IF( n > 0 ) CALL Fatal('AddSolvers','Relative Mesh Level should ne negative!')
1606
j = 0
1607
DO WHILE(j > n)
1608
pMesh => pMesh % Parent
1609
IF(.NOT. ASSOCIATED(pMesh)) EXIT
1610
j = j-1
1611
END DO
1612
IF(ASSOCIATED(pMesh) ) THEN
1613
CALL Info('AddSolvers','Using relative mesh level '//I2S(n),Level=10)
1614
ELSE
1615
CALL Fatal('AddSolvers','Could not find relative mesh level: '//I2S(n))
1616
END IF
1617
Solver % Mesh => pMesh
1618
END IF
1619
1620
1621
DoTiming = ListGetLogical( Solver % Values,'Solver Timing', Found )
1622
IF( DoTiming ) CALL ResetTimer('SolverInitialization')
1623
1624
CurrentModel % Solver => Solver
1625
CALL AddEquationBasics( Solver, eq, Transient )
1626
CALL AddEquationSolution( Solver, Transient )
1627
1628
IF( DoTiming ) CALL CheckTimer('SolverInitialization',Level=7,Delete=.TRUE.)
1629
1630
CALL Info('AddSolvers','Executing solver '//I2S(i)//' immediately when created!,Level=5')
1631
CALL SetCurrentMesh( CurrentModel, Solver % Mesh )
1632
CALL SingleSolver( CurrentModel, Solver, 0.0_dp, .FALSE. )
1633
END IF
1634
END DO
1635
1636
1637
! And now initialize the other solvers
1638
!---------------------------------------------------------------------
1639
DO i=1,CurrentModel % NumberOfSolvers
1640
Solver => CurrentModel % Solvers(i)
1641
IF ( Solver % SolverExecWhen == SOLVER_EXEC_WHENCREATED ) CYCLE
1642
1643
eq = ListGetString( Solver % Values,'Equation', Found )
1644
CALL Info('AddSolvers','Setting up solver '//I2S(i)//': '//TRIM(eq),Level=10)
1645
1646
InitSolver = ListGetLogical( Solver % Values, 'Initialize', Found )
1647
IF ( Found .AND. InitSolver ) THEN
1648
CALL FreeMatrix( Solver % Matrix )
1649
CALL ListAddLogical( Solver % Values, 'Initialize', .FALSE. )
1650
END IF
1651
1652
IF ( Solver % PROCEDURE == 0 .OR. InitSolver ) THEN
1653
IF ( .NOT. ASSOCIATED( Solver % Mesh ) ) THEN
1654
Solver % Mesh => CurrentModel % Meshes
1655
END IF
1656
CurrentModel % Solver => Solver
1657
1658
DoTiming = ListGetLogical( Solver % Values,'Solver Timing', Found )
1659
IF( DoTiming ) CALL ResetTimer('SolverInitialization')
1660
1661
CALL AddEquationBasics( Solver, eq, Transient )
1662
CALL AddEquationSolution( Solver, Transient )
1663
1664
IF( DoTiming ) CALL CheckTimer('SolverInitialization',Level=7,Delete=.TRUE.)
1665
END IF
1666
END DO
1667
1668
CALL Info('AddSolvers','Setting up solvers done',Level=12)
1669
1670
!------------------------------------------------------------------------------
1671
END SUBROUTINE AddSolvers
1672
!------------------------------------------------------------------------------
1673
1674
1675
!------------------------------------------------------------------------------
1676
!> Adds coordinate as variables to the current mesh structure.
1677
!------------------------------------------------------------------------------
1678
SUBROUTINE AddMeshCoordinates()
1679
!------------------------------------------------------------------------------
1680
CALL Info('AddMeshCoordinates','Setting mesh coordinates and time',Level=10)
1681
1682
Mesh => CurrentModel % Meshes
1683
DO WHILE( ASSOCIATED( Mesh ) )
1684
CALL VariableAdd( Mesh % Variables, Mesh, &
1685
Name='Coordinate 1',DOFs=1,Values=Mesh % Nodes % x )
1686
1687
CALL VariableAdd(Mesh % Variables,Mesh, &
1688
Name='Coordinate 2',DOFs=1,Values=Mesh % Nodes % y )
1689
1690
CALL VariableAdd(Mesh % Variables,Mesh, &
1691
Name='Coordinate 3',DOFs=1,Values=Mesh % Nodes % z )
1692
Mesh => Mesh % Next
1693
END DO
1694
1695
!------------------------------------------------------------------------------
1696
END SUBROUTINE AddMeshCoordinates
1697
!------------------------------------------------------------------------------
1698
1699
1700
1701
!------------------------------------------------------------------------------
1702
!> Adds coordinate and time variables to the current mesh structure.
1703
!------------------------------------------------------------------------------
1704
SUBROUTINE AddTimeEtc()
1705
!------------------------------------------------------------------------------
1706
TYPE(Variable_t), POINTER :: DtVar
1707
1708
CALL Info('AddTimeEtc','Setting time and other global variables',Level=10)
1709
1710
NULLIFY( Solver )
1711
1712
Mesh => CurrentModel % Meshes
1713
DO WHILE( ASSOCIATED( Mesh ) )
1714
CALL VariableAdd( Mesh % Variables, Mesh, Name='Time',DOFs=1, Values=sTime )
1715
CALL VariableAdd( Mesh % Variables, Mesh, Name='Timestep', DOFs=1, Values=sStep )
1716
CALL VariableAdd( Mesh % Variables, Mesh, Name='Timestep size', DOFs=1, Values=sSize )
1717
CALL VariableAdd( Mesh % Variables, Mesh, Name='Timestep interval', DOFs=1, Values=sInterval )
1718
1719
! Save some previous timesteps for variable timestep multistep methods
1720
DtVar => VariableGet( Mesh % Variables, 'Timestep size' )
1721
DtVar % PrevValues => sPrevSizes
1722
1723
CALL VariableAdd( Mesh % Variables, Mesh, &
1724
Name='nonlin iter', DOFs=1, Values=nonlinIt )
1725
CALL VariableAdd( Mesh % Variables, Mesh, &
1726
Name='coupled iter', DOFs=1, Values=steadyIt )
1727
1728
1729
IF( ListCheckPrefix( CurrentModel % Simulation,'Periodic Time') .OR. &
1730
ListCheckPresent( CurrentModel % Simulation,'Time Period') ) THEN
1731
! For periodic systems we may do several cycles.
1732
CALL VariableAdd( Mesh % Variables, Mesh, Name='Periodic Time',DOFs=1, Values=sPeriodicTime )
1733
CALL VariableAdd( Mesh % Variables, Mesh, Name='Periodic Cycle',DOFs=1, Values=sPeriodicCycle )
1734
1735
! After convergence is reached we may start producing the results.
1736
CALL VariableAdd( Mesh % Variables, Mesh, Name='Finish',DOFs=1, Values=sFinish )
1737
CALL VariableAdd( Mesh % Variables, Mesh, Name='Produce',DOFs=1, Values=sProduce )
1738
END IF
1739
1740
IF( ListCheckPresent( CurrentModel % Simulation,'Rotor Angle') ) THEN
1741
CALL VariableAdd( Mesh % Variables, Mesh, Name='rotor angle',DOFs=1, Values=sAngle )
1742
CALL VariableAdd( Mesh % Variables, Mesh, Name='rotor velo',DOFs=1, Values=sAngleVelo )
1743
END IF
1744
1745
IF( ListCheckPresentAnySolver( CurrentModel,'Scanning Loops') ) THEN
1746
CALL VariableAdd( Mesh % Variables, Mesh, Name='scan', DOFs=1, Values=sScan )
1747
END IF
1748
1749
IF( DoControl ) THEN
1750
sSweep = 1.0_dp * iSweep
1751
CALL VariableAdd( Mesh % Variables, Mesh, Name='run', DOFs=1, Values=sSweep )
1752
END IF
1753
1754
sPar(1) = 1.0_dp * ParEnv % MyPe
1755
CALL VariableAdd( Mesh % Variables, Mesh, Name='Partition', DOFs=1, Values=sPar )
1756
1757
IF( ListCheckPresent( CurrentModel % Simulation,'Parallel Slices') ) THEN
1758
CALL VariableAdd( Mesh % Variables, Mesh, Name='slice', DOFs=1, Values=sSlice )
1759
CALL VariableAdd( Mesh % Variables, Mesh, Name='slice ratio', DOFs=1, Values=sSliceRatio )
1760
CALL VariableAdd( Mesh % Variables, Mesh, Name='slice weight', DOFs=1, Values=sSliceWeight )
1761
END IF
1762
1763
IF( ListCheckPresent( CurrentModel % Simulation,'Parallel Timestepping') ) THEN
1764
CALL VariableAdd( Mesh % Variables, Mesh, Name='time sector', DOFs=1, Values=sSector )
1765
END IF
1766
1767
! Add partition as a elemental field in case we have just one partition
1768
! and have asked still for partitioning into many.
1769
IF( ParEnv % PEs == 1 .AND. ASSOCIATED( Mesh % Repartition ) ) THEN
1770
BLOCK
1771
REAL(KIND=dp), POINTER :: PartField(:)
1772
INTEGER, POINTER :: PartPerm(:)
1773
INTEGER :: i,n
1774
1775
CALL Info('AddTimeEtc','Adding partitioning also as a field')
1776
1777
n = Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
1778
1779
NULLIFY( PartField, PartPerm )
1780
ALLOCATE( PartField(n), PartPerm(n) )
1781
DO i=1,n
1782
PartPerm(i) = i
1783
PartField(i) = 1.0_dp * Mesh % RePartition(i)
1784
END DO
1785
1786
CALL VariableAdd( Mesh % Variables, Mesh, Name='PartField',DOFs=1, &
1787
Values=PartField, Perm=PartPerm, TYPE=Variable_on_elements)
1788
END BLOCK
1789
END IF
1790
1791
Mesh => Mesh % Next
1792
1793
END DO
1794
!------------------------------------------------------------------------------
1795
END SUBROUTINE AddTimeEtc
1796
!------------------------------------------------------------------------------
1797
1798
1799
!------------------------------------------------------------------------------
1800
!> Sets initial conditions for the fields.
1801
!------------------------------------------------------------------------------
1802
SUBROUTINE SetInitialConditions()
1803
!------------------------------------------------------------------------------
1804
USE CoordinateSystems, ONLY : CoordinateSystemDimension
1805
1806
INTEGER :: DOFs
1807
CHARACTER(:), ALLOCATABLE :: str
1808
LOGICAL :: Found, NamespaceFound
1809
TYPE(Solver_t), POINTER :: Solver
1810
INTEGER, ALLOCATABLE :: Indexes(:)
1811
REAL(KIND=dp),ALLOCATABLE :: Work(:)
1812
1813
INTEGER :: i,j,k,l,m,vect_dof,real_dof,dim
1814
1815
REAL(KIND=dp) :: nrm(3),t1(3),t2(3),vec(3),tmp(3),udot
1816
TYPE(ValueList_t), POINTER :: BC
1817
TYPE(Nodes_t), SAVE :: Nodes
1818
LOGICAL :: nt_boundary, DG
1819
TYPE(Element_t), POINTER :: Element
1820
TYPE(Variable_t), POINTER :: var, vect_var
1821
LOGICAL :: AnyNameSpace
1822
TYPE(Element_t), POINTER :: p
1823
1824
CALL Info('SetInitialConditions','Setting up initial conditions (if any)',Level=10)
1825
1826
1827
dim = CoordinateSystemDimension()
1828
1829
IF (GetLogical(GetSimulation(),'Restart Before Initial Conditions',Found)) THEN
1830
CALL Restart()
1831
CALL InitCond()
1832
ELSE
1833
CALL InitCond()
1834
CALL Restart()
1835
END IF
1836
1837
CALL Info('SetInitialConditions','Initial conditions set',Level=20)
1838
1839
!------------------------------------------------------------------------------
1840
! Make sure that initial values at boundaries are set correctly.
1841
! NOTE: This overrides the initial condition setting for field variables!!!!
1842
!-------------------------------------------------------------------------------
1843
InitDirichlet = ListGetLogical( CurrentModel % Simulation, &
1844
'Initialize Dirichlet Conditions', GotIt )
1845
IF ( .NOT. GotIt ) InitDirichlet = .TRUE.
1846
1847
AnyNameSpace = ListCheckPresentAnySolver( CurrentModel,'Namespace')
1848
NamespaceFound = .FALSE.
1849
1850
vect_var => NULL()
1851
IF ( InitDirichlet ) THEN
1852
Mesh => CurrentModel % Meshes
1853
DO WHILE( ASSOCIATED(Mesh) )
1854
ALLOCATE( Work(Mesh % MaxElementDOFs) )
1855
CALL SetCurrentMesh( CurrentModel, Mesh )
1856
1857
DO t = Mesh % NumberOfBulkElements + 1, &
1858
Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
1859
1860
Element => Mesh % Elements(t)
1861
1862
! Set also the current element pointer in the model structure to
1863
! reflect the element being processed:
1864
! ---------------------------------------------------------------
1865
CurrentModel % CurrentElement => Element
1866
n = Element % TYPE % NumberOfNodes
1867
1868
BC => GetBC()
1869
IF(.NOT.ASSOCIATED(BC)) CYCLE
1870
1871
Var => Mesh % Variables
1872
DO WHILE( ASSOCIATED(Var) )
1873
Solver => Var % Solver
1874
IF ( .NOT. ASSOCIATED(Solver) ) Solver => CurrentModel % Solver
1875
1876
IF( AnyNameSpace ) THEN
1877
str = ListGetString( Solver % Values, 'Namespace', NamespaceFound )
1878
IF (NamespaceFound) CALL ListPushNamespace(str)
1879
END IF
1880
1881
! This seems to be a more robust marker for DG type
1882
DG = ( Var % Type == Variable_on_nodes_on_elements )
1883
1884
1885
IF ( Var % DOFs <= 1 ) THEN
1886
Work(1:n) = GetReal( BC,Var % Name, gotIt )
1887
IF ( GotIt ) THEN
1888
1889
nt_boundary = .FALSE.
1890
IF ( GetElementFamily() /= 1 ) THEN
1891
k = LEN_TRIM(var % name)
1892
vect_dof = ICHAR(Var % Name(k:k))-ICHAR('0');
1893
IF ( vect_dof>=1 .AND. vect_dof<= 3 ) THEN
1894
nt_boundary = GetLogical( BC, &
1895
'normal-tangential '//var % name(1:k-2), gotIt)
1896
1897
IF ( nt_boundary ) THEN
1898
nt_boundary = .FALSE.
1899
Vect_var => Mesh % Variables
1900
DO WHILE( ASSOCIATED(Vect_var) )
1901
IF ( Vect_var % Dofs>=dim ) THEN
1902
DO real_dof=1,Vect_var % Dofs
1903
nt_boundary = ASSOCIATED(Var % Values, &
1904
Vect_var % Values(real_dof::Vect_var % Dofs))
1905
IF ( nt_boundary ) EXIT
1906
END DO
1907
IF ( nt_boundary ) EXIT
1908
END IF
1909
Vect_var => Vect_var % Next
1910
END DO
1911
END IF
1912
1913
IF ( nt_boundary ) THEN
1914
CALL GetElementNodes(Nodes)
1915
nrm = NormalVector(Element,Nodes,0._dp,0._dp,.TRUE.)
1916
SELECT CASE(Element % TYPE % DIMENSION)
1917
CASE(1)
1918
t1(1) = nrm(2)
1919
t1(2) = -nrm(1)
1920
CASE(2)
1921
CALL TangentDirections(nrm,t1,t2)
1922
END SELECT
1923
1924
SELECT CASE(vect_dof)
1925
CASE(1)
1926
vec = nrm
1927
CASE(2)
1928
vec = t1
1929
CASE(3)
1930
vec = t2
1931
END SELECT
1932
END IF
1933
END IF
1934
END IF
1935
1936
DO j=1,n
1937
IF ( DG ) THEN
1938
k = 0
1939
p => Element % BoundaryInfo % Left
1940
IF( ASSOCIATED( p ) ) THEN
1941
DO i=1,p % TYPE % NumberOfNodes
1942
IF(p % NodeIndexes(i) == Element % NodeIndexes(j) ) THEN
1943
k = p % DGIndexes(i); EXIT
1944
END IF
1945
END DO
1946
IF ( ASSOCIATED(Var % Perm) ) k = Var % Perm(k)
1947
END IF
1948
! The active BC could be on either side!
1949
! If this is an internal BC this may really be poorly defined.
1950
IF( k == 0 ) THEN
1951
p => Element % BoundaryInfo % Right
1952
IF( ASSOCIATED( p ) ) THEN
1953
DO i=1,p % TYPE % NumberOfNodes
1954
IF(p % NodeIndexes(i) == Element % NodeIndexes(j) ) THEN
1955
k = p % DGIndexes(i); EXIT
1956
END IF
1957
END DO
1958
IF ( ASSOCIATED(Var % Perm) ) k = Var % Perm(k)
1959
END IF
1960
END IF
1961
ELSE
1962
k = Element % NodeIndexes(j)
1963
IF ( ASSOCIATED(Var % Perm) ) k = Var % Perm(k)
1964
END IF
1965
1966
IF ( k>0 ) THEN
1967
IF ( nt_boundary ) THEN
1968
DO l=1,dim
1969
m = l+real_dof-vect_dof
1970
tmp(l)=Vect_var % Values(Vect_var % Dofs*(k-1)+m)
1971
END DO
1972
udot = SUM(vec(1:dim)*tmp(1:dim))
1973
tmp(1:dim)=tmp(1:dim)+(work(j)-udot)*vec(1:dim)
1974
DO l=1,dim
1975
m = l+real_dof-vect_dof
1976
Vect_var % Values(Vect_var % Dofs*(k-1)+m)=tmp(l)
1977
END DO
1978
ELSE
1979
Var % Values(k) = Work(j)
1980
END IF
1981
END IF
1982
END DO
1983
END IF
1984
1985
IF ( Transient .AND. Solver % TimeOrder==2 ) THEN
1986
Work(1:n) = GetReal( BC, TRIM(Var % Name) // ' Velocity', GotIt )
1987
IF ( GotIt ) THEN
1988
DO j=1,n
1989
k = Element % NodeIndexes(j)
1990
IF ( ASSOCIATED(Var % Perm) ) k = Var % Perm(k)
1991
IF ( k>0 ) Var % PrevValues(k,1) = Work(j)
1992
END DO
1993
END IF
1994
Work(1:n) = GetReal( BC, TRIM(Var % Name) // ' Acceleration', GotIt )
1995
IF ( GotIt ) THEN
1996
DO j=1,n
1997
k = Element % NodeIndexes(j)
1998
IF ( ASSOCIATED(Var % Perm) ) k = Var % Perm(k)
1999
IF ( k>0 ) THEN
2000
Var % PrevValues(k,2) = Work(j)
2001
Var % PrevValues(k,6) = Work(j)
2002
END IF
2003
END DO
2004
END IF
2005
END IF
2006
ELSE
2007
CALL ListGetRealArray( BC, &
2008
Var % Name, WorkA, n, Element % NodeIndexes, gotIt )
2009
IF ( GotIt ) THEN
2010
DO j=1,n
2011
k = Element % NodeIndexes(j)
2012
IF ( ASSOCIATED(Var % Perm) ) k = Var % Perm(k)
2013
IF(k>0) THEN
2014
DO l=1,MIN(SIZE(WorkA,1),Var % DOFs)
2015
Var % Values(Var % DOFs*(k-1)+l) = WorkA(l,1,j)
2016
END DO
2017
END IF
2018
END DO
2019
ELSE
2020
END IF
2021
END IF
2022
2023
IF(NamespaceFound) CALL ListPopNamespace()
2024
Var => Var % Next
2025
END DO
2026
END DO
2027
DEALLOCATE( Work )
2028
Mesh => Mesh % Next
2029
END DO
2030
END IF
2031
2032
CALL Info('SetInitialConditions','Initial values for boundaries set',Level=20)
2033
2034
2035
!------------------------------------------------------------------------------
2036
END SUBROUTINE SetInitialConditions
2037
!------------------------------------------------------------------------------
2038
2039
2040
!------------------------------------------------------------------------------
2041
SUBROUTINE InitCond()
2042
!------------------------------------------------------------------------------
2043
USE Integration, ONLY : GaussIntegrationPoints_t
2044
USE SolverUtils, ONLY : GaussPointsAdapt
2045
USE ElementDescription, ONLY : ElementInfo
2046
2047
TYPE(Element_t), POINTER :: Edge
2048
INTEGER :: DOFs,i,i2,j,k,k1,k2,l,n,n2,m,nsize
2049
CHARACTER(:), ALLOCATABLE :: str, VarName
2050
LOGICAL :: Found, ThingsToDO, NamespaceFound, AnyNameSpace
2051
TYPE(Solver_t), POINTER :: Solver, CSolver
2052
INTEGER, ALLOCATABLE :: Indexes(:)
2053
REAL(KIND=dp) :: Val
2054
REAL(KIND=dp),ALLOCATABLE :: Work(:)
2055
TYPE(ValueList_t), POINTER :: IC
2056
TYPE(Nodes_t) :: Nodes
2057
TYPE(GaussIntegrationPoints_t) :: IP
2058
REAL(KIND=dp), ALLOCATABLE :: Basis(:)
2059
REAL(KIND=dp) :: DetJ
2060
TYPE(Element_t), POINTER :: Element, p
2061
TYPE(ValueHandle_t) :: LocalSol_h
2062
LOGICAL :: Stat, FoundIC, PrevFoundIC
2063
INTEGER :: VarOrder, PrevBodyId
2064
!------------------------------------------------------------------------------
2065
2066
AnyNameSpace = ListCheckPresentAnySolver( CurrentModel,'namespace')
2067
NameSpaceFound = .FALSE.
2068
2069
Mesh => CurrentModel % Meshes
2070
DO WHILE( ASSOCIATED( Mesh ) )
2071
2072
CALL SetCurrentMesh( CurrentModel, Mesh )
2073
2074
IF( InfoActive( 30 ) ) THEN
2075
CALL Info('InitCond','Initial conditions for '//I2S(Mesh % MeshDim)//'D mesh:'//TRIM(Mesh % Name))
2076
Var => Mesh % Variables
2077
DO WHILE( ASSOCIATED(Var) )
2078
IF( ListCheckPresentAnyIC( CurrentModel, Var % Name ) ) THEN
2079
CALL VectorValuesRange(Var % Values,SIZE(Var % Values),'PreInit: '//TRIM(Var % Name))
2080
END IF
2081
Var => Var % Next
2082
END DO
2083
END IF
2084
2085
m = Mesh % MaxElementDofs
2086
n = Mesh % MaxElementNodes
2087
ALLOCATE( Indexes(m), Work(m) , Basis(m), Nodes % x(n), Nodes % y(n), Nodes % z(n) )
2088
2089
! First set the global variables and check whether there is anything left to do
2090
ThingsToDo = .FALSE.
2091
DO j=1,CurrentModel % NumberOfICs
2092
2093
IC => CurrentModel % ICs(j) % Values
2094
2095
Var => Mesh % Variables
2096
DO WHILE( ASSOCIATED(Var) )
2097
2098
IF( .NOT. ASSOCIATED( Var % Values ) ) THEN
2099
Var => Var % Next
2100
CYCLE
2101
END IF
2102
2103
IF( SIZE( Var % Values ) == 0 ) THEN
2104
Var => Var % Next
2105
CYCLE
2106
END IF
2107
2108
Solver => Var % Solver
2109
IF ( .NOT. ASSOCIATED(Solver) ) Solver => CurrentModel % Solver
2110
2111
IF( AnyNameSpace ) THEN
2112
str = ListGetString( Solver % Values, 'Namespace', NamespaceFound )
2113
IF (NamespaceFound) CALL ListPushNamespace(TRIM(str))
2114
END IF
2115
2116
! global variable
2117
IF( SIZE( Var % Values ) == Var % DOFs .OR. Var % Type == Variable_global ) THEN
2118
Val = ListGetCReal( IC, Var % Name, GotIt )
2119
IF( GotIt ) THEN
2120
WRITE( Message,'(A,ES12.3)') 'Initializing global variable: > '&
2121
//TRIM(Var % Name)//' < to :',Val
2122
CALL Info('InitCond', Message,Level=8)
2123
Var % Values = Val
2124
END IF
2125
ELSE
2126
ThingsToDo = ThingsToDo .OR. &
2127
ListCheckPresent( IC, TRIM(Var % Name) )
2128
ThingsToDo = ThingsToDo .OR. &
2129
ListCheckPresent( IC, TRIM(Var % Name)//' Velocity' )
2130
ThingsToDo = ThingsToDo .OR. &
2131
ListCheckPresent( IC, TRIM(Var % Name)//' Acceleration' )
2132
ThingsToDo = ThingsToDo .OR. &
2133
ListCheckPresent( IC, TRIM(Var % Name)//' {e}' )
2134
END IF
2135
IF (NamespaceFound) CALL ListPopNamespace()
2136
Var => Var % Next
2137
END DO
2138
END DO
2139
2140
2141
! And now do the ordinary fields
2142
!--------------------------------
2143
IF( ThingsToDo ) THEN
2144
DO t=1, Mesh % NumberOfBulkElements+Mesh % NumberOfBoundaryElements
2145
2146
Element => Mesh % Elements(t)
2147
2148
GotIt = .FALSE.
2149
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
2150
i = Element % BoundaryInfo % Constraint
2151
IF ( i >= 1 .AND. i <= CurrentModel % NumberOfBCs) THEN
2152
j = ListGetInteger(CurrentModel % BCs(i) % Values, &
2153
'Initial Condition',GotIt, 1, CurrentModel % NumberOfBCs )
2154
END IF
2155
END IF
2156
2157
IF ( .NOT. GotIt ) THEN
2158
i = Element % BodyId
2159
IF( i == 0 ) CYCLE
2160
2161
j = ListGetInteger(CurrentModel % Bodies(i) % Values, &
2162
'Initial Condition',GotIt, 1, CurrentModel % NumberOfICs )
2163
IF ( .NOT. GotIt ) CYCLE
2164
END IF
2165
2166
IC => CurrentModel % ICs(j) % Values
2167
CurrentModel % CurrentElement => Element
2168
n = GetElementNOFNodes()
2169
2170
Var => Mesh % Variables
2171
DO WHILE( ASSOCIATED(Var) )
2172
2173
IF( .NOT. ASSOCIATED( Var % Values ) ) THEN
2174
Var => Var % Next
2175
CYCLE
2176
END IF
2177
2178
IF( SIZE( Var % Values ) == 0 ) THEN
2179
Var => Var % Next
2180
CYCLE
2181
END IF
2182
2183
IF( t == 1 ) THEN
2184
CALL Info('InitCond','Trying to initialize variable: '//TRIM(Var % Name),Level=20)
2185
END IF
2186
2187
Solver => Var % Solver
2188
IF ( .NOT. ASSOCIATED(Solver) ) THEN
2189
Solver => CurrentModel % Solver
2190
END IF
2191
CSolver => CurrentModel % Solver
2192
CurrentModel % Solver => Solver
2193
2194
IF( AnyNameSpace ) THEN
2195
str = ListGetString( Solver % Values, 'Namespace', NamespaceFound )
2196
IF (NamespaceFound) CALL ListPushNamespace(TRIM(str))
2197
END IF
2198
2199
! global variables were already set
2200
IF( SIZE( Var % Values ) == Var % DOFs .OR. Var % Type == Variable_global ) THEN
2201
CONTINUE
2202
2203
ELSE IF( Var % TYPE == Variable_on_elements ) THEN
2204
IF( Var % DOFs > 1 ) THEN
2205
CALL Fatal('InitCond','Initialization only for scalar elements fields!')
2206
END IF
2207
2208
Work(1:n) = GetReal( IC, Var % Name, GotIt )
2209
IF ( GotIt ) THEN
2210
k1 = Element % ElementIndex
2211
IF ( ASSOCIATED(Var % Perm) ) k1 = Var % Perm(k1)
2212
IF ( k1>0 ) Var % Values(k1) = SUM( Work(1:n) ) / n
2213
END IF
2214
2215
ELSE IF( Var % TYPE == Variable_on_gauss_points ) THEN
2216
! We do this elsewhere in a more efficient manner
2217
CONTINUE
2218
2219
ELSE IF ( Var % DOFs == 1 ) THEN
2220
2221
Work(1:n) = ListGetReal( IC, Var % Name, n, Element % NodeIndexes, GotIt )
2222
2223
IF ( GotIt ) THEN
2224
! Sometimes you may have both DG and bubbles,
2225
! this way DG always has priority.
2226
IF( Var % TYPE == Variable_on_nodes_on_elements ) THEN
2227
DO k=1,n
2228
IF( ASSOCIATED( Element % DGIndexes) ) THEN
2229
! DG variable has always a permutation associated to it!
2230
k1 = Var % Perm(Element % DgIndexes(k))
2231
ELSE
2232
k1 = 0
2233
p => Element % BoundaryInfo % Left
2234
IF( ASSOCIATED( p ) ) THEN
2235
DO i=1,p % TYPE % NumberOfNodes
2236
IF(p % NodeIndexes(i) == Element % NodeIndexes(k) ) THEN
2237
k1 = Var % Perm(p % DGIndexes(i)); EXIT
2238
END IF
2239
END DO
2240
END IF
2241
IF( k1 == 0 ) THEN
2242
p => Element % BoundaryInfo % Right
2243
IF( ASSOCIATED( p ) ) THEN
2244
DO i=1,p % TYPE % NumberOfNodes
2245
IF(p % NodeIndexes(i) == Element % NodeIndexes(k) ) THEN
2246
k1 = Var % Perm(p % DGIndexes(i)); EXIT
2247
END IF
2248
END DO
2249
END IF
2250
END IF
2251
END IF
2252
2253
IF ( k1>0 ) Var % Values(k1) = Work(k)
2254
END DO
2255
2256
ELSE
2257
DOFs = GetElementDOFs( Indexes, USolver=Var % Solver )
2258
DO k=1,n
2259
k1 = Indexes(k)
2260
IF ( ASSOCIATED(Var % Perm) ) k1 = Var % Perm(k1)
2261
IF ( k1>0 ) Var % Values(k1) = Work(k)
2262
END DO
2263
END IF
2264
2265
END IF
2266
2267
IF ( Transient .AND. Solver % TimeOrder==2 ) THEN
2268
Work(1:n) = GetReal( IC, TRIM(Var % Name) // ' Velocity', GotIt )
2269
IF ( GotIt ) THEN
2270
IF( Var % TYPE == Variable_on_nodes_on_elements ) THEN
2271
Indexes(1:n) = Element % DgIndexes(1:n)
2272
ELSE
2273
DOFs = GetElementDOFs( Indexes, USolver=Var % Solver )
2274
END IF
2275
2276
DO k=1,n
2277
k1 = Indexes(k)
2278
IF ( ASSOCIATED(Var % Perm) ) k1 = Var % Perm(k1)
2279
IF ( k1>0 ) Var % PrevValues(k1,1) = Work(k)
2280
END DO
2281
END IF
2282
Work(1:n) = GetReal( IC, TRIM(Var % Name) // ' Acceleration', GotIt )
2283
IF ( GotIt ) THEN
2284
IF( Var % TYPE == Variable_on_nodes_on_elements ) THEN
2285
Indexes(1:n) = Element % DgIndexes(1:n)
2286
ELSE
2287
DOFs = GetElementDOFs( Indexes, USolver=Var % Solver )
2288
END IF
2289
2290
DO k=1,n
2291
k1 = Indexes(k)
2292
IF ( ASSOCIATED(Var % Perm) ) k1 = Var % Perm(k1)
2293
IF ( k1>0 ) THEN
2294
Var % PrevValues(k1,2) = Work(k)
2295
Var % PrevValues(k1,6) = Work(k)
2296
END IF
2297
END DO
2298
END IF
2299
END IF
2300
2301
IF(ASSOCIATED(Mesh % Edges)) THEN
2302
IF ( i<=Mesh % NumberOfBulkElements) THEN
2303
BLOCK
2304
Gotit = ListCheckPresent( IC, Var % Name//' {e}' )
2305
END BLOCK
2306
IF ( Gotit ) THEN
2307
DO k=1,Element % TYPE % NumberOfedges
2308
Edge => Mesh % Edges(Element % EdgeIndexes(k))
2309
l = Var % Perm(Element % EdgeIndexes(k)+Mesh % NumberOfNodes)
2310
IF ( l>0 ) THEN
2311
CALL VectorElementEdgeDOFs( IC, &
2312
Edge, Edge % TYPE % NumberOfNodes, Element, n, &
2313
TRIM(Var % Name)//' {e}', Work )
2314
Var % Values(l) = Work(1)
2315
END IF
2316
END DO
2317
END IF
2318
END IF
2319
END IF
2320
2321
ELSE
2322
CALL ListGetRealArray( IC, &
2323
Var % Name, WorkA, n, Element % NodeIndexes, gotIt )
2324
2325
IF ( GotIt ) THEN
2326
DO k=1,n
2327
k1 = Indexes(k)
2328
IF ( ASSOCIATED(Var % Perm) ) k1 = Var % Perm(k1)
2329
IF(k1>0) THEN
2330
DO l=1,MIN(SIZE(WorkA,1),Var % DOFs)
2331
IF ( k1>0 ) Var % Values(Var % DOFs*(k1-1)+l) = WorkA(l,1,k)
2332
END DO
2333
END IF
2334
END DO
2335
END IF
2336
END IF
2337
IF(NamespaceFound) CALL ListPopNamespace()
2338
Var => Var % Next
2339
END DO
2340
CSolver => CurrentModel % Solver
2341
END DO
2342
2343
! Here we do just the gauss point values for now.
2344
! It would really make sense to do the ICs in this order since probably
2345
! there are quite few IC variables to set but quite many elements.
2346
2347
Var => Mesh % Variables
2348
DO WHILE( ASSOCIATED(Var) )
2349
2350
VarName = TRIM(Var % Name)
2351
Solver => Var % Solver
2352
IF ( .NOT. ASSOCIATED(Solver) ) Solver => CurrentModel % Solver
2353
2354
IF( AnyNameSpace ) THEN
2355
str = ListGetString( Solver % Values, 'Namespace', NamespaceFound )
2356
IF (NamespaceFound) CALL ListPushNamespace(TRIM(str))
2357
END IF
2358
2359
VarOrder = -1
2360
DO VarOrder = 0, 2
2361
IF( VarOrder == 0 ) THEN
2362
VarName = TRIM(Var % Name)
2363
ELSE IF( VarOrder == 1 ) THEN
2364
VarName = TRIM(Var % Name )//' Velocity'
2365
ELSE IF( VarOrder == 2 ) THEN
2366
VarName = TRIM(Var % Name )//' Acceleration'
2367
END IF
2368
2369
!CALL ListInitElementKeyword( LocalSol_h,'Initial Condition',VarName, &
2370
! FoundSomewhere = Found )
2371
Found = ListCheckPresentAnyIC( CurrentModel, VarName )
2372
2373
IF( Found .AND. VarOrder > 0 ) THEN
2374
IF ( .NOT. ( Transient .AND. Solver % TimeOrder==2 ) ) THEN
2375
CALL Warn('InitCond','We can only set timederivative for transients')
2376
Found = .FALSE.
2377
END IF
2378
END IF
2379
2380
IF( Found ) THEN
2381
2382
CALL ListInitElementKeyword( LocalSol_h,'Initial Condition',VarName )
2383
2384
IF( Var % TYPE /= Variable_on_gauss_points ) CYCLE
2385
2386
CALL Info('InitCond','Initializing gauss point field: '//TRIM(VarName),Level=7)
2387
IF( Var % DOFs > 1 ) THEN
2388
CALL Fatal('InitCond','Initialization only for scalar elemental fields!')
2389
END IF
2390
2391
100 PrevBodyId = -1
2392
DO t=1, Mesh % NumberOfBulkElements+Mesh % NumberOfBoundaryElements
2393
2394
Element => Mesh % Elements(t)
2395
2396
i = Element % BodyId
2397
IF( i == 0 ) CYCLE
2398
2399
IF( i == PrevBodyId ) THEN
2400
FoundIC = PrevFoundIC
2401
ELSE
2402
j = ListGetInteger(CurrentModel % Bodies(i) % Values, &
2403
'Initial Condition',FoundIC, 1, CurrentModel % NumberOfICs )
2404
IF ( FoundIC ) THEN
2405
IC => CurrentModel % ICs(j) % Values
2406
FoundIC = ListCheckPresent( IC, VarName )
2407
END IF
2408
PrevFoundIC = FoundIC
2409
END IF
2410
2411
IF( .NOT. FoundIC ) CYCLE
2412
2413
CurrentModel % CurrentElement => Element
2414
n = GetElementNOFNodes()
2415
2416
k1 = Var % Perm( Element % ElementIndex )
2417
k2 = Var % Perm( Element % ElementIndex + 1 )
2418
2419
IF( k2- k1 > 0 ) THEN
2420
2421
IP = GaussPointsAdapt( Element, Solver )
2422
2423
IF( k2 - k1 /= Ip % n ) THEN
2424
CALL Info('InitCond','Number of Gauss points has changed, redoing permutations!',Level=8)
2425
CALL UpdateIpPerm( Solver, Var % Perm )
2426
nsize = MAXVAL( Var % Perm )
2427
2428
CALL Info('InitCond','Total number of new IP dofs: '//I2S(nsize))
2429
2430
IF( SIZE( Var % Values ) /= Var % Dofs * nsize ) THEN
2431
DEALLOCATE( Var % Values )
2432
ALLOCATE( Var % Values( nsize * Var % Dofs ) )
2433
END IF
2434
Var % Values = 0.0_dp
2435
GOTO 100
2436
END IF
2437
2438
Nodes % x(1:n) = Mesh % Nodes % x(Element % NodeIndexes)
2439
Nodes % y(1:n) = Mesh % Nodes % y(Element % NodeIndexes)
2440
Nodes % z(1:n) = Mesh % Nodes % z(Element % NodeIndexes)
2441
2442
DO k=1,IP % n
2443
stat = ElementInfo( Element, Nodes, IP % U(k), IP % V(k), &
2444
IP % W(k), detJ, Basis )
2445
2446
val = ListGetElementReal( LocalSol_h,Basis,Element,Found,GaussPoint=k)
2447
2448
IF( VarOrder == 0 ) THEN
2449
Var % Values(k1+k) = val
2450
ELSE
2451
Var % PrevValues(k1+k,VarOrder) = val
2452
END IF
2453
2454
END DO
2455
2456
END IF
2457
END DO
2458
END IF
2459
END DO
2460
IF(NamespaceFound) CALL ListPopNamespace()
2461
Var => Var % Next
2462
END DO
2463
END IF
2464
2465
DEALLOCATE( Indexes, Work, Basis, Nodes % x, Nodes % y, Nodes % z)
2466
2467
IF( InfoActive( 20 ) ) THEN
2468
Var => Mesh % Variables
2469
DO WHILE( ASSOCIATED(Var) )
2470
IF( ListCheckPresentAnyIC( CurrentModel, Var % Name ) ) THEN
2471
CALL VectorValuesRange(Var % Values,SIZE(Var % Values),'PostInit: '//TRIM(Var % Name))
2472
END IF
2473
Var => Var % Next
2474
END DO
2475
END IF
2476
2477
Mesh => Mesh % Next
2478
END DO
2479
2480
!------------------------------------------------------------------------------
2481
END SUBROUTINE InitCond
2482
!------------------------------------------------------------------------------
2483
2484
!------------------------------------------------------------------------------
2485
!> Check if we are restarting and if yes, read in field values.
2486
!------------------------------------------------------------------------------
2487
SUBROUTINE Restart()
2488
!------------------------------------------------------------------------------
2489
LOGICAL :: Gotit, DoIt
2490
INTEGER :: i, j, k, l
2491
REAL(KIND=dp) :: StartTime
2492
TYPE(Mesh_t), POINTER :: Mesh, pMesh
2493
TYPE(ValueList_t), POINTER :: RestartList
2494
LOGICAL, ALLOCATABLE :: MeshDone(:)
2495
INTEGER, POINTER :: MeshesToRestart(:)
2496
LOGICAL :: CheckMesh, DoMesh, isParallel
2497
!------------------------------------------------------------------------------
2498
2499
2500
! Count the number of meshes first so that we can identify them
2501
j = 0
2502
pMesh => CurrentModel % Meshes
2503
DO WHILE( ASSOCIATED(pMesh) )
2504
j = j + 1
2505
pMesh => pMesh % Next
2506
END DO
2507
ALLOCATE( MeshDone( j ) )
2508
MeshDone = .FALSE.
2509
2510
2511
! Do Solver-mesh specific restart only
2512
!-----------------------------------------------------------------
2513
IF ( ListCheckPresentAnySolver( CurrentModel,'Restart File') ) THEN
2514
DO i=1, CurrentModel % NumberOfSolvers
2515
RestartList => CurrentModel % Solvers(i) % Values
2516
2517
RestartFile = ListGetString( RestartList, 'Restart File', GotIt )
2518
IF ( GotIt ) THEN
2519
2520
Mesh => CurrentModel % Solvers(i) % Mesh
2521
IF( .NOT. ASSOCIATED(Mesh) ) THEN
2522
CALL Warn('Restart','Solver has no mesh associated!')
2523
CYCLE
2524
END IF
2525
2526
DoIt = .TRUE.
2527
pMesh => CurrentModel % Meshes
2528
j = 0
2529
DO WHILE( ASSOCIATED(pMesh) )
2530
j = j + 1
2531
pMesh => pMesh % Next
2532
IF( ASSOCIATED( Mesh, pMesh ) ) THEN
2533
IF( MeshDone(j) ) THEN
2534
DoIt = .FALSE.
2535
ELSE
2536
MeshDone(j) = .TRUE.
2537
END IF
2538
END IF
2539
END DO
2540
2541
! Variables for this mesh already done!
2542
IF(.NOT. DoIt ) CYCLE
2543
2544
CALL Info('Restart','Perfoming solver specific Restart for: '//TRIM(Mesh % Name),Level=6)
2545
IF ( LEN_TRIM(Mesh % Name) > 0 ) THEN
2546
OutputName = TRIM(Mesh % Name) // '/' // TRIM(RestartFile)
2547
ELSE
2548
OutputName = RestartFile
2549
END IF
2550
2551
! If we have single mesh we have the luxury of using either parallel or serial restart
2552
isParallel = ParEnv % PEs > 1
2553
IF(isParallel .AND. Mesh % SingleMesh ) THEN
2554
isParallel = ListGetLogical( RestartList,'Restart Parallel',Found )
2555
END IF
2556
IF(isParallel) OutputName = OutputName // '.' // i2s(ParEnv % MyPe)
2557
2558
CALL SetCurrentMesh( CurrentModel, Mesh )
2559
2560
k = ListGetInteger( RestartList,'Restart Position',GotIt, minv=0 )
2561
CALL LoadRestartFile( OutputName, k, Mesh, SolverId = i )
2562
2563
StartTime = ListGetConstReal( RestartList ,'Restart Time',GotIt)
2564
IF( GotIt ) THEN
2565
Var => VariableGet( Mesh % Variables, 'Time' )
2566
IF ( ASSOCIATED( Var ) ) Var % Values(1) = StartTime
2567
END IF
2568
END IF
2569
2570
END DO
2571
END IF
2572
2573
! Do the standard global restart
2574
!-----------------------------------------------------------------
2575
RestartList => CurrentModel % Simulation
2576
2577
! We may suppress restart from certain meshes.
2578
! This was initially only related to calving, but no need to limit to that.
2579
l = 0
2580
MeshesToRestart => ListGetIntegerArray(RestartList,&
2581
'Meshes To Restart', CheckMesh )
2582
2583
RestartFile = ListGetString( RestartList, 'Restart File', GotIt )
2584
IF ( GotIt ) THEN
2585
k = ListGetInteger( RestartList,'Restart File Number',GotIt)
2586
IF( GotIt ) RestartFile = TRIM(RestartFile)//'_'//I2S(k)//'nc'
2587
2588
k = ListGetInteger( RestartList,'Restart Position',GotIt, minv=0 )
2589
Mesh => CurrentModel % Meshes
2590
2591
j = 0
2592
DO WHILE( ASSOCIATED(Mesh) )
2593
j = j + 1
2594
2595
! Make sure that if a mesh has already been restarted
2596
! it is not being done again.
2597
IF( MeshDone(j) ) THEN
2598
CALL Info('Restart','Already done mesh: '//TRIM(Mesh % Name))
2599
Mesh => Mesh % Next
2600
CYCLE
2601
END IF
2602
MeshDone(j) = .TRUE.
2603
2604
CALL Info('Restart','Perfoming global Restart for: '//TRIM(Mesh % Name),Level=6)
2605
2606
IF ( LEN_TRIM(Mesh % Name) > 0 ) THEN
2607
OutputName = TRIM(Mesh % Name) // '/' // TRIM(RestartFile)
2608
ELSE
2609
OutputName = TRIM(RestartFile)
2610
END IF
2611
2612
isParallel = ParEnv % PEs > 1
2613
IF(isParallel .AND. Mesh % SingleMesh ) THEN
2614
isParallel = ListGetLogical( RestartList,'Restart Parallel',Found )
2615
END IF
2616
IF(isParallel ) OutputName = TRIM(OutputName) // '.' // i2s(ParEnv % MyPe)
2617
2618
l = l+1
2619
2620
DoMesh = .TRUE.
2621
IF(CheckMesh) THEN
2622
DoMesh = (ANY(MeshesToRestart == l))
2623
END IF
2624
2625
IF( DoMesh ) THEN
2626
CALL SetCurrentMesh( CurrentModel, Mesh )
2627
CALL LoadRestartFile( OutputName, k, Mesh )
2628
2629
StartTime = ListGetConstReal( RestartList ,'Restart Time',GotIt)
2630
IF( GotIt ) THEN
2631
Var => VariableGet( Mesh % Variables, 'Time' )
2632
IF ( ASSOCIATED( Var ) ) Var % Values(1) = StartTime
2633
END IF
2634
END IF
2635
Mesh => Mesh % Next
2636
END DO
2637
ELSE
2638
StartTime = ListGetConstReal( CurrentModel % Simulation ,'Start Time',GotIt)
2639
Mesh => CurrentModel % Meshes
2640
2641
j = 0
2642
IF( GotIt ) THEN
2643
DO WHILE( ASSOCIATED(Mesh) )
2644
j = j + 1
2645
2646
! Make sure that if a mesh has already been restarted
2647
! it is not being done again.
2648
IF( MeshDone(j) ) THEN
2649
CALL Info('Restart','Already done mesh: '//TRIM(Mesh % Name))
2650
Mesh => Mesh % Next
2651
CYCLE
2652
END IF
2653
MeshDone(j) = .TRUE.
2654
Var => VariableGet( Mesh % Variables, 'Time' )
2655
IF ( ASSOCIATED( Var ) ) Var % Values(1) = StartTime
2656
WRITE(Message,*) 'Found "Start Time" (without restart) and setting time-variable to t=',StartTime
2657
CALL INFO("Restart",Message,Level=1)
2658
END DO
2659
END IF
2660
END IF
2661
2662
2663
!------------------------------------------------------------------------------
2664
END SUBROUTINE Restart
2665
!------------------------------------------------------------------------------
2666
2667
2668
!------------------------------------------------------------------------------
2669
!> Execute the individual solvers in defined sequence.
2670
!------------------------------------------------------------------------------
2671
SUBROUTINE ExecSimulation(TimeIntervals, CoupledMinIter, &
2672
CoupledMaxIter, OutputIntervals, Transient, Scanning)
2673
!------------------------------------------------------------------------------
2674
USE Integration, ONLY : GaussPointsInitialized, GaussPointsInit
2675
IMPLICIT NONE
2676
INTEGER :: TimeIntervals,CoupledMinIter, CoupledMaxIter,OutputIntervals(:)
2677
LOGICAL :: Transient,Scanning
2678
!------------------------------------------------------------------------------
2679
INTEGER :: interval, timestep, i, j, k, n
2680
REAL(KIND=dp) :: dt, ddt, dtfunc, timeleft
2681
INTEGER :: cum_timestep
2682
INTEGER, SAVE :: stepcount, RealTimestep
2683
LOGICAL :: ExecThis,SteadyStateReached=.FALSE.,PredCorrControl, &
2684
DivergenceControl, HaveDivergence
2685
REAL(KIND=dp) :: CumTime, MaxErr, AdaptiveLimit, &
2686
AdaptiveMinTimestep, AdaptiveMaxTimestep, timePeriod
2687
INTEGER :: SmallestCount, AdaptiveKeepSmallest, StepControl=-1, nSolvers
2688
LOGICAL :: AdaptiveTime = .TRUE., AdaptiveRough, AdaptiveSmart, Found, DoIt
2689
INTEGER :: AllocStat
2690
REAL(KIND=dp) :: AdaptiveIncrease, AdaptiveDecrease
2691
TYPE(Solver_t), POINTER :: Solver
2692
TYPE AdaptiveVariables_t
2693
TYPE(Variable_t) :: Var
2694
REAL(KIND=dp) :: Norm
2695
END TYPE AdaptiveVariables_t
2696
TYPE(AdaptiveVariables_t), ALLOCATABLE, SAVE :: AdaptVars(:)
2697
REAL(KIND=dp) :: newtime, prevtime=0, maxtime, exitcond
2698
INTEGER, SAVE :: PrevMeshI = 0
2699
INTEGER :: nPeriodic, nSlices, nTimes, iSlice, iTime
2700
LOGICAL :: ParallelTime, ParallelSlices, IsPeriodic
2701
CHARACTER(*), PARAMETER :: Caller = 'ExecSimulation'
2702
2703
!$OMP PARALLEL
2704
IF(.NOT.GaussPointsInitialized()) CALL GaussPointsInit()
2705
!$OMP END PARALLEL
2706
2707
nSolvers = CurrentModel % NumberOfSolvers
2708
DO i=1,nSolvers
2709
Solver => CurrentModel % Solvers(i)
2710
IF ( Solver % PROCEDURE==0 ) CYCLE
2711
DoIt = ( Solver % SolverExecWhen == SOLVER_EXEC_AHEAD_ALL )
2712
IF(.NOT. DoIt) THEN
2713
DoIt = ListGetLogical( Solver % Values,'Before All',Found ) .OR. &
2714
ListGetLogical( Solver % Values,'Before Simulation',Found )
2715
END IF
2716
2717
IF( DoIt ) THEN
2718
! solver to be called prior to time looping can never be transient
2719
dt = 1.0_dp
2720
CALL SolverActivate( CurrentModel,Solver,dt,.FALSE. )
2721
END IF
2722
END DO
2723
2724
IF( ListGetLogical( CurrentModel % Simulation,'Calculate Mesh Pieces',Found ) .OR. &
2725
ListCheckPresent( CurrentModel % Simulation,'Desired Mesh Pieces') ) THEN
2726
CALL CalculateMeshPieces( CurrentModel % Mesh )
2727
END IF
2728
2729
! Predictor-Corrector time stepping control
2730
PredCorrControl = ListGetLogical( CurrentModel % Simulation, &
2731
'Predictor-Corrector Control', gotIt)
2732
2733
! Divergence control
2734
DivergenceControl = ListGetLogical( CurrentModel % Simulation, &
2735
'Convergence Control', gotIt)
2736
2737
AdaptiveTime = ListGetLogical( CurrentModel % Simulation, &
2738
'Adaptive Timestepping', GotIt )
2739
2740
stepcount = 0
2741
DO interval = 1, TimeIntervals
2742
stepcount = stepcount + Timesteps(interval)
2743
END DO
2744
2745
dt = 1.0_dp
2746
cum_Timestep = 0
2747
ddt = -1.0_dp
2748
2749
! For parallel timestepping we need to divide the periodic timesteps for each partition.
2750
ParallelTime = ListGetLogical( CurrentModel % Simulation,'Parallel Timestepping', GotIt ) &
2751
.AND. ( ParEnv % PEs > 1 )
2752
2753
! For parallel slices we need to introduce the slices
2754
! Let this be active even for serial case to have consistent setup
2755
ParallelSlices = ListGetLogical( CurrentModel % Simulation,'Parallel Slices',GotIt )
2756
!.AND. ( ParEnv % PEs > 1 )
2757
2758
IF( ParallelTime .OR. ParallelSlices ) THEN
2759
IF( ParEnv % PEs > 1 ) THEN
2760
IF(.NOT. ListGetLogical( CurrentModel % Simulation,'Single Mesh',GotIt ) ) THEN
2761
CALL Fatal(Caller,'Parallel time and slices only available with "Single Mesh"')
2762
END IF
2763
END IF
2764
END IF
2765
2766
2767
nSlices = 1
2768
nTimes = 1
2769
iTime = 0
2770
iSlice = 0
2771
2772
IF( ParallelTime .AND. ParallelSlices ) THEN
2773
nSlices = ListGetInteger( CurrentModel % Simulation,'Number Of Slices',GotIt)
2774
IF(GotIt) THEN
2775
IF( nSlices > ParEnv % PEs ) THEN
2776
CALL Fatal(Caller,'"Number Of Slices" cannot be be larger than #np')
2777
END IF
2778
ELSE
2779
IF( ParEnv % PEs == 1 ) THEN
2780
CALL ListAddInteger( CurrentModel % Simulation,'Number Of Slices',nSlices)
2781
ELSE
2782
CALL Fatal(Caller,'We need "Number Of Slices" with parallel timestepping')
2783
END IF
2784
END IF
2785
IF( MODULO( ParEnv % PEs, nSlices ) /= 0 ) THEN
2786
CALL Fatal(Caller,'For hybrid parallelism #np must be divisible with "Number of Slices"')
2787
END IF
2788
nTimes = ParEnv % PEs / nSlices
2789
CALL ListAddInteger( CurrentModel % Simulation,'Number Of Times',nTimes )
2790
iSlice = MODULO( ParEnv % MyPe, nSlices )
2791
iTime = ParEnv % MyPe / nSlices
2792
ELSE IF( ParallelTime ) THEN
2793
nTimes = ParEnv % PEs
2794
iTime = ParEnv % MyPe
2795
CALL ListAddInteger( CurrentModel % Simulation,'Number Of Times',nTimes )
2796
CALL ListAddInteger( CurrentModel % Simulation,'Number Of Slices',nSlices )
2797
CALL Info(Caller,'Setting one time sector for each partition!')
2798
ELSE IF( ParallelSlices ) THEN
2799
nSlices = ParEnv % PEs
2800
iSlice = ParEnv % MyPe
2801
CALL ListAddInteger( CurrentModel % Simulation,'Number Of Times',nTimes )
2802
CALL ListAddInteger( CurrentModel % Simulation,'Number Of Slices',nSlices )
2803
CALL Info(Caller,'Setting one slice for each partition!')
2804
END IF
2805
2806
IF( nTimes > 1 ) THEN
2807
DO i=1,SIZE(Timesteps,1)
2808
IF( MODULO( Timesteps(i), nTimes ) /= 0 ) THEN
2809
CALL Fatal(Caller,'"Timestep Intervals" should be divisible by nTimes: '//I2S(nTimes))
2810
END IF
2811
Timesteps(i) = Timesteps(i) / nTimes
2812
END DO
2813
CALL Info(Caller,'Divided timestep intervals equally for each partition!',Level=4)
2814
END IF
2815
2816
IsPeriodic = ListCheckPrefix( CurrentModel % Simulation,'Periodic Time') .OR. &
2817
ListCheckPresent( CurrentModel % Simulation,'Time Period' )
2818
2819
nPeriodic = ListGetInteger( CurrentModel % Simulation,'Periodic Timesteps',GotIt )
2820
IF( ParallelTime ) THEN
2821
IF( nPeriodic <= 0 ) THEN
2822
CALL Fatal(Caller,'Parallel timestepping requires "Periodic Timesteps"')
2823
END IF
2824
IF( MODULO( nPeriodic, nTimes ) /= 0 ) THEN
2825
CALL Fatal(Caller,'For parallel timestepping "Periodic Timesteps" must be divisible by #np')
2826
END IF
2827
nPeriodic = nPeriodic / nTimes
2828
END IF
2829
2830
IF( ListGetLogical( CurrentModel % Simulation,'Parallel Slices',GotIt ) ) THEN
2831
IF( nSlices <= 1 ) THEN
2832
sSlice = 0.0_dp
2833
sSliceRatio = 0.0_dp
2834
sSliceWeight = 1.0_dp
2835
ELSE
2836
sSlice = 1.0_dp * iSlice
2837
sSliceRatio = ( iSlice + 0.5_dp ) / nSlices - 0.5_dp
2838
sSliceWeight = 1.0_dp / nSlices
2839
END IF
2840
2841
BLOCK
2842
REAL :: z_min, z_max, z_mid
2843
z_min = ListGetConstReal(CurrentModel % Simulation,'Extruded Min Coordinate',GotIt)
2844
z_max = ListGetConstReal(CurrentModel % Simulation,'Extruded Max Coordinate',GotIt)
2845
2846
IF( GotIt .AND. nSlices > 1) THEN
2847
z_mid = 0.5_dp * ( z_min + z_max )
2848
CALL Info(Caller,'Moving parallel slices in z-direction!',Level=6)
2849
i = CurrentModel % Mesh % NumberOfNodes
2850
CurrentModel % Mesh % Nodes % z(1:i) = z_mid + (z_max-z_min) * sSliceRatio(1)
2851
END IF
2852
END BLOCK
2853
END IF
2854
2855
IF( ListGetLogical( CurrentModel % Simulation,'Parallel Timestepping',GotIt ) ) THEN
2856
IF( nTimes <= 1 ) THEN
2857
sSector = 0.0_dp
2858
ELSE
2859
sSector = 1.0_dp * iTime
2860
END IF
2861
END IF
2862
2863
DO interval = 1,TimeIntervals
2864
2865
!------------------------------------------------------------------------------
2866
! go through number of timesteps within an interval
2867
!------------------------------------------------------------------------------
2868
timePeriod = ListGetCReal(CurrentModel % Simulation, 'Time Period',gotIt)
2869
IF(.NOT.GotIt) timePeriod = HUGE(timePeriod)
2870
2871
IF(GetNameSpaceCheck()) THEN
2872
IF(Scanning) THEN
2873
CALL ListPushNamespace('scan:')
2874
ELSE IF(Transient) THEN
2875
CALL ListPushNamespace('time:')
2876
ELSE
2877
CALL ListPushNamespace('steady:')
2878
END IF
2879
END IF
2880
2881
RealTimestep = 1
2882
2883
timestep = 1
2884
DO WHILE(timestep <= Timesteps(interval))
2885
2886
cum_Timestep = cum_Timestep + 1
2887
sStep(1) = cum_Timestep
2888
2889
IF ( GetNamespaceCheck() ) THEN
2890
IF( Scanning ) THEN
2891
CALL ListPushNamespace('scan '//i2s(cum_Timestep)//':')
2892
ELSE IF ( Transient ) THEN
2893
CALL ListPushNamespace('time '//i2s(cum_Timestep)//':')
2894
ELSE
2895
CALL ListPushNamespace('steady '//i2s(cum_Timestep)//':')
2896
END IF
2897
END IF
2898
2899
! Sometimes when timestep depends on time we need to have first timestep size
2900
! given separately to avoid problems.
2901
GotIt = .FALSE.
2902
IF( cum_Timestep == 1 ) THEN
2903
dtfunc = ListGetCReal( CurrentModel % Simulation,'First Timestep Size',GotIt )
2904
IF(GotIt) dt = dtfunc
2905
END IF
2906
2907
IF ( ( Transient .OR. Scanning ) .AND. .NOT. GotIt ) THEN
2908
dtfunc = ListGetCReal( CurrentModel % Simulation,'Timestep Function',GotIt )
2909
IF(GotIt) THEN
2910
CALL Warn(Caller,'Obsolete keyword > Timestep Function < , use > Timestep Size < instead')
2911
ELSE
2912
dtfunc = ListGetCReal( CurrentModel % Simulation,'Timestep Size', gotIt)
2913
END IF
2914
IF( GotIt ) THEN
2915
BLOCK
2916
TYPE(Variable_t), POINTER :: tVar
2917
INTEGER :: dtiter
2918
REAL(KIND=dp) :: t0
2919
dtiter = ListGetInteger( CurrentModel % Simulation,'Timestep Size Iterations',Found)
2920
2921
! If timestep size depends on time i.e. dt=dt(t) we may sometimes want to iterate
2922
! so that the timestep is consistent with the new time t+dt i.e. dt=dt(t+dt).
2923
IF( dtiter > 0 ) THEN
2924
tVar => VariableGet( CurrentModel % Mesh % Variables, 'time' )
2925
IF(ASSOCIATED(tVar)) THEN
2926
t0 = tVar % Values(1)
2927
! Iterate for consistent time + timestep size.
2928
DO i=1,dtiter
2929
tVar % Values(1) = t0 + dtfunc
2930
dtfunc = ListGetCReal( CurrentModel % Simulation,'Timestep Size' )
2931
END DO
2932
! Revert back to original time, this will be added later on again.
2933
tVar % Values(1) = t0
2934
END IF
2935
END IF
2936
END BLOCK
2937
END IF
2938
2939
IF(GotIt) THEN
2940
dt = dtfunc
2941
IF(dt < EPSILON(dt) ) THEN
2942
WRITE(Message,'(A,ES12.3)') 'Timestep smaller than epsilon: ',dt
2943
CALL Fatal(Caller, Message)
2944
END IF
2945
ELSE
2946
dt = TimestepSizes(interval,1)
2947
IF( GotTimestepRatios ) THEN
2948
BLOCK
2949
REAL(KIND=dp) :: q
2950
q = TimestepRatios(interval,1)
2951
IF( ABS(1-q) > EPSILON(q) ) dt = dt * q**(timestep-1)
2952
END BLOCK
2953
END IF
2954
2955
END IF
2956
END IF
2957
2958
!------------------------------------------------------------------------------
2959
! Predictor-Corrector time stepping control
2960
IF ( PredCorrControl ) THEN
2961
CALL PredictorCorrectorControl( CurrentModel, dt, timestep )
2962
END IF
2963
2964
!------------------------------------------------------------------------------
2965
2966
IF( AdaptiveTime ) THEN
2967
AdaptiveLimit = ListGetConstReal( CurrentModel % Simulation, &
2968
'Adaptive Time Error', GotIt )
2969
IF ( .NOT. GotIt ) THEN
2970
CALL Fatal('MAIN','Adaptive Time Error must be given for ' // &
2971
'adaptive stepping scheme.')
2972
END IF
2973
AdaptiveKeepSmallest = ListGetInteger( CurrentModel % Simulation, &
2974
'Adaptive Keep Smallest', GotIt, minv=0 )
2975
END IF
2976
2977
IF( AdaptiveTime .OR. DivergenceControl ) THEN
2978
AdaptiveMaxTimestep = ListGetConstReal( CurrentModel % Simulation, &
2979
'Adaptive Max Timestep', GotIt )
2980
IF ( GotIt ) THEN
2981
AdaptiveMaxTimestep = MIN(AdaptiveMaxTimeStep, dt)
2982
ELSE
2983
AdaptiveMaxTimestep = dt
2984
END IF
2985
2986
AdaptiveMinTimestep = ListGetConstReal( CurrentModel % Simulation, &
2987
'Adaptive Min Timestep', GotIt )
2988
IF(.NOT. GotIt) AdaptiveMinTimestep = 1.0e-8 * AdaptiveMaxTimestep
2989
2990
AdaptiveIncrease = ListGetConstReal( CurrentModel % Simulation, &
2991
'Adaptive Increase Coefficient', GotIt )
2992
IF(.NOT. GotIt) AdaptiveIncrease = 2.0_dp
2993
2994
AdaptiveDecrease = ListGetConstReal( CurrentModel % Simulation, &
2995
'Adaptive Decrease Coefficient', GotIt )
2996
IF(.NOT. GotIt) AdaptiveDecrease = 0.5_dp
2997
2998
AdaptiveRough = ListGetLogical( CurrentModel % Simulation, &
2999
'Adaptive Rough Timestep', GotIt )
3000
3001
AdaptiveSmart = ListGetLogical( CurrentModel % Simulation, &
3002
'Adaptive Smart Timestep', GotIt )
3003
END IF
3004
3005
3006
!------------------------------------------------------------------------------
3007
IF(cum_Timestep == 1 .AND. ListGetLogical( CurrentModel % Simulation,'Timestep Start Zero',GotIt) ) THEN
3008
CALL Info(Caller,'Not advancing the 1st timestep!')
3009
ELSE
3010
sTime(1) = sTime(1) + dt
3011
END IF
3012
3013
IF( nPeriodic > 0 ) THEN
3014
IF( ParallelTime ) THEN
3015
timePeriod = nTimes * nPeriodic * dt
3016
IF( cum_Timestep == 1 ) THEN
3017
sTime(1) = sTime(1) + iTime * nPeriodic * dt
3018
ELSE IF( MODULO( cum_Timestep, nPeriodic ) == 1 ) THEN
3019
CALL Info(Caller,'Making jump in time-parallel scheme!')
3020
sTime(1) = sTime(1) + nPeriodic * (nTimes - 1) * dt
3021
END IF
3022
ELSE
3023
timePeriod = nPeriodic * dt
3024
END IF
3025
END IF
3026
3027
IF( isPeriodic ) THEN
3028
sPeriodicCycle(1) = sTime(1) / timePeriod
3029
sPeriodicTime(1) = MODULO( sTime(1), timePeriod )
3030
END IF
3031
3032
! Move the old timesteps one step down the ladder
3033
IF(timestep > 1 .OR. interval > 1) THEN
3034
DO i = SIZE(sPrevSizes,2),2,-1
3035
sPrevSizes(1,i) = sPrevSizes(1,i-1)
3036
END DO
3037
sPrevSizes(1,1) = sSize(1)
3038
END IF
3039
sSize(1) = dt
3040
3041
sInterval(1) = interval
3042
IF (.NOT. Transient ) steadyIt(1) = steadyIt(1) + 1
3043
3044
!-----------------------------------------------------------------------------
3045
IF( ListCheckPresent( CurrentModel % Simulation,'Rotor Angle') ) THEN
3046
BLOCK
3047
REAL(KIND=dp) :: PrevAngle
3048
PrevAngle = sAngle(1)
3049
sAngle(1) = ListGetCReal( CurrentModel % Simulation,'Rotor Angle')
3050
sAngleVelo(1) = (sAngle(1)-PrevAngle)/dt
3051
WRITE(Message,'(A,ES12.3)') '"Rotor Angle" set to value: ',sAngle(1)
3052
CALL Info(Caller,Message,Level=6)
3053
WRITE(Message,'(A,ES12.3)') '"Rotor Velo" set to value: ',sAngleVelo(1)
3054
CALL Info(Caller,Message,Level=6)
3055
END BLOCK
3056
END IF
3057
3058
!------------------------------------------------------------------------------
3059
3060
BLOCK
3061
TYPE(Mesh_t), POINTER :: Mesh
3062
REAL(KIND=dp) :: MeshR
3063
CHARACTER(:), ALLOCATABLE :: MeshStr
3064
3065
IF( ListCheckPresent( GetSimulation(), 'Mesh Name Index') ) THEN
3066
! we cannot have mesh depend on "time" or "timestep" if they are not available as
3067
! variables.
3068
Mesh => CurrentModel % Meshes
3069
CALL VariableAdd( Mesh % Variables, Mesh, Name='Time',DOFs=1, Values=sTime )
3070
CALL VariableAdd( Mesh % Variables, Mesh, Name='Timestep', DOFs=1, Values=sStep )
3071
3072
MeshR = GetCREal( GetSimulation(), 'Mesh Name Index',gotIt )
3073
i = NINT( MeshR )
3074
3075
IF( i > 0 .AND. i /= PrevMeshI ) THEN
3076
MeshStr = ListGetString( GetSimulation(),'Mesh Name '//I2S(i),GotIt)
3077
IF( GotIt ) THEN
3078
CALL Info(Caller,'Swapping mesh to: '//MeshStr,Level=5)
3079
ELSE
3080
CALL Fatal(Caller,'Could not find >Mesh Name '//I2S(i)//'<')
3081
END IF
3082
CALL SwapMesh( CurrentModel, Mesh, MeshStr )
3083
PrevMeshI = i
3084
END IF
3085
END IF
3086
END BLOCK
3087
3088
3089
!------------------------------------------------------------------------------
3090
IF ( ParEnv % MyPE == 0 ) THEN
3091
CALL Info( 'MAIN', ' ', Level=3 )
3092
CALL Info( 'MAIN', '-------------------------------------', Level=3 )
3093
3094
IF ( Transient .OR. Scanning ) THEN
3095
WRITE( Message,'(A,ES12.3)') 'Time: '//i2s(cum_Timestep)//'/'// &
3096
i2s(stepcount)//':', sTime(1)
3097
CALL Info( 'MAIN', Message, Level=3 )
3098
3099
newtime= RealTime()
3100
3101
IF( cum_Timestep > 1 ) THEN
3102
maxtime = ListGetConstReal( CurrentModel % Simulation,'Real Time Max',GotIt)
3103
IF( GotIt ) THEN
3104
WRITE( Message,'(A,F8.3)') 'Fraction of real time left: ',&
3105
1.0_dp-(RealTime()-RT0)/ maxtime
3106
END IF
3107
3108
! This gives elapsed time in same format as estimated time
3109
timeleft = (newtime-RT0)
3110
IF( timeleft > 1 ) THEN
3111
IF (timeleft >= 10 * 3600) THEN
3112
WRITE( Message,'(A)') 'Elapsed time: '//I2S(NINT(timeleft/3600))//' hours'
3113
ELSE IF (timeleft >= 3600) THEN
3114
WRITE( Message,'(A,F5.1,A)') 'Elapsed time:',timeleft/3600,' hours'
3115
ELSE IF(timeleft >= 60) THEN
3116
WRITE( Message,'(A,F5.1,A)') 'Elapsed time:',timeleft/60,' minutes'
3117
ELSE
3118
WRITE( Message,'(A,F5.1,A)') 'Elapsed time:',timeleft,' seconds'
3119
END IF
3120
CALL Info( 'MAIN', Message, Level=6 )
3121
END IF
3122
3123
! Compute estimated time left in seconds
3124
timeleft = (stepcount-(cum_Timestep-1))*(newtime-prevtime)
3125
3126
! No sense to show too short estimated times
3127
IF( timeleft > 1 ) THEN
3128
IF (timeleft >= 10 * 3600) THEN ! >10 hours
3129
WRITE( Message,'(A)') 'Estimated time left: '//I2S(NINT(timeleft/3600))//' hours'
3130
ELSE IF (timeleft >= 3600) THEN ! >1 hours
3131
WRITE( Message,'(A,F5.1,A)') 'Estimated time left:',timeleft/3600,' hours'
3132
ELSE IF(timeleft >= 60) THEN ! 1 to 60 minutes
3133
WRITE( Message,'(A,F5.1,A)') 'Estimated time left:',timeleft/60,' minutes'
3134
ELSE ! 1 to 60 seconds
3135
WRITE( Message,'(A,F5.1,A)') 'Estimated time left:',timeleft,' seconds'
3136
END IF
3137
CALL Info( 'MAIN', Message, Level=3 )
3138
END IF
3139
3140
END IF
3141
prevtime = newtime
3142
ELSE
3143
WRITE( Message, * ) 'Steady state iteration: ',cum_Timestep
3144
CALL Info( 'MAIN', Message, Level=3 )
3145
END IF
3146
3147
CALL Info( 'MAIN', '-------------------------------------', Level=3 )
3148
CALL Info( 'MAIN', ' ', Level=3 )
3149
END IF
3150
3151
!------------------------------------------------------------------------------
3152
! Solve any and all governing equations in the system
3153
!------------------------------------------------------------------------------
3154
3155
IF ( Transient .AND. AdaptiveTime ) THEN
3156
3157
IF(.NOT. ALLOCATED( AdaptVars ) ) THEN
3158
ALLOCATE( AdaptVars( nSolvers ), STAT = AllocStat )
3159
IF( AllocStat /= 0 ) CALL Fatal(Caller,'Allocation error for AdaptVars')
3160
3161
DO i=1,nSolvers
3162
Solver => CurrentModel % Solvers(i)
3163
3164
NULLIFY( AdaptVars(i) % Var % Values )
3165
NULLIFY( AdaptVars(i) % Var % PrevValues )
3166
3167
IF( .NOT. ASSOCIATED( Solver % Variable ) ) CYCLE
3168
IF( .NOT. ASSOCIATED( Solver % Variable % Values ) ) CYCLE
3169
CALL Info(Caller,'Allocating adaptive work space for: '//I2S(i),Level=12)
3170
j = SIZE( Solver % Variable % Values )
3171
ALLOCATE( AdaptVars(i) % Var % Values( j ), STAT=AllocStat )
3172
IF( AllocStat /= 0 ) CALL Fatal(Caller,'Allocation error AdaptVars Values')
3173
3174
IF( ASSOCIATED( Solver % Variable % PrevValues ) ) THEN
3175
k = SIZE( Solver % Variable % PrevValues, 2 )
3176
ALLOCATE( AdaptVars(i) % Var % PrevValues( j, k ), STAT=AllocStat)
3177
IF( AllocStat /= 0 ) CALL Fatal(Caller,'Allocation error for AdaptVars PrevValues')
3178
END IF
3179
END DO
3180
END IF
3181
3182
CumTime = 0.0d0
3183
IF ( ddt < 0.0_dp .OR. ddt > AdaptiveMaxTimestep ) ddt = AdaptiveMaxTimestep
3184
3185
s = sTime(1) - dt
3186
SmallestCount = 0
3187
DO WHILE( CumTime < dt-1.0d-12 )
3188
IF( .NOT. AdaptiveRough ) THEN
3189
ddt = MIN( dt - CumTime, ddt )
3190
IF( AdaptiveSmart ) THEN
3191
! If the next timestep will not get us home but the next one would
3192
! then split the timestep equally into two parts.
3193
IF( dt - CumTime - ddt > 1.0d-12 ) THEN
3194
CALL Info(Caller,'Splitted timestep into two equal parts',Level=12)
3195
ddt = MIN( ddt, ( dt - CumTime ) / 2.0_dp )
3196
END IF
3197
END IF
3198
3199
END IF
3200
3201
! Store the initial values before the start of the step
3202
DO i=1,nSolvers
3203
Solver => CurrentModel % Solvers(i)
3204
IF ( .NOT. ASSOCIATED( Solver % Variable ) ) CYCLE
3205
IF ( .NOT. ASSOCIATED( Solver % Variable % Values ) ) CYCLE
3206
AdaptVars(i) % Var % Values = Solver % Variable % Values
3207
AdaptVars(i) % Var % Norm = Solver % Variable % Norm
3208
IF ( ASSOCIATED( Solver % Variable % PrevValues ) ) THEN
3209
AdaptVars(i) % Var % PrevValues = Solver % Variable % PrevValues
3210
END IF
3211
END DO
3212
3213
sTime(1) = s + CumTime + ddt
3214
sSize(1) = ddt
3215
3216
! Solve with full timestep
3217
CALL SolveEquations( CurrentModel, ddt, Transient, &
3218
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep, &
3219
BeforeTime = .TRUE., AtTime = .TRUE., AfterTime = .FALSE.)
3220
3221
! External adaptive error given
3222
MaxErr = ListGetConstReal( CurrentModel % Simulation, &
3223
'Adaptive Error Measure', GotIt )
3224
3225
DO i=1,nSolvers
3226
Solver => CurrentModel % Solvers(i)
3227
IF ( .NOT. ASSOCIATED( Solver % Variable ) ) CYCLE
3228
IF ( .NOT. ASSOCIATED( Solver % Variable % Values ) ) CYCLE
3229
Solver % Variable % Values = AdaptVars(i) % Var % Values
3230
AdaptVars(i) % Norm = Solver % Variable % Norm
3231
IF ( ASSOCIATED( Solver % Variable % PrevValues ) ) THEN
3232
Solver % Variable % PrevValues = AdaptVars(i) % Var % PrevValues
3233
END IF
3234
END DO
3235
3236
! Test the error for half the timestep
3237
sStep(1) = ddt / 2
3238
sTime(1) = s + CumTime + ddt/2
3239
CALL SolveEquations( CurrentModel, ddt/2, Transient, &
3240
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep, &
3241
BeforeTime = .TRUE., AtTime = .TRUE., AfterTime = .FALSE.)
3242
3243
sTime(1) = s + CumTime + ddt
3244
CALL SolveEquations( CurrentModel, ddt/2, Transient, &
3245
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep, &
3246
BeforeTime = .TRUE., AtTime = .TRUE., AfterTime = .FALSE.)
3247
3248
MaxErr = ABS( MaxErr - ListGetConstReal( CurrentModel % Simulation, &
3249
'Adaptive Error Measure', GotIt ) )
3250
3251
! If not measure given then use the maximum change in norm as the measure
3252
IF ( .NOT. GotIt ) THEN
3253
MaxErr = 0.0d0
3254
DO i=1,nSolvers
3255
Solver => CurrentModel % Solvers(i)
3256
IF ( .NOT. ASSOCIATED( Solver % Variable ) ) CYCLE
3257
IF ( .NOT. ASSOCIATED( Solver % Variable % Values ) ) CYCLE
3258
IF ( AdaptVars(i) % norm /= Solver % Variable % Norm ) THEN
3259
Maxerr = MAX(Maxerr,ABS(AdaptVars(i) % norm - Solver % Variable % Norm)/&
3260
AdaptVars(i) % norm )
3261
END IF
3262
END DO
3263
END IF
3264
3265
! We have a success no need to redo this step
3266
IF ( MaxErr < AdaptiveLimit .OR. ddt <= AdaptiveMinTimestep ) THEN
3267
CumTime = CumTime + ddt
3268
RealTimestep = RealTimestep+1
3269
IF ( SmallestCount >= AdaptiveKeepSmallest .OR. StepControl > 0 ) THEN
3270
ddt = MIN( AdaptiveIncrease * ddt, AdaptiveMaxTimeStep )
3271
StepControl = 1
3272
SmallestCount = 0
3273
ELSE
3274
StepControl = 0
3275
SmallestCount = SmallestCount + 1
3276
END IF
3277
3278
! Finally solve only the postprocessing solver after the timestep has been accepted
3279
CALL SolveEquations( CurrentModel, ddt/2, Transient, &
3280
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep, &
3281
BeforeTime = .FALSE., AtTime = .FALSE., AfterTime = .TRUE.)
3282
ELSE
3283
DO i=1,nSolvers
3284
Solver => CurrentModel % Solvers(i)
3285
IF ( .NOT. ASSOCIATED( Solver % Variable ) ) CYCLE
3286
IF ( .NOT. ASSOCIATED( Solver % Variable % Values ) ) CYCLE
3287
Solver % Variable % Norm = AdaptVars(i) % Var % Norm
3288
Solver % Variable % Values = AdaptVars(i) % Var % Values
3289
IF ( ASSOCIATED( Solver % Variable % PrevValues ) ) THEN
3290
Solver % Variable % PrevValues = AdaptVars(i) % Var % PrevValues
3291
END IF
3292
END DO
3293
ddt = AdaptiveDecrease * ddt
3294
StepControl = -1
3295
END IF
3296
3297
WRITE(*,'(a,3e20.12)') 'Adaptive(cum,ddt,err): ', cumtime, ddt, maxerr
3298
END DO
3299
sSize(1) = dt
3300
sTime(1) = s + dt
3301
3302
ELSE IF( DivergenceControl ) THEN
3303
! This is still tentative
3304
CALL Info(Caller,'Solving equations with divergence control',Level=6)
3305
3306
CumTime = 0.0d0
3307
ddt = AdaptiveIncrease * ddt
3308
IF ( ddt < 0.0_dp .OR. ddt > AdaptiveMaxTimestep ) ddt = AdaptiveMaxTimestep
3309
s = sTime(1) - dt
3310
!StepControl = 0
3311
3312
DO WHILE( CumTime < dt-1.0d-12 )
3313
3314
IF( .NOT. AdaptiveRough ) THEN
3315
ddt = MIN( dt - CumTime, ddt )
3316
IF( AdaptiveSmart ) THEN
3317
IF( dt - CumTime - ddt > 1.0d-12 ) THEN
3318
CALL Info(Caller,'Splitted timestep into two equal parts',Level=12)
3319
ddt = MIN( ddt, ( dt - CumTime ) / 2.0_dp )
3320
END IF
3321
END IF
3322
END IF
3323
3324
sTime(1) = s + CumTime + ddt
3325
sSize(1) = ddt
3326
3327
CALL SolveEquations( CurrentModel, ddt, Transient, &
3328
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep, &
3329
BeforeTime = .TRUE., AtTime = .TRUE., AfterTime = .FALSE.)
3330
3331
HaveDivergence = .FALSE.
3332
DO i=1,nSolvers
3333
Solver => CurrentModel % Solvers(i)
3334
IF( ASSOCIATED( Solver % Variable ) ) THEN
3335
IF( Solver % Variable % NonlinConverged > 1 ) THEN
3336
CALL Info(Caller,'Solver '//I2S(i)//' has diverged',Level=8)
3337
HaveDivergence = .TRUE.
3338
EXIT
3339
END IF
3340
END IF
3341
END DO
3342
3343
IF( .NOT. HaveDivergence ) THEN
3344
CALL Info(Caller,'No solver has diverged',Level=8)
3345
3346
! Finally solve only the postprocessing solver after the timestep has been accepted
3347
CALL SolveEquations( CurrentModel, ddt, Transient, &
3348
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep, &
3349
BeforeTime = .FALSE., AtTime = .FALSE., AfterTime = .TRUE.)
3350
3351
! If step control was active for this interval then we can
3352
! again start to increase timestep, otherwise not
3353
3354
CumTime = CumTime + ddt
3355
RealTimestep = RealTimestep+1
3356
3357
!IF ( StepControl > 0 ) THEN
3358
ddt = AdaptiveIncrease * ddt
3359
IF( ddt > AdaptiveMaxTimestep ) THEN
3360
ddt = AdaptiveMaxTimestep
3361
StepControl = 0
3362
END IF
3363
!END IF
3364
ELSE
3365
IF( ddt < AdaptiveMinTimestep * (1+1.0e-8) ) THEN
3366
CALL Fatal(Caller,'Could not find stable timestep above given minimum')
3367
END IF
3368
3369
CALL Info(Caller,'Reducing timestep due to divergence problems!',Level=6)
3370
3371
ddt = MAX( AdaptiveDecrease * ddt, AdaptiveMinTimestep )
3372
StepControl = 1
3373
3374
CALL Info(Caller,'Reverting to previous timestep as initial guess',Level=8)
3375
DO i=1,nSolvers
3376
Solver => CurrentModel % Solvers(i)
3377
IF ( ASSOCIATED( Solver % Variable % Values ) ) THEN
3378
IF( ASSOCIATED( Solver % Variable % PrevValues ) ) THEN
3379
Solver % Variable % Values = Solver % Variable % PrevValues(:,1)
3380
Solver % Variable % Norm = Solver % Variable % PrevNorm
3381
END IF
3382
END IF
3383
END DO
3384
END IF
3385
END DO
3386
ELSE
3387
CALL SolveEquations( CurrentModel, dt, Transient, &
3388
CoupledMinIter, CoupledMaxIter, SteadyStateReached, RealTimestep )
3389
RealTimestep = RealTimestep+1
3390
END IF
3391
!------------------------------------------------------------------------------
3392
! Save results to disk, if requested
3393
!------------------------------------------------------------------------------
3394
3395
LastSaved = .FALSE.
3396
3397
IF( OutputIntervals(Interval) /= 0 ) THEN
3398
3399
CALL SaveToPost(0)
3400
k = MOD( Timestep-1, OutputIntervals(Interval) )
3401
3402
IF ( k == 0 .OR. SteadyStateReached ) THEN
3403
DO i=1,nSolvers
3404
Solver => CurrentModel % Solvers(i)
3405
IF ( Solver % PROCEDURE == 0 ) CYCLE
3406
ExecThis = ( Solver % SolverExecWhen == SOLVER_EXEC_AHEAD_SAVE)
3407
When = ListGetString( Solver % Values, 'Exec Solver', GotIt )
3408
IF ( GotIt ) ExecThis = ( When == 'before saving')
3409
IF( ExecThis ) CALL SolverActivate( CurrentModel,Solver,dt,Transient )
3410
END DO
3411
3412
! Output file is used to Save the results for restart.
3413
! Optionally we may save just the final stage which saves disk space and time.
3414
IF( .NOT. ListGetLogical( CurrentModel % Simulation,'Output File Final Only',GotIt) ) THEN
3415
CALL SaveCurrent(Timestep)
3416
END IF
3417
3418
CALL SaveToPost(TimeStep)
3419
LastSaved = .TRUE.
3420
3421
DO i=1,nSolvers
3422
Solver => CurrentModel % Solvers(i)
3423
IF ( Solver % PROCEDURE == 0 ) CYCLE
3424
ExecThis = ( Solver % SolverExecWhen == SOLVER_EXEC_AFTER_SAVE)
3425
When = ListGetString( Solver % Values, 'Exec Solver', GotIt )
3426
IF ( GotIt ) ExecThis = ( When == 'after saving')
3427
IF( ExecThis ) CALL SolverActivate( CurrentModel,Solver,dt,Transient )
3428
END DO
3429
END IF
3430
END IF
3431
!------------------------------------------------------------------------------
3432
CALL ListPopNameSpace()
3433
!------------------------------------------------------------------------------
3434
3435
maxtime = ListGetCReal( CurrentModel % Simulation,'Real Time Max',GotIt)
3436
IF( GotIt .AND. RealTime() - RT0 > maxtime ) THEN
3437
CALL Info('MAIN','Reached allowed maximum real time, exiting...',Level=3)
3438
GOTO 100
3439
END IF
3440
3441
exitcond = ListGetCReal( CurrentModel % Simulation,'Exit Condition',GotIt)
3442
IF( GotIt .AND. exitcond > 0.0_dp ) THEN
3443
CALL Info('MAIN','Found a positive exit condition, exiting...',Level=3)
3444
GOTO 100
3445
END IF
3446
3447
IF( sFinish(1) > 0.0_dp ) THEN
3448
CALL Info('MAIN','Finishing condition "finish" found to be positive, exiting...',Level=3)
3449
GOTO 100
3450
END IF
3451
3452
!------------------------------------------------------------------------------
3453
3454
IF ( SteadyStateReached .AND. .NOT. (Transient .OR. Scanning) ) THEN
3455
IF ( Timestep >= CoupledMinIter ) EXIT
3456
END IF
3457
3458
! if extra steps have been added need to check if the loop needs extended
3459
! (used for calving algorithm)
3460
IF(Transient) THEN
3461
Timesteps => ListGetIntegerArray( CurrentModel % Simulation, &
3462
'Timestep Intervals', GotIt )
3463
IF ( .NOT.GotIt ) THEN
3464
CALL Fatal('ElmerSolver', 'Keyword > Timestep Intervals < MUST be ' // &
3465
'defined for transient and scanning simulations' )
3466
END IF
3467
END IF
3468
Timestep = Timestep + 1
3469
3470
stepcount = 0
3471
DO i = 1, TimeIntervals
3472
stepcount = stepcount + Timesteps(i)
3473
END DO
3474
3475
!------------------------------------------------------------------------------
3476
END DO ! timestep within an iterval
3477
!------------------------------------------------------------------------------
3478
3479
!------------------------------------------------------------------------------
3480
END DO ! timestep intervals, i.e. the simulation
3481
!------------------------------------------------------------------------------
3482
3483
BLOCK
3484
TYPE(Solver_t), POINTER :: iSolver
3485
3486
DO i=1,CurrentModel % NumberOfSolvers
3487
iSolver => CurrentModel % Solvers(i)
3488
IF( iSolver % NumberOfConstraintModes > 0 ) THEN
3489
IF( ListGetLogical( iSolver % Values,'Steady State Constraint Modes', Found ) ) THEN
3490
CALL FinalizeLumpedMatrix( iSolver )
3491
END IF
3492
END IF
3493
END DO
3494
END BLOCK
3495
3496
100 CONTINUE
3497
3498
CALL ListPopNamespace()
3499
3500
DO i=1,nSolvers
3501
Solver => CurrentModel % Solvers(i)
3502
IF ( Solver % PROCEDURE == 0 ) CYCLE
3503
When = ListGetString( Solver % Values, 'Exec Solver', GotIt )
3504
IF ( GotIt ) THEN
3505
IF ( When == 'after simulation' .OR. When == 'after all' ) THEN
3506
CALL SolverActivate( CurrentModel,Solver,dt,Transient )
3507
!IF( ASSOCIATED(Solver % Variable) ) THEN
3508
! This construct seems to be for cases when we solve something "after all"
3509
! that affects results elsewhere. Hence we set "LastSaved" to false even
3510
! if it would be true before.
3511
!IF (ASSOCIATED(Solver % Variable % Values) ) LastSaved = .FALSE.
3512
!END IF
3513
END IF
3514
ELSE
3515
IF ( Solver % SolverExecWhen == SOLVER_EXEC_AFTER_ALL ) THEN
3516
CALL SolverActivate( CurrentModel,Solver,dt,Transient )
3517
!IF( ASSOCIATED(Solver % Variable) ) THEN
3518
! IF (ASSOCIATED(Solver % Variable % Values) ) LastSaved = .FALSE.
3519
!END IF
3520
END IF
3521
END IF
3522
END DO
3523
3524
!------------------------------------------------------------------------------
3525
! Always save the last step to output
3526
!-----------------------------------------------------------------------------
3527
IF ( .NOT.LastSaved ) THEN
3528
DO i=1,CurrentModel % NumberOfSolvers
3529
Solver => CurrentModel % Solvers(i)
3530
IF ( Solver % PROCEDURE == 0 ) CYCLE
3531
ExecThis = ( Solver % SolverExecWhen == SOLVER_EXEC_AHEAD_SAVE)
3532
When = ListGetString( Solver % Values, 'Exec Solver', GotIt )
3533
IF ( GotIt ) ExecThis = ( When == 'before saving')
3534
IF( ExecThis ) CALL SolverActivate( CurrentModel,Solver,dt,Transient )
3535
END DO
3536
3537
CALL SaveToPost(0)
3538
CALL SaveToPost(TimeStep)
3539
3540
IF( .NOT. ListGetLogical( CurrentModel % Simulation,'Output File Final Only',GotIt) ) THEN
3541
CALL SaveCurrent(Timestep)
3542
END IF
3543
3544
DO i=1,CurrentModel % NumberOfSolvers
3545
Solver => CurrentModel % Solvers(i)
3546
IF ( Solver % PROCEDURE == 0 ) CYCLE
3547
ExecThis = ( Solver % SolverExecWhen == SOLVER_EXEC_AFTER_SAVE)
3548
When = ListGetString( Solver % Values, 'Exec Solver', GotIt )
3549
IF ( GotIt ) ExecThis = ( When == 'after saving')
3550
IF( ExecThis ) CALL SolverActivate( CurrentModel,Solver,dt,Transient )
3551
END DO
3552
ELSE IF( ListGetLogical( CurrentModel % Simulation,'Output File Final Only',GotIt) ) THEN
3553
CALL SaveCurrent(Timestep)
3554
END IF
3555
3556
!------------------------------------------------------------------------------
3557
END SUBROUTINE ExecSimulation
3558
!------------------------------------------------------------------------------
3559
3560
3561
#ifdef HAVE_EXTOPTIM
3562
!------------------------------------------------------------------------------
3563
!> This is a handle for doing parametric simulation using minpack optimization
3564
!> library. The function returns a set of function values.
3565
!------------------------------------------------------------------------------
3566
SUBROUTINE ExecSimulationFunVec(NoParam,Param,Fvec,iflag )
3567
INTEGER, INTENT(in) :: NoParam
3568
REAL(KIND=dp), INTENT(in) :: Param(NoParam)
3569
REAL(KIND=dp), INTENT(out) :: Fvec(NoParam)
3570
INTEGER, INTENT(inout) :: iflag
3571
3572
INTEGER :: i, cnt, iSweep = 0
3573
LOGICAL :: Found
3574
3575
iSweep = iSweep + 1
3576
3577
CALL Info('ExecSimulationFunVec','Calling Elmer as a cost function: '//I2S(iSweep))
3578
3579
IF(iSweep==1) THEN
3580
CONTINUE
3581
ELSE
3582
CALL ControlResetMesh(Control % Control, iSweep )
3583
END IF
3584
3585
! Optionally reset the mesh if it has been modified
3586
CALL ControlResetMesh(Control % Control, iSweep )
3587
3588
! Set parameters to be accessible to the MATC preprocessor when reading sif file.
3589
CALL SetRealParametersMATC(NoParam,Param)
3590
! Reread the sif file for MATC changes to take effect
3591
Found = ReloadInputFile(CurrentModel,RewindFile=.TRUE.)
3592
3593
! Update the parameters also as coefficient as we don't know which one we are using
3594
CALL SetRealParametersKeywordCoeff(NoParam,Param,cnt)
3595
CALL Info('ExecSimulationFunVec','Set '//I2S(cnt)//&
3596
' coefficients with parameter tags!',Level=10)
3597
3598
CALL InitializeIntervals()
3599
CALL SetInitialConditions()
3600
3601
CALL ExecSimulation( TimeIntervals, CoupledMinIter, &
3602
CoupledMaxIter, OutputIntervals, Transient, Scanning)
3603
3604
DO i=1,NoParam
3605
Fvec(i) = GetControlValue(CurrentModel % Mesh,CurrentModel % Control,i)
3606
END DO
3607
3608
PRINT *,'Fvec:',iSweep, Fvec
3609
3610
END SUBROUTINE ExecSimulationFunVec
3611
3612
3613
!------------------------------------------------------------------------------
3614
!> This is a handle for doing parametric simulation with optimizers that
3615
!> except one single value of cost function.
3616
!------------------------------------------------------------------------------
3617
3618
SUBROUTINE ExecSimulationFunCost(NoParam,Param,Cost)
3619
INTEGER, INTENT(in) :: NoParam
3620
REAL(KIND=dp), INTENT(in) :: Param(NoParam)
3621
REAL(KIND=dp), INTENT(out) :: Cost
3622
3623
INTEGER :: i, cnt, iSweep = 0
3624
LOGICAL :: Found
3625
3626
iSweep = iSweep + 1
3627
3628
CALL Info('ExecSimulationFunCost','Calling Elmer as a cost function: '//I2S(iSweep))
3629
3630
IF(iSweep==1) THEN
3631
CONTINUE
3632
ELSE
3633
CALL ControlResetMesh(Control % Control, iSweep )
3634
END IF
3635
3636
! Optionally reset the mesh if it has been modified
3637
CALL ControlResetMesh(Control % Control, iSweep )
3638
3639
! Set parameters to be accessible to the MATC preprocessor when reading sif file.
3640
CALL SetRealParametersMATC(NoParam,Param)
3641
! Reread the sif file for MATC changes to take effect
3642
Found = ReloadInputFile(CurrentModel,RewindFile=.TRUE.)
3643
3644
! Update the parameters also as coefficient as we don't know which one we are using
3645
CALL SetRealParametersKeywordCoeff(NoParam,Param,cnt)
3646
CALL Info('ExecSimulationFunCost','Set '//I2S(cnt)//&
3647
' coefficients with parameter tags!',Level=10)
3648
3649
CALL InitializeIntervals()
3650
CALL SetInitialConditions()
3651
3652
CALL ExecSimulation( TimeIntervals, CoupledMinIter, &
3653
CoupledMaxIter, OutputIntervals, Transient, Scanning)
3654
3655
CALL GetCostFunction(CurrentModel % Control,Cost,Found)
3656
IF(.NOT. Found ) THEN
3657
CALL Fatal('ExecSimulationFunCost','Could not find cost function!')
3658
END IF
3659
3660
PRINT *,'Cost:',iSweep, Cost
3661
3662
END SUBROUTINE ExecSimulationFunCost
3663
!------------------------------------------------------------------------------
3664
#endif
3665
3666
!------------------------------------------------------------------------------
3667
!> Saves current timestep to external files.
3668
!------------------------------------------------------------------------------
3669
SUBROUTINE SaveCurrent( CurrentStep )
3670
!------------------------------------------------------------------------------
3671
INTEGER :: i, j,k,l,n,m,q,CurrentStep,nlen,Time
3672
TYPE(Variable_t), POINTER :: Var, TimeVar
3673
LOGICAL :: EigAnal, GotIt, BinaryOutput, SaveAll, OutputActive, EveryTime
3674
TYPE(ValueList_t), POINTER :: vList
3675
TYPE(Solver_t), POINTER :: pSolver
3676
3677
CALL Info('SaveCurrent','Saving information on current step',Level=20)
3678
3679
! There are currently global definitions that apply also for solver specific meshes
3680
vList => CurrentModel % Simulation
3681
BinaryOutput = ListGetLogical( vList,'Binary Output',GotIt )
3682
SaveAll = .NOT. ListGetLogical( vList,'Omit unchanged variables in output',GotIt )
3683
IF ( .NOT.GotIt ) SaveAll = .TRUE.
3684
3685
3686
Mesh => CurrentModel % Meshes
3687
DO WHILE( ASSOCIATED( Mesh ) )
3688
3689
! We want to be able to give the "output file" a different name for solver-specific
3690
! meshes. Otherwise we might write data on the same file.
3691
vList => CurrentModel % Simulation
3692
OutputActive = Mesh % OutputActive
3693
m = Mesh % SolverId
3694
IF( m > 0 ) THEN
3695
pSolver => CurrentModel % Solvers(m)
3696
IF( ListCheckPresent( pSolver % Values,'Output File') ) THEN
3697
vList => pSolver % Values
3698
OutputActive = ListGetLogical( vList,'Mesh Output',GotIt)
3699
IF(.NOT. GotIt) OutputActive = Mesh % OutputActive
3700
END IF
3701
END IF
3702
3703
IF(.NOT. OutputActive ) THEN
3704
Mesh => Mesh % Next
3705
CYCLE
3706
END IF
3707
3708
OutputFile = ListGetString( vList,'Output File',GotIt)
3709
IF(GotIt) THEN
3710
i = INDEX( OutputFile,'/')
3711
IF( i > 0 ) THEN
3712
CALL Warn('SaveCurrent','> Output File < for restart should not include directory: '&
3713
//TRIM(OutputFile))
3714
END IF
3715
3716
! This was added for needs of calving where remeshing is applied and can go wrong but
3717
! we want to study the results.
3718
EveryTime = ListGetLogical( vList,'Output File Each Timestep',GotIt)
3719
IF(EveryTime) THEN
3720
TimeVar => VariableGet( CurrentModel % Variables, 'Timestep' )
3721
Time = INT(TimeVar % Values(1))
3722
3723
OutputFile = OutputFile // '.' // i2s(Time)
3724
3725
! set saves to zero. This will insure new save file even if remeshing fails
3726
Mesh % SavesDone = 0
3727
END IF
3728
3729
!IF ( ParEnv % PEs > 1 ) THEN
3730
! DO i=1,MAX_NAME_LEN
3731
! IF ( OutputFile(i:i) == ' ' ) EXIT
3732
! END DO
3733
! OutputFile(i:i) = '.'
3734
! WRITE( OutputFile(i+1:), '(a)' ) i2s(ParEnv % MyPE)
3735
!END IF
3736
3737
! Always write the output with respect to mesh file
3738
nlen = LEN_TRIM(Mesh % Name )
3739
IF ( nlen > 0 ) THEN
3740
OutputName = Mesh % Name(1:nlen) // '/' // TRIM(OutputFile)
3741
END IF
3742
3743
EigAnal = .FALSE.
3744
DO i=1,CurrentModel % NumberOfSolvers
3745
pSolver => CurrentModel % Solvers(i)
3746
IF ( ASSOCIATED( pSolver % Mesh, Mesh ) ) THEN
3747
EigAnal = ListGetLogical( pSolver % Values,'Eigen Analysis', GotIt ) .OR. &
3748
ListGetLogical( pSolver % Values,'Harmonic Analysis', GotIt )
3749
3750
IF ( EigAnal ) THEN
3751
Var => pSolver % Variable
3752
IF ( ASSOCIATED(Var % EigenValues) ) THEN
3753
IF ( TotalTimesteps == 1 ) THEN
3754
DO j=1,pSolver % NOFEigenValues
3755
IF ( pSolver % Matrix % COMPLEX ) THEN
3756
3757
n = SIZE(Var % Values)/Var % DOFs
3758
DO k=1,n
3759
DO l=1,Var % DOFs/2
3760
q = Var % DOFs*(k-1)
3761
Var % Values(q+l) = REAL(Var % EigenVectors(j,q/2+l))
3762
Var % Values(q+l+Var % DOFs/2) = AIMAG(Var % EigenVectors(j,q/2+l))
3763
END DO
3764
END DO
3765
ELSE
3766
Var % Values = REAL( Var % EigenVectors(j,:) )
3767
END IF
3768
SavedSteps = SaveResult( OutputName, Mesh, &
3769
j, sTime(1), BinaryOutput, SaveAll, vList = vList )
3770
END DO
3771
ELSE
3772
j = MIN( CurrentStep, SIZE( Var % EigenVectors,1 ) )
3773
IF ( pSolver % Matrix % COMPLEX ) THEN
3774
n = SIZE(Var % Values)/Var % DOFs
3775
DO k=1,n
3776
DO l=1,Var % DOFs/2
3777
q = Var % DOFs*(k-1)
3778
Var % Values(q+l) = REAL(Var % EigenVectors(j,q/2+l))
3779
Var % Values(q+l+Var % DOFs/2) = AIMAG(Var % EigenVectors(j,q/2+l))
3780
END DO
3781
END DO
3782
ELSE
3783
Var % Values = REAL(Var % EigenVectors(j,:))
3784
END IF
3785
SavedSteps = SaveResult( OutputName, Mesh, &
3786
CurrentStep, sTime(1), BinaryOutput, SaveAll, vList = vList )
3787
END IF
3788
Var % Values = 0.0d0
3789
END IF
3790
END IF
3791
END IF
3792
END DO
3793
3794
IF ( .NOT. EigAnal ) THEN
3795
SavedSteps = SaveResult( OutputName,Mesh, NINT(sStep(1)), &
3796
sTime(1), BinaryOutput, SaveAll, vList = vList )
3797
END IF
3798
ELSE
3799
Mesh % SavesDone = Mesh % SavesDone+1
3800
END IF
3801
Mesh => Mesh % Next
3802
END DO
3803
3804
!------------------------------------------------------------------------------
3805
END SUBROUTINE SaveCurrent
3806
!------------------------------------------------------------------------------
3807
3808
!------------------------------------------------------------------------------
3809
!> Saves results file to post processing file of ElmerPost format, if requested.
3810
!------------------------------------------------------------------------------
3811
SUBROUTINE SaveToPost(CurrentStep)
3812
!------------------------------------------------------------------------------
3813
TYPE(Variable_t), POINTER :: Var
3814
LOGICAL :: EigAnal = .FALSE., Found
3815
INTEGER :: i, j,k,l,n,q,CurrentStep,nlen,nlen2,timesteps,SavedEigenValues
3816
CHARACTER(LEN=MAX_NAME_LEN) :: Simul, SaveWhich
3817
CHARACTER(MAX_PATH_LEN) :: OutputDirectory
3818
TYPE(Solver_t), POINTER :: pSolver
3819
3820
Simul = ListGetString( CurrentModel % Simulation,'Simulation Type' )
3821
3822
OutputFile = ListGetString( CurrentModel % Simulation,'Output File',GotIt )
3823
3824
IF ( Gotit ) THEN
3825
IF ( ParEnv % PEs > 1 ) THEN
3826
OutputFile = OutputFile // '.' // i2s(ParEnv % MyPE)
3827
END IF
3828
END IF
3829
3830
PostFile = ListGetString( CurrentModel % Simulation,'Post File',GotIt )
3831
IF( .NOT. GotIt ) RETURN
3832
3833
IF ( ParEnv % PEs > 1 ) THEN
3834
PostFile = PostFile // '.' // i2s(ParEnv % MyPE)
3835
END IF
3836
3837
! Loop over all meshes
3838
!---------------------------------------------------
3839
Mesh => CurrentModel % Meshes
3840
DO WHILE( ASSOCIATED( Mesh ) )
3841
IF ( CurrentStep == 0 .AND. Mesh % SavesDone > 0) THEN
3842
Mesh => Mesh % Next
3843
CYCLE
3844
END IF
3845
3846
! Check whether this mesh is active for saving
3847
!--------------------------------------------------
3848
IF ( Mesh % OutputActive ) THEN
3849
nlen = LEN_TRIM(Mesh % Name)
3850
3851
IF ( nlen==0 .OR. FileNameQualified(OutputFile) ) THEN
3852
OutputName = OutputFile
3853
ELSE
3854
OutputName = Mesh % Name(1:nlen)//'/'//TRIM(OutputFile)
3855
END IF
3856
3857
nlen2 = LEN_TRIM(OutputPath)
3858
IF(nlen2 == 1) THEN
3859
IF(OutputPath(1:1) == '.') nlen2 = 0
3860
END IF
3861
3862
! If "Results Directory" is given (nlen2>0) we want to give that
3863
! priority over mesh directory.
3864
IF ( FileNameQualified(PostFile) .OR. nlen2 > 0 .OR. nlen==0 ) THEN
3865
PostName = PostFile
3866
ELSE
3867
PostName = Mesh % Name(1:nlen)//'/'//TRIM(PostFile)
3868
END IF
3869
3870
IF ( ListGetLogical( CurrentModel % Simulation,'Filename Numbering',GotIt) ) THEN
3871
IF( CurrentStep == 0 ) THEN
3872
PostName = NextFreeFilename(PostName)
3873
ELSE
3874
PostName = NextFreeFilename(PostName,LastExisting = .TRUE. )
3875
END IF
3876
END IF
3877
3878
! Set the Mesh pointer in the CurrentModel
3879
CALL SetCurrentMesh( CurrentModel, Mesh )
3880
3881
! Use number of timesteps or number of eigenmodes
3882
!------------------------------------------------
3883
EigAnal = .FALSE.
3884
timesteps = TotalTimeSteps
3885
DO i=1,CurrentModel % NumberOfSolvers
3886
pSolver => CurrentModel % Solvers(i)
3887
IF (ASSOCIATED(pSolver % Mesh, Mesh)) THEN
3888
EigAnal = ListGetLogical( pSolver % Values, 'Eigen Analysis', GotIt ) .OR. &
3889
ListGetLogical( pSolver % Values, 'Harmonic Analysis', GotIt )
3890
IF ( EigAnal ) timesteps = MAX( timesteps, pSolver % NOFEigenValues )
3891
END IF
3892
END DO
3893
3894
DO i=1,CurrentModel % NumberOfSolvers
3895
pSolver => CurrentModel % Solvers(i)
3896
IF (ASSOCIATED(pSolver % Mesh, Mesh)) THEN
3897
EigAnal = ListGetLogical( pSolver % Values, 'Eigen Analysis', GotIt ) .OR. &
3898
ListGetLogical( pSolver % Values, 'Harmonic Analysis', GotIt )
3899
3900
IF ( EigAnal ) THEN
3901
SaveWhich = ListGetString( pSolver % Values, &
3902
'Eigen and Harmonic Solution Output', Found )
3903
SavedEigenValues = pSolver % NOFEigenValues
3904
3905
DO j=1, SavedEigenValues
3906
Var => Mesh % Variables
3907
DO WHILE(ASSOCIATED(Var))
3908
IF ( .NOT. ASSOCIATED(Var % EigenValues) ) THEN
3909
Var => Var % Next
3910
CYCLE
3911
END IF
3912
3913
IF ( pSolver % Matrix % COMPLEX ) THEN
3914
IF(Var % DOFs==1) THEN
3915
Var => Var % Next
3916
CYCLE
3917
END IF
3918
3919
n = SIZE(Var % Values)/Var % DOFs
3920
DO k=1,n
3921
DO l=1,Var % DOFs/2
3922
q = Var % DOFs*(k-1)
3923
Var % Values(q+l) = REAL(Var % EigenVectors(j,q/2+l))
3924
Var % Values(q+l+Var % DOFs/2) = AIMAG(Var % EigenVectors(j,q/2+l))
3925
END DO
3926
END DO
3927
3928
ELSE
3929
SELECT CASE( SaveWhich )
3930
CASE('real part')
3931
Var % Values = Var % EigenVectors(j,:)
3932
CASE('imag part')
3933
Var % Values = AIMAG(Var % EigenVectors(j,:))
3934
CASE('abs value')
3935
Var % Values = ABS(Var % EigenVectors(j,:))
3936
CASE('phase angle')
3937
Var % Values = ATAN2(AIMAG(Var % EigenVectors(j,:)), &
3938
REAL(Var % EigenVectors(j,:)))
3939
CASE DEFAULT
3940
Var % CValues => Var % EigenVectors(j,:)
3941
END SELECT
3942
END IF
3943
Var => Var % Next
3944
END DO
3945
3946
IF ( CurrentStep > 0 ) THEN
3947
IF ( Mesh % SavesDone /= 0 ) THEN
3948
IF( TotalTimeSteps == 1 ) THEN
3949
Mesh % SavesDone = j
3950
ELSE
3951
Mesh % SavesDone = CurrentStep
3952
END IF
3953
END IF
3954
CALL WritePostFile( PostName,OutputName, CurrentModel, &
3955
pSolver % NOFEigenValues, .TRUE. )
3956
END IF
3957
END DO
3958
EXIT
3959
END IF
3960
END IF
3961
END DO
3962
3963
! If this mesh has not been saved, then do so
3964
!----------------------------------------------------------------------------
3965
IF ( .NOT. EigAnal .OR. CurrentStep == 0 ) THEN
3966
CALL WritePostFile( PostName, OutputName, CurrentModel, timesteps, .TRUE. )
3967
END IF
3968
3969
Var => Mesh % Variables
3970
DO WHILE(ASSOCIATED(Var))
3971
IF ( ASSOCIATED(Var % EigenValues) ) THEN
3972
Var % Values = 0._dp
3973
Var % CValues => NULL()
3974
END IF
3975
Var => Var % Next
3976
END DO
3977
END IF
3978
Mesh => Mesh % Next
3979
END DO
3980
!------------------------------------------------------------------------------
3981
END SUBROUTINE SaveToPost
3982
!------------------------------------------------------------------------------
3983
3984
!------------------------------------------------------------------------------
3985
END SUBROUTINE ElmerSolver
3986
!------------------------------------------------------------------------------
3987
3988
!> \} ElmerLib
3989
3990