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 program is free software; you can redistribute it and/or
8! *  modify it under the terms of the GNU General Public License
9! *  as published by the Free Software Foundation; either version 2
10! *  of the License, or (at your option) any later version.
11! *
12! *  This program 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
15! *  GNU General Public License for more details.
16! *
17! *  You should have received a copy of the GNU General Public License
18! *  along with this program (in file fem/GPL-2); if not, write to the
19! *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20! *  Boston, MA 02110-1301, USA.
21! *
22! *****************************************************************************/
23!
24!/******************************************************************************
25! *
26! *  Mesh adaptation & variable interpolation for 2D calving model. Original
27! *  notes from Peter below:
28! *
29! *  This solver may be used to map the field variables of a stretched mesh
30! *  to the unstretched initial configuration of the same mesh. In addition
31! *  the vertical size of the mesh is accommodated so that the height of
32! *  the mesh stays fixed. All-in-all two different mapping stages and
33! *  one solution of Laplace equation is needed for the mapping.
34! *  The user may also optionally nullify some field variables such as the
35! *  Mesh Update which should freshly start from the new configuration.
36! *
37! *  Notes:
38! *  ----------
39! *  This solver is currently only implemented for the 2D flowline case.
40! *  For 3D calving, see the Calving3D test case.
41! *  In places, the code would appear to permit 3D, but these haven't been
42! *  properly implemented or tested.
43! *
44! *  Currently InterpolateMeshToMesh will not report points for which
45! *  interpolation failed (although InterpolateVarToVarReduced *will*).
46! *  When the new variable is created, it's values are set to -HUGE()
47! *  in the hope that it will be obvious to the user that a problem has
48! *  occurred, though of course the long term solution should be to report
49! *  failure... This is probably only a minor issue, as no points should
50! *  ever be missing, as this would indicate a larger problem with
51! *  this routine.
52! *
53! *  In addition to dealing with the mesh manipulation required for a calving
54! *  event, this subroutine (in conjunction with Calving.F90), can also modify
55! *  the mesh when a frontal melting overhang becomes so severe as to force
56! *  'calving front' nodes below 'bed' nodes.  This is done via the 'RemeshOccurs'
57! *  switch.
58! ******************************************************************************
59! *
60! *  Authors: Peter R�back, Joe Todd
61! *  Email:   Peter.Raback@csc.fi
62! *  Web:     http://www.csc.fi/elmer
63! *  Address: CSC - IT Center for Science Ltd.
64! *           Keilaranta 14
65! *           02101 Espoo, Finland
66! *
67! *  Original Date: 19.10.2010
68! *
69! ****************************************************************************/
70
71SUBROUTINE TwoMeshes( Model,Solver,dt,TransientSimulation )
72!------------------------------------------------------------------------------
73  USE DefUtils
74  USE CRSMatrix
75  USE GeneralUtils
76  USE ElementDescription
77  USE MeshUtils
78  USE InterpVarToVar
79
80  IMPLICIT NONE
81!------------------------------------------------------------------------------
82  TYPE(Solver_t) :: Solver
83  TYPE(Model_t) :: Model
84  REAL(KIND=dp) :: dt
85  LOGICAL :: TransientSimulation
86!------------------------------------------------------------------------------
87! Local variables
88!------------------------------------------------------------------------------
89
90  TYPE(Mesh_t), POINTER :: MeshA => NULL(), MeshB => NULL(), Mesh0 => Null(),&
91       MeshTop => Null(), MeshBot => Null()
92  TYPE(Variable_t), POINTER :: Var, Var2, VarNew, VarTop, VarBot, VarDisplace1, VarDisplace2, &
93       TopVar, BotVar, FrontVar, FirstBCVar, LastBodyVar
94  TYPE(Element_t), POINTER :: Element
95  TYPE(Nodes_t), POINTER :: NodesA, NodesB, Nodes0, NodesTop, NodesBot, PreNodes, PostNodes
96  CHARACTER(LEN=MAX_NAME_LEN) :: Name, VarName, TopMaskName, BotMaskName, FrontMaskName, SolverName
97  REAL(KIND=dp) :: BoundingBox(6),eps1,eps2, Norm, &
98      TopDisplacement, BotDisplacement, H, B, T, y, p, &
99      PreArea, PostArea, TotalLoss, BergLength, BergHeight
100  INTEGER :: i,j,n,dim,istat,HeightDim, NoNodes, TopNodes, BotNodes, &
101      OldBotNodes, FrontNodes, active, TopCornerIndex, BotCornerIndex, County
102  INTEGER, POINTER :: TopPerm(:), BotPerm(:), FrontPerm(:), HeightPerm(:), &
103       FieldPerm(:), WorkInt(:)
104  REAL(KIND=dp), POINTER :: TopValues(:), BotValues(:), FrontValues(:), Height(:), ForceVector(:), Field(:),AuxReal(:)
105  TYPE(Matrix_t), POINTER  :: StiffMatrix
106  REAL(KIND=dp), ALLOCATABLE :: STIFF(:,:), FORCE(:)
107  LOGICAL :: Found,RebuiltQuadrantTree,FSTop,FSBot,NeedInit=.FALSE., &
108       MapCondition, RemeshCondition, Parallel, Debug = .FALSE., FirstTime = .TRUE.
109  LOGICAL, POINTER :: UnfoundNodes(:)
110
111  SAVE MeshA, MeshB, Mesh0, MeshTop, MeshBot, NodesA, NodesB, Nodes0, &
112      NodesTop, NodesBot, dim, HeightDim, TopCornerIndex, BotCornerIndex, &
113      TopPerm, BotPerm, FrontPerm, TopValues, BotValues, FrontValues, NoNodes,&
114      TopNodes, BotNodes, TopMaskName, BotMaskName, Height, HeightPerm, &
115      STIFF, FORCE, FirstTime, FSTop, FSBot, TotalLoss, PreNodes, PostNodes, &
116      FirstBCVar, LastBodyVar
117
118  INTERFACE
119     SUBROUTINE InterpolateMeshToMesh( OldMesh, NewMesh, OldVariables, &
120          NewVariables, UseQuadrantTree, Projector, MaskName, UnfoundNodes )
121       !------------------------------------------------------------------------------
122       USE Lists
123       USE SParIterComm
124       USE Interpolation
125       USE CoordinateSystems
126       !-------------------------------------------------------------------------------
127       TYPE(Mesh_t), TARGET  :: OldMesh, NewMesh
128       TYPE(Variable_t), POINTER, OPTIONAL :: OldVariables, NewVariables
129       LOGICAL, OPTIONAL :: UseQuadrantTree
130       LOGICAL, POINTER, OPTIONAL :: UnfoundNodes(:)
131       TYPE(Projector_t), POINTER, OPTIONAL :: Projector
132       CHARACTER(LEN=*),OPTIONAL :: MaskName
133     END SUBROUTINE InterpolateMeshToMesh
134  END INTERFACE
135
136!------------------------------------------------------------------------------
137
138  Debug = .FALSE.
139  SolverName = "TwoMeshes"
140
141  CALL Info( SolverName, '-----------------------------------' )
142  CALL Info( SolverName, ' Adapting the calving mesh...' )
143  CALL Info( SolverName, '-----------------------------------' )
144
145  dim = CoordinateSystemDimension()
146  IF(dim /= 2) THEN
147     CALL Fatal(SolverName, "This solver only works in 2D, sorry!")
148  END IF
149  !This is somewhat redundant but it permits the possibility of future generalisation
150  HeightDim = dim
151
152
153  Parallel = ParEnv % Pes > 1
154  IF(Parallel) CALL Fatal(SolverName, "Solver does not work in parallel yet!")
155
156  IF ( FirstTime ) THEN
157     FirstTime = .FALSE.
158
159     !variable to store total mass lost through calving
160     TotalLoss = 0.0_dp
161
162     !If both top and bottom surfaces are free, we simply interpolate
163     !them from the previous (t-1) timestep.  However, repeated interpolation
164     !on a fixed surface will lead to artificial smoothing, so we must store
165     !the t=0 surface and interpolate from that each time.
166     FSTop = ListGetLogical( Solver % Values, 'FS Top', Found)
167     IF(.NOT. Found) THEN
168        Call Warn(SolverName,'No value "FS Top" found, assuming Free Surface at surface.')
169        FSTop = .TRUE.
170     END IF
171
172     FSBot = ListGetLogical( Solver % Values, 'FS Bottom', Found)
173     IF(.NOT. Found) THEN
174        Call Warn(SolverName,'No value "FS Bottom" found, assuming no Free Surface at bed.')
175        FSBot = .FALSE.
176     END IF
177
178     IF((.NOT. FSBot).OR.(.NOT. FSTop))THEN
179        NeedInit = .TRUE.
180     END IF
181
182     MeshA => Solver % Mesh
183     NodesA => MeshA % Nodes
184
185     MeshB => AllocateMesh()
186     MeshB = MeshA
187     MeshB % Name = TRIM(MeshA % Name)//'_copy'
188
189     CALL Info(SolverName,'Allocated a new copy of the mesh')
190
191     IF(NeedInit)THEN
192        Mesh0 => AllocateMesh()
193        Mesh0 = MeshA
194        Mesh0 % Name = TRIM(Solver % Mesh % Name)//'_initial'
195        CALL Info(SolverName,'Created initial reference mesh because at least one surface is fixed')
196     END IF
197
198     NoNodes = SIZE( MeshA % Nodes % x )
199     NULLIFY( MeshB % Nodes )
200     ALLOCATE( NodesB )
201     ALLOCATE( NodesB % x(NoNodes), NodesB % y(NoNodes), NodesB % z(NoNodes) )
202     NodesB % x = NodesA % x
203     NodesB % y = NodesA % y
204     NodesB % z = NodesA % z
205     MeshB % Nodes => NodesB
206
207     ALLOCATE( Nodes0 )
208     ALLOCATE( Nodes0 % x(NoNodes), Nodes0 % y(NoNodes), Nodes0 % z(NoNodes) )
209     Nodes0 % x = NodesA % x
210     Nodes0 % y = NodesA % y
211     Nodes0 % z = NodesA % z
212     IF(NeedInit) Mesh0 % Nodes => Nodes0
213
214     !Get the height variable for geometry interpolation
215     HeightPerm => Solver % Variable % Perm
216     Height => Solver % Variable % Values
217
218     !The convenience variables MeshTop/Bot and NodesTop/Bot remove the
219     !need for multiple IF statements later on.
220     !------------------------------------------------------------
221     IF(FSTop) THEN
222        MeshTop => MeshA
223     ELSE
224        MeshTop => Mesh0
225     END IF
226
227     IF(FSBot) THEN
228        MeshBot => MeshA
229     ELSE
230        MeshBot => Mesh0
231     END IF
232
233     NodesTop => MeshTop % Nodes
234     NodesBot => MeshBot % Nodes
235
236     ! Nullify the list of variables to take use of the automatic
237     ! features of the mapping
238     NULLIFY( MeshB % Variables )
239
240     ! Create the variables in MeshB
241     ! These need to be there for successful mapping
242     !--------------------------------------------------------------
243     DO i=1,99
244
245        WRITE( Name, '(A,I0)') 'Variable ',i
246        VarName = ListGetString( Solver % Values,TRIM(Name),Found)
247        IF(.NOT. Found ) EXIT
248
249        Var => VariableGet( MeshA % Variables, TRIM( VarName), ThisOnly = .TRUE.)
250        IF( ASSOCIATED( Var) ) THEN
251           NULLIFY( Field, FieldPerm )
252           ALLOCATE( Field(SIZE(Var % Values)), FieldPerm(SIZE(Var % Perm)) )
253
254           !TODO InterpolateMeshToMesh should be made to report missing points in
255           !interpolation, as InterpVarToVar currently does.
256           Field = -HUGE(Field)
257           FieldPerm = Var % Perm
258
259           CALL VariableAdd( MeshB % Variables, MeshB, Solver, TRIM( VarName), 1, Field, FieldPerm )
260
261           IF(ASSOCIATED(Var % PrevValues)) THEN
262              VarNew => VariableGet( MeshB % Variables, TRIM( VarName), ThisOnly = .TRUE. )
263              ALLOCATE( VarNew % PrevValues ( SIZE( Var % PrevValues,1), &
264                                              SIZE( Var % PrevValues,2) ) )
265           END IF
266           CALL Info(SolverName,'Created variable: '//TRIM( VarName ) )
267        ELSE
268           WRITE(Message,'(a,a,a)') "Requested variable: ", TRIM(VarName), " but it wasn't found!"
269           CALL Warn(SolverName, Message)
270        END IF
271     END DO
272
273     DO i=1,99
274        !Variables created here (listed in the sif Solver section) are those
275        !which are only defined on the upper and lower surface
276        !They are interpolated using InterpolateVarToVarReduced
277
278        WRITE( Name, '(A,I0)') 'Surface Variable ',i
279        VarName = ListGetString( Solver % Values,TRIM(Name),Found)
280        IF(.NOT. Found ) EXIT
281
282        Var => VariableGet( MeshA % Variables, TRIM( VarName), ThisOnly = .TRUE. )
283
284        IF( ASSOCIATED( Var) ) THEN
285           NULLIFY( Field, FieldPerm)
286           ALLOCATE( Field(SIZE(Var % Values)), FieldPerm(SIZE(Var % Perm)) )
287           Field = Var % Values
288           !Field = 0.0_dp
289           FieldPerm = Var % Perm
290
291           CALL VariableAdd( MeshB % Variables, MeshB, Solver, TRIM( VarName), 1, Field, FieldPerm )
292
293           IF(i==1) THEN
294              !Keep a handle on this so we can split variable list when interpolating
295              FirstBCVar => VariableGet( MeshB % Variables, TRIM( VarName), ThisOnly = .TRUE. )
296           END IF
297
298           IF(ASSOCIATED(Var % PrevValues)) THEN
299              VarNew => VariableGet( MeshB % Variables, TRIM( VarName), ThisOnly = .TRUE. )
300              ALLOCATE( VarNew % PrevValues ( SIZE( Var % PrevValues,1),&
301                                              SIZE( Var % PrevValues,2) ) )
302           END IF
303           CALL Info(SolverName,'Created surface variable: '//TRIM( VarName ) )
304        ELSE
305           WRITE(Message,'(a,a,a)') "Requested surface variable: ", &
306                TRIM(VarName), " but it wasn't found!"
307           CALL Warn(SolverName, Message)
308        END IF
309     END DO
310
311     !Handle to last body variable, same as above
312     Var => MeshB % Variables
313     DO WHILE(ASSOCIATED(Var))
314        IF(ASSOCIATED(Var % Next, FirstBCVar)) THEN
315           LastBodyVar => Var
316           EXIT
317        END IF
318        Var => Var % Next
319     END DO
320
321     ! Create variable for the top surface
322     !---------------------------------------------------
323     TopMaskName = 'Top Surface Mask'
324     TopVar => VariableGet(MeshTop % Variables, TopMaskName, ThisOnly=.TRUE.)
325
326     IF(ASSOCIATED(TopVar)) THEN
327        TopValues => TopVar % Values
328        TopPerm => TopVar % Perm
329        TopNodes = COUNT(TopPerm > 0)
330     ELSE
331        ALLOCATE( TopPerm(NoNodes) )
332        CALL MakePermUsingMask( Model,Solver,MeshTop,TopMaskName, &
333             .FALSE., TopPerm, TopNodes )
334
335        ALLOCATE( TopValues(TopNodes) )
336        CALL VariableAdd( MeshTop % Variables, MeshTop, Solver, &
337             TopMaskName, 1, TopValues, TopPerm )
338     END IF
339
340     ! Create variable for the bottom surface
341     !---------------------------------------------------
342     BotMaskName = 'Bottom Surface Mask'
343     BotVar => VariableGet(MeshBot % Variables, BotMaskName, ThisOnly=.TRUE.)
344
345     IF(ASSOCIATED(BotVar)) THEN
346        BotValues => BotVar % Values
347        BotPerm => BotVar % Perm
348        BotNodes = COUNT(BotPerm > 0)
349     ELSE
350        ALLOCATE( BotPerm(NoNodes) )
351        CALL MakePermUsingMask( Model,Solver,MeshBot,BotMaskName, &
352             .FALSE., BotPerm, BotNodes )
353
354        ALLOCATE( BotValues(BotNodes) )
355        CALL VariableAdd( MeshBot % Variables, MeshBot, Solver, &
356             BotMaskName, 1, BotValues, BotPerm )
357     END IF
358
359     ! Create variable for the calving front
360     !---------------------------------------------------
361     FrontMaskName = 'Calving Front Mask'
362     FrontVar => VariableGet(MeshBot % Variables, FrontMaskName, ThisOnly=.TRUE.)
363
364     IF(ASSOCIATED(FrontVar)) THEN
365        FrontValues => FrontVar % Values
366        FrontPerm => FrontVar % Perm
367        FrontNodes = COUNT(FrontPerm > 0)
368     ELSE
369        ALLOCATE( FrontPerm(NoNodes) )
370        CALL MakePermUsingMask( Model,Solver,MeshBot,FrontMaskName, &
371             .FALSE., FrontPerm, FrontNodes )
372
373        ALLOCATE( FrontValues(FrontNodes) )
374        CALL VariableAdd( MeshA % Variables, MeshA, Solver, &
375             FrontMaskName, 1, FrontValues, FrontPerm )
376     END IF
377
378
379     ! Find two corner nodes at calving front
380     !---------------------------------------------------
381     DO i=1,NoNodes
382        IF(TopPerm(i) > 0 .AND. FrontPerm(i) > 0) THEN
383           TopCornerIndex = i
384        END IF
385        IF(BotPerm(i) > 0 .AND. FrontPerm(i) > 0) THEN
386           BotCornerIndex = i
387        END IF
388     END DO
389
390     n = MeshA % MaxElementNodes
391     ALLOCATE( FORCE(n), STIFF(n,n), STAT=istat )
392
393     !Allocate node holders for calculating calving event size later
394     ALLOCATE(PreNodes,PostNodes)
395     ALLOCATE(PreNodes % x(2),&
396          PreNodes % y(2),&
397          PostNodes % x(2),&
398          PostNodes % y(2))
399
400  END IF !FirstTime
401
402
403  ! Add a suitable condition here for calving
404  !---------------------------------------------
405  ! This has been linked to the Calving.f90 solver by means of the "CalvingOccurs"
406  ! logical in the list.
407  MapCondition = ListGetLogical( Model % Simulation, 'CalvingOccurs', Found)
408  IF(.NOT. Found) THEN
409     CALL Warn("Two Meshes","Can't find CalvingOccurs Logical, exiting... ")
410     RETURN
411  END IF
412
413  RemeshCondition = ListGetLogical( Model % Simulation, 'RemeshOccurs', Found)
414  IF(.NOT. Found) THEN
415     CALL Warn("Two Meshes","Can't find RemeshCondition Logical, assuming false!")
416     RemeshCondition = .FALSE.
417  END IF
418
419  IF( .NOT. (MapCondition .OR. RemeshCondition)) RETURN
420
421  PreArea = ModelArea(MeshA)
422
423  !An array of 2 nodes, 1 being top, 2 bottom.
424  !This is stored to check if berg is tabular or not...
425  PreNodes % x(1) = MeshA % Nodes % x(TopCornerIndex)
426  PreNodes % y(1) = MeshA % Nodes % y(TopCornerIndex)
427  PreNodes % x(2) = MeshA % Nodes % x(BotCornerIndex)
428  PreNodes % y(2) = MeshA % Nodes % y(BotCornerIndex)
429
430  PRINT *,'Initial ranges'
431  PRINT *,'X0:',MINVAL( Nodes0 % x), MAXVAL( Nodes0 % x)
432  PRINT *,'XA:',MINVAL( NodesA % x), MAXVAL( NodesA % x)
433  PRINT *,'XB:',MINVAL( NodesB % x), MAXVAL( NodesB % x)
434
435  ! First copy the top and bottom (and front) height to variables
436  !----------------------------------------------------------
437  DO i=1,NoNodes
438    j = TopPerm(i)
439    IF( j > 0 ) THEN
440      IF( HeightDim == 1 ) THEN
441        TopValues(j) = NodesTop % x(i)
442      ELSE IF( HeightDim == 2 ) THEN
443        TopValues(j) = NodesTop % y(i)
444      ELSE
445        TopValues(j) = NodesTop % z(i)
446      END IF
447    END IF
448
449    j = BotPerm(i)
450    IF( j > 0 ) THEN
451      IF( HeightDim == 1 ) THEN
452        BotValues(j) = NodesBot % x(i)
453      ELSE IF( HeightDim == 2 ) THEN
454        BotValues(j) = NodesBot % y(i)
455      ELSE
456        BotValues(j) = NodesBot % z(i)
457      END IF
458    END IF
459
460    j = FrontPerm(i)
461    IF( j > 0 ) THEN
462      IF( HeightDim == 1 ) THEN
463        FrontValues(j) = NodesA % x(i)
464      ELSE IF( HeightDim == 2 ) THEN
465        FrontValues(j) = NodesA % y(i)
466      ELSE
467        FrontValues(j) = NodesA % z(i)
468      END IF
469    END IF
470  END DO
471
472  ! Map the top and bottom variables to the reference mesh
473  ! For that purpose set the coordinates of MeshB to initial ones
474  ! Stretching may be accounted for here.
475  !--------------------------------------------------------------
476  NodesB % x = NodesA % x
477  NodesB % y = NodesA % y
478  NodesB % z = NodesA % z
479
480  !At this point, our nodes are displaced due to calving.  If we were dealing only
481  !with vertical calving faces and uniform calving retreat (i.e. a perfect rectangle
482  !falls off) then we can simply say NodesB % x = NodesB % x - CalvingEventSize
483  !However, non-vertical calving faces require a more complex treatment.
484
485  !FrontDisplacement returns the translation between current pre-calving node
486  !positions and the post-calving mesh whose node positions are the result of
487  !mesh displacement on the *initial* reference mesh.  This preserves mesh
488  !quality after repeated calving/advance cycles.
489  VarDisplace1 => VariableGet(MeshA % Variables, 'Front Displacement 1', ThisOnly=.TRUE.)
490  VarDisplace2 => VariableGet(MeshA % Variables, 'Front Displacement 2', ThisOnly=.TRUE.)
491
492  NodesB % x = NodesA % x + VarDisplace1 % Values(VarDisplace1 % Perm)
493  NodesB % y = NodesA % y + VarDisplace2 % Values(VarDisplace2 % Perm)
494
495  !In the case where remeshing is required to deal with a severe melt overhang
496  !the bottom corner node may actually 'advance' (though no physical advance of
497  !the front actually takes place).
498  !In this case, its height must be interpolated from some severely tilted front
499  !nodes, and so we temporarily change their BotPerm here.
500  IF(RemeshCondition) THEN
501     IF(Debug) PRINT *, 'Debug Calving: RemeshCondition TRUE'
502     !Save BotNodes so it can be restored...
503     OldBotNodes = BotNodes
504
505     !Adding all frontnodes, except the bottom corner which is already in
506     BotNodes = BotNodes + FrontNodes - 1
507
508     ALLOCATE(AuxReal(BotNodes))
509     AuxReal = BotValues !(BotNodes - OldBotNodes) slots left empty
510
511     County = 0
512     DO i=1,NoNodes
513        IF(FrontPerm(i) == 0) CYCLE  !if it's not a front node
514        IF(BotPerm(i) /= 0) CYCLE  !if it already exists in bottom variable
515
516        County = County + 1
517        BotPerm(i) = OldBotNodes + County
518
519        AuxReal(BotPerm(i)) = MeshA % Nodes % y(i)
520        IF(Debug) THEN
521           PRINT *, 'Debug ',SolverName,': Added NEW AuxReal nodenum: ',i,&
522                ' botperm: ',BotPerm(i),' and AuxReal: ',AuxReal(BotPerm(i))
523        END IF
524     END DO
525
526     BotVar => VariableGet(MeshBot % Variables, BotMaskName, ThisOnly=.TRUE.)
527     BotVar % Values => AuxReal
528
529  END IF
530
531  !this is somewhat obtuse, but it allows InterpolateVarToVarReduced to
532  !reduce either 1 or 2 dimensions.
533  ALLOCATE(WorkInt(1)); WorkInt = HeightDim;
534  UnfoundNodes => NULL()
535  CALL InterpolateVarToVarReduced(MeshTop, MeshB, TopMaskName, WorkInt, &
536       UnfoundNodes, Variables=MeshA % Variables)
537
538  IF(ANY(UnfoundNodes)) CALL Fatal(SolverName,&
539       "Failed to find all nodes in top surface linesearch")
540  CALL Info(SolverName,'Interpolated the top values to the original mesh')
541
542  CALL InterpolateVarToVarReduced(MeshBot, MeshB, BotMaskName, WorkInt, &
543       UnfoundNodes, Variables=MeshA % Variables)
544
545  IF(ANY(UnfoundNodes)) CALL Fatal(SolverName,&
546       "Failed to find all nodes in bottom surface linesearch")
547  CALL Info(SolverName,'Interpolated the bottom values to the original mesh')
548
549  IF(RemeshCondition) THEN
550     VarBot => VariableGet(MeshB % Variables, BotMaskName, ThisOnly = .TRUE.)
551     !Reset surplus BotPerm values
552     DO i=1,NoNodes
553        IF(BotPerm(i) > OldBotNodes) THEN
554           BotPerm(i) = 0
555           VarBot % Perm(i) = 0
556        END IF
557     END DO
558     BotVar % Values => BotValues  !Reset variable values from AuxReal
559
560     IF(Debug) THEN
561        PRINT *, 'Debug ',SolverName,', BotVar % Values: ', BotVar % Values
562        PRINT *, 'Debug ',SolverName,', BotVar % Perm: ', BotVar % Perm
563     END IF
564  END IF
565
566  ! Copy interpolated height variables back to TopValues and BotValues
567  !----------------------------------------------------------
568
569  VarTop => VariableGet(MeshB % Variables, TopMaskName, ThisOnly = .TRUE.)
570  VarBot => VariableGet(MeshB % Variables, BotMaskName, ThisOnly = .TRUE.)
571  DO i=1,NoNodes
572    j = TopPerm(i)
573    IF( j > 0 ) THEN
574        TopValues(j) = VarTop % Values(VarTop % Perm(i))
575    END IF
576    j = BotPerm(i)
577    IF( j > 0 ) THEN
578        BotValues(j) = VarBot % Values(VarBot % Perm(i))
579    END IF
580  END DO
581
582  ! Find the y-shift in the calving front nodes
583  ! using the two end values from MeshA and B to guide the deformation
584  ! This is necessary for situations where the calving front is not
585  ! vertical, as the nodes will tend towards the outwardmost end otherwise
586  !----------------------------------------------------------
587
588  H = Nodes0 % y(TopCornerIndex) - Nodes0 % y(BotCornerIndex)
589  T = Nodes0 % y(TopCornerIndex)
590  B = Nodes0 % y(BotCornerIndex)
591
592  TopDisplacement = VarTop % Values(VarTop % Perm(TopCornerIndex)) - NodesB % y(TopCornerIndex)
593  BotDisplacement = VarBot % Values(VarBot % Perm(BotCornerIndex)) - NodesB % y(BotCornerIndex)
594
595  DO i=1,NoNodes
596     j = FrontPerm(i)
597     IF( j > 0 ) THEN
598        y = Nodes0 % y(i)
599        !p is 1 at the top, 0 at the bottom
600        p = ((y-B)/H)
601        FrontValues(j) = NodesB % y(i) + (p*TopDisplacement) + ((1-p)*BotDisplacement)
602     END IF
603  END DO
604
605
606  ! Then map the mesh using Laplace equation in height direction
607  !----------------------------------------------------------
608  CALL Info(SolverName,'Solving the height from poisson equation')
609  Solver % Mesh % Nodes => NodesB
610
611  CALL DefaultInitialize()
612
613  active = GetNOFActive()
614  DO i=1,active
615    Element => GetActiveElement(i)
616    n = GetElementNOFNodes()
617    CALL LocalMatrix(  STIFF, FORCE, Element, n )
618    CALL DefaultUpdateEquations( STIFF, FORCE )
619  END DO
620
621  CALL DefaultFinishAssembly()
622
623
624  ! Set top and bottom Dirichlet BCs using the ones mapped from the
625  ! deformed mesh. This eliminates the need for external BCs.
626  !-----------------------------------------------------------------
627  StiffMatrix => Solver % Matrix
628  ForceVector => StiffMatrix % RHS
629
630  DO i=1, NoNodes
631    j =  TopPerm(i)
632    IF( j > 0 ) THEN
633      CALL SetDirichtletPoint( StiffMatrix, ForceVector,1,1, &
634          HeightPerm, i, TopValues(j) )
635    END IF
636    j = BotPerm(i)
637    IF( j > 0 ) THEN
638      CALL SetDirichtletPoint( StiffMatrix, ForceVector,1,1, &
639          HeightPerm, i, BotValues(j) )
640    END IF
641    j = FrontPerm(i)
642    IF( j > 0 ) THEN
643      CALL SetDirichtletPoint( StiffMatrix, ForceVector,1,1, &
644          HeightPerm, i, FrontValues(j) )
645    END IF
646  END DO
647
648  Norm = DefaultSolve()
649
650  ! Return the nodes to the original ones in which all other variables
651  ! have been computed in order not to case problems later on...
652  Solver % Mesh % Nodes => NodesA
653
654  ! Copy the height now to the original mesh deformed to comply
655  ! with the deformed top and bottom surfaces
656  !------------------------------------------------------------
657  DO i=1,NoNodes
658    j = HeightPerm(i)
659    IF( j == 0 ) CYCLE
660    IF( HeightDim == 1 ) THEN
661      NodesB % x(i) = Height(j)
662    ELSE IF( HeightDim == 2 ) THEN
663      NodesB % y(i) = Height(j)
664    ELSE
665      NodesB % z(i) = Height(j)
666    END IF
667  END DO
668
669
670  ! Map the mesh to the real positions
671  ! Always built a new tree as MeshA has changed
672  ! This would ideally be built inside the interpolation...
673  !--------------------------------------------------------------
674  RebuiltQuadrantTree = .TRUE.
675  IF( RebuiltQuadrantTree ) THEN
676    BoundingBox(1) = MINVAL( NodesA % x )
677    BoundingBox(2) = MINVAL( NodesA % y )
678    BoundingBox(3) = MINVAL( NodesA % z )
679    BoundingBox(4) = MAXVAL( NodesA % x )
680    BoundingBox(5) = MAXVAL( NodesA % y )
681    BoundingBox(6) = MAXVAL( NodesA % z )
682
683    eps1 = 0.1_dp
684    eps2 = eps1 * MAXVAL( BoundingBox(4:6) - BoundingBox(1:3) )
685    BoundingBox(1:3) = BoundingBox(1:3) - eps2
686    BoundingBox(4:6) = BoundingBox(4:6) + eps2
687
688    IF(ASSOCIATED(MeshA % RootQuadrant)) CALL FreeQuadrantTree( MeshA % RootQuadrant )
689    CALL BuildQuadrantTree( MeshA,BoundingBox,MeshA % RootQuadrant)
690  END IF
691
692  !Manipulate variable list to prevent BC variables being interpolated,
693  !they're already interpolated by InterpolateVarToVarReduced
694  LastBodyVar % Next => NULL()
695
696  ! This one uses the standard interpolation routines with two meshes
697  ! Note that the 4th argument (the new meshes variable) is never actually used.
698  CALL InterpolateMeshToMesh( MeshA, MeshB, MeshA % Variables,MeshB % Variables, .TRUE. )
699  CALL Info('TwoMesh','Interpolation done')
700
701  !Restore variable list
702  LastBodyVar % Next => FirstBCVar
703
704  ! Now we still have the problem that the interpolated values sit on MeshB while
705  ! we would like to work with MeshA. It seems easiest to copy all the relevant
706  ! stuff back to MeshA.
707  !------------------------------------------------------------------------------
708
709  NodesA % x = NodesB % x
710  NodesA % y = NodesB % y
711  NodesA % z = NodesB % z
712
713
714  Var => MeshB % Variables
715  DO WHILE(ASSOCIATED(Var))
716     Var2 => VariableGet(MeshA % Variables, TRIM(Var % Name), ThisOnly = .TRUE.)
717     IF(.NOT. ASSOCIATED(Var2)) CALL Fatal(SolverName, "Error while copying back variables")
718
719     CALL Info(SolverName,'Copying back variable: '//TRIM( Var % Name ) )
720     Var2 % Values = Var % Values
721     PRINT *,'Range',MINVAL( Var2 % Values), MAXVAL( Var2 % Values )
722
723     Var => Var % Next
724  END DO
725
726  DO i=1,99
727     WRITE( Name, '(A,I0)') 'Nullify ',i
728     VarName = ListGetString( Solver % Values,TRIM(Name),Found)
729     IF(.NOT. Found ) EXIT
730     Var2 => VariableGet( MeshA % Variables, TRIM( VarName), ThisOnly = .TRUE. )
731     IF( ASSOCIATED( Var2) ) THEN
732        CALL Info(SolverName,'Zeroing variable: '//TRIM( VarName ) )
733        Var2 % Values = 0.0_dp
734     ELSE
735        WRITE(Message,'(a,a,a)') "Requested nullified variable: ", &
736             TRIM(VarName), " but it wasn't found!"
737        CALL Warn(SolverName, Message)
738     END IF
739  END DO
740
741  MeshA % Changed = .TRUE.
742
743  PRINT *,'Final ranges'
744  PRINT *,'X0:',MINVAL( Nodes0 % x), MAXVAL( Nodes0 % x)
745  PRINT *,'XA:',MINVAL( NodesA % x), MAXVAL( NodesA % x)
746  PRINT *,'XB:',MINVAL( NodesB % x), MAXVAL( NodesB % x)
747
748  !Calculate and print berg size
749  PostArea = ModelArea(MeshA)
750  TotalLoss = TotalLoss + (PreArea-Postarea)
751
752  WRITE(Message, '(a,E10.4,a)') 'Calving event size: ',PreArea-PostArea,' m2'
753  CALL Info(SolverName, Message)
754  WRITE(Message, '(a,E10.4,a)') 'Total mass lost through calving: ',TotalLoss,' m2'
755  CALL Info(SolverName, Message)
756
757  !Check if tabular berg or not.
758  PostNodes % x(1) = MeshA % Nodes % x(TopCornerIndex)
759  PostNodes % y(1) = MeshA % Nodes % y(TopCornerIndex)
760  PostNodes % x(2) = MeshA % Nodes % x(BotCornerIndex)
761  PostNodes % y(2) = MeshA % Nodes % y(BotCornerIndex)
762
763  BergLength = ((PreNodes % x(1) - PostNodes % x(1)) + (PreNodes % x(2) - PostNodes % x(2))) * 0.5
764  BergHeight = ((PreNodes % y(1) - PreNodes % y(2)) + ( PostNodes % y(1) - PostNodes % y(2))) * 0.5
765
766  IF(BergLength >= BergHeight) THEN
767     WRITE(Message,'(a)') 'Calving event type: tabular'
768  ELSE
769     WRITE(Message,'(a)') 'Calving event type: normal'
770  END IF
771  CALL Info(SolverName, Message)
772
773  DEALLOCATE(WorkInt, UnfoundNodes)
774  IF(RemeshCondition) DEALLOCATE(AuxReal)
775
776  CALL Info(SolverName,'All done')
777
778CONTAINS
779
780!------------------------------------------------------------------------------
781  SUBROUTINE LocalMatrix(  STIFF, FORCE, Element, n )
782!------------------------------------------------------------------------------
783    REAL(KIND=dp) :: STIFF(:,:), FORCE(:)
784    INTEGER :: n
785    TYPE(Element_t), POINTER :: Element
786!------------------------------------------------------------------------------
787    REAL(KIND=dp) :: Basis(n),dBasisdx(n,3),DetJ
788    LOGICAL :: Stat
789    INTEGER :: t
790    TYPE(GaussIntegrationPoints_t) :: IP
791
792    TYPE(Nodes_t) :: Nodes
793    SAVE Nodes
794!------------------------------------------------------------------------------
795    CALL GetElementNodes( Nodes )
796
797    FORCE = 0.0_dp
798    STIFF = 0.0_dp
799
800    !Numerical integration:
801    !----------------------
802    IP = GaussPoints( Element )
803    DO t=1,IP % n
804      stat = ElementInfo( Element, Nodes, IP % U(t), IP % V(t), &
805          IP % W(t),  detJ, Basis, dBasisdx )
806      STIFF(1:n,1:n) = STIFF(1:n,1:n) + IP % s(t) * DetJ * &
807          MATMUL( dBasisdx, TRANSPOSE( dBasisdx ) )
808    END DO
809!------------------------------------------------------------------------------
810  END SUBROUTINE LocalMatrix
811
812
813!------------------------------------------------------------------------------
814  SUBROUTINE SetDirichtletPoint( StiffMatrix, ForceVector,DOF, NDOFs, &
815      Perm, NodeIndex, NodeValue)
816!------------------------------------------------------------------------------
817
818    IMPLICIT NONE
819
820    TYPE(Matrix_t), POINTER :: StiffMatrix
821    REAL(KIND=dp) :: ForceVector(:), NodeValue
822    INTEGER :: DOF, NDOFs, Perm(:), NodeIndex
823!------------------------------------------------------------------------------
824
825    INTEGER :: PermIndex
826    REAL(KIND=dp) :: s
827
828!------------------------------------------------------------------------------
829
830    PermIndex = Perm(NodeIndex)
831
832    IF ( PermIndex > 0 ) THEN
833      PermIndex = NDOFs * (PermIndex-1) + DOF
834
835      IF ( StiffMatrix % FORMAT == MATRIX_SBAND ) THEN
836        CALL SBand_SetDirichlet( StiffMatrix,ForceVector,PermIndex,NodeValue )
837      ELSE IF ( StiffMatrix % FORMAT == MATRIX_CRS .AND. &
838          StiffMatrix % Symmetric ) THEN
839        CALL CRS_SetSymmDirichlet(StiffMatrix,ForceVector,PermIndex,NodeValue)
840      ELSE
841        s = StiffMatrix % Values(StiffMatrix % Diag(PermIndex))
842        ForceVector(PermIndex) = NodeValue * s
843        CALL ZeroRow( StiffMatrix,PermIndex )
844        CALL SetMatrixElement( StiffMatrix,PermIndex,PermIndex,1.0d0*s )
845      END IF
846    END IF
847
848!------------------------------------------------------------------------------
849  END SUBROUTINE SetDirichtletPoint
850!------------------------------------------------------------------------------
851
852  FUNCTION ModelArea(Mesh) RESULT(A)
853    TYPE(Mesh_t), POINTER :: Mesh
854    INTEGER :: i
855    REAL(KIND=dp) :: A
856
857    A = 0.0_dp
858
859    DO i=1,Mesh % NumberOfBulkElements
860
861       A = A + ElementArea(Mesh, Mesh % Elements(i), &
862            Mesh % Elements(i) % Type % NumberOfNodes)
863    END DO
864
865  END FUNCTION ModelArea
866!------------------------------------------------------------------------------
867END SUBROUTINE TwoMeshes
868