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