SUBROUTINE Find_Calving (Model, Solver, dt, TransientSimulation )
USE types
USE CoordinateSystems
USE SolverUtils
USE ElementDescription
USE DefUtils
IMPLICIT NONE
TYPE CrevasseGroups_t
LOGICAL, ALLOCATABLE :: NotEmpty(:),Valid(:)
INTEGER, ALLOCATABLE :: NodeIndexes(:,:), NoNodes(:)
INTEGER :: CurrentGroup
END TYPE CrevasseGroups_t
TYPE(Model_t) :: Model
TYPE(Solver_t) :: Solver
Type(Nodes_t) :: CornerElementNodes, CurrentElementNodes, &
TargetNodes, CalvedNodes
Type(Nodes_t), POINTER :: Nodes0
Type(Nodes_t), TARGET :: EvalNodes
TYPE(Matrix_t), POINTER :: Vel1Matrix
TYPE(ValueList_t), POINTER :: Material, SolverParams
TYPE(Element_t), POINTER :: CurrentElement, CornerElement
TYPE(CrevasseGroups_t) :: SurfaceCrevasseGroups, BasalCrevasseGroups
TYPE(Mesh_t), POINTER :: Mesh, EvalMesh, Mesh0 => Null()
TYPE(Variable_t), POINTER :: DepthSol, StressSol, Stress1Sol, Stress4Sol, &
Vel1Sol, DistanceSol, FlowSol, &
WPressureSol, TimeVar, CSurfIndexSol, CBasalIndexSol, Var, &
CrevasseGroupVar
REAL (KIND=dp) :: t, dt, xcoord, ycoord, NodeDepth, NodeStress, NodeStress1, NodeStress4, &
NodeWPressure, CalvingSurfIndex, CalvingBasalIndex, CalvingCoordHolder = 1.0E20, &
FreeConnect, FreeConnected, Length, WaterDepth, Dw, NodeLength, RhoWF, RhoWS, Rho, &
g, OverlapCalvingCoordinate, SeaLevel, BasalCalvingCoordinate, EvalResolution, &
STuningParam, BTuningParam, DwStart, DwStop, season, Te, sign, Normal(3), &
CornerNormal(3), BedSecond, BedSecondDiff, beddiff, BedToler, dx, dy, &
LocalDist, LocalDistNode, PropDistNode, normalcond, ForceCalveSize, &
localM(2,2), EigValues(2), EI(2), dumy, dumy2, work(8),YieldStress, &
rt0, rt
REAL (KIND=DP), POINTER :: DepthValues(:), StressValues(:), Stress1Values(:), Stress4Values(:), &
Calving1Values(:), DistanceValues(:), WPressureValues(:), FrontValues(:), &
CSurfIndexValues(:), CBasalIndexValues(:), CIndexValues(:), CrevasseGroupValues(:), &
Calving2Values(:), EvalPoints(:,:), Field(:), WorkReal(:)
REAL (KIND=dp), ALLOCATABLE :: CumDist(:), PropCumDist(:), TargetCumDist(:),TargetPropDist(:)
INTEGER :: DIM, i, j, NoNodes, MaxN, FrontNodes, BotNodes, TopNodes, &
NofEvalPoints, NextSlot, BotCornerIndex, &
BotSecondIndex, county, GoToNode, PrevNode, NextNode, &
TimeSinceLast, NoNeighbours, MaxNeighbours, DOFs, ierr, StressDOFs
INTEGER, POINTER :: DepthPerm(:), StressPerm(:), Stress1Perm(:), Stress4Perm(:),&
Vel1Perm(:), Vel1InvPerm(:), DistancePerm(:), OrderPerm(:),&
WPressurePerm(:), FrontPerm(:)=>NULL(), InvFrontPerm(:), &
TopPerm(:)=>NULL(), BotPerm(:)=>NULL(), Permutation(:), &
CSurfIndexPerm(:), CBasalIndexPerm(:), CIndexPerm(:), FieldPerm(:), &
NodeNeighbours(:,:), NumNeighbours(:), CrevasseGroupPerm(:)
INTEGER, ALLOCATABLE :: ThisNodeNeighbours(:)
LOGICAL :: FirstTime = .TRUE., CalvingOccurs, RemeshOccurs, &
BasalCalvingOccurs = .FALSE., BasalCrevasseModel, OverlapOccurs, DwSeason, &
CornerCalving, KeepLooking, TransientSimulation, Found, Debug = .FALSE., &
ForceCalving = .FALSE., PlaneStressOnly, Cauchy, OldWay, BasalFS, CornerBadBed, &
CornerBadSlope
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, FrontMaskName, BotMaskName, TopMaskName, &
DwMode, CalvingModel, FlowVarName,BasalFSVarName
SAVE :: FirstTime, DIM, Permutation, Calving1Values, Calving2Values, &
NoNodes, Mesh, FrontMaskName, FreeConnect, WaterDepth, Rho, RhoWS, RhoWF, g, &
FrontPerm, FrontValues, FrontNodes, BotPerm, BotNodes, TopPerm, &
TopNodes, CSurfIndexSol, &
CBasalIndexSol, CSurfIndexPerm, CBasalIndexPerm, CSurfIndexValues, CBasalIndexValues, &
EvalMesh, Material, EvalNodes, NodeNeighbours, NumNeighbours, Mesh0, Nodes0, &
TimeSinceLast, BasalCrevasseModel, PlaneStressOnly, Cauchy, SolverParams, OldWay, &
BasalFS, BasalFSVarName
INTERFACE
SUBROUTINE InterpolateMeshToMesh( OldMesh, NewMesh, OldVariables, &
NewVariables, UseQuadrantTree, Projector, MaskName, UnfoundNodes )
USE Lists
USE SParIterComm
USE Interpolation
USE CoordinateSystems
TYPE(Mesh_t), TARGET :: OldMesh, NewMesh
TYPE(Variable_t), POINTER, OPTIONAL :: OldVariables, NewVariables
LOGICAL, OPTIONAL :: UseQuadrantTree
LOGICAL, POINTER, OPTIONAL :: UnfoundNodes(:)
TYPE(Projector_t), POINTER, OPTIONAL :: Projector
CHARACTER(LEN=*),OPTIONAL :: MaskName
END SUBROUTINE InterpolateMeshToMesh
END INTERFACE
rt0 = RealTime()
SolverName = "Calving"
Debug = .FALSE.
IF(ParEnv % Pes > 1) CALL Fatal(SolverName, "Solver does not work in parallel!")
Timevar => VariableGet( Model % Variables,'Time', UnfoundFatal=.TRUE.)
t = TimeVar % Values(1)
dt = Model % Solver % dt
season = t - floor(t)
RemeshOccurs = .FALSE.
IF(.NOT. ASSOCIATED(Solver % Variable)) CALL Fatal('Calving', 'Variable not associated!')
CSurfIndexSol => VariableGet( Solver % Mesh % Variables, 'Calving Surface Index', &
UnfoundFatal=.TRUE.)
CSurfIndexPerm => CSurfIndexSol % Perm
CSurfIndexValues => CSurfIndexSol % Values
CBasalIndexSol => VariableGet( Solver % Mesh % Variables, 'Calving Basal Index', &
UnfoundFatal=.TRUE.)
CBasalIndexPerm => CBasalIndexSol % Perm
CBasalIndexValues => CBasalIndexSol % Values
CrevasseGroupVar => VariableGet( Solver % Mesh % Variables, 'Crevasse Group ID', &
UnfoundFatal=.TRUE.)
CrevasseGroupPerm => CrevasseGroupVar % Perm
CrevasseGroupValues => CrevasseGroupVar % Values
DepthSol => VariableGet( Model % Variables, 'Depth', UnfoundFatal=.TRUE.)
DepthPerm => DepthSol % Perm
DepthValues => DepthSol % Values
StressSol => VariableGet( Model % Variables, "Stress", UnfoundFatal=.TRUE.)
StressPerm => StressSol % Perm
StressValues => StressSol % Values
StressDOFs = StressSol % DOFs
Stress1Sol => VariableGet( Model % Variables, "Stress 1", &
UnfoundFatal=.TRUE.)
Stress1Perm => Stress1Sol % Perm
Stress1Values => Stress1Sol % Values
Stress4Sol => VariableGet( Model % Variables, "Stress 4", &
UnfoundFatal=.TRUE.)
Stress4Perm => Stress4Sol % Perm
Stress4Values => Stress4Sol % Values
DistanceSol => VariableGet( Model % Variables, "Distance", &
UnfoundFatal=.TRUE.)
DistancePerm => DistanceSol % Perm
DistanceValues => DistanceSol % Values
WPressureSol => VariableGet( Model % Variables, "Water Pressure", &
UnfoundFatal=.TRUE.)
WPressurePerm => WPressureSol % Perm
WPressureValues => WPressureSol % Values
IF(FirstTime) THEN
DIM = CoordinateSystemDimension()
IF(DIM /= 2) CALL Fatal('Calving','Solver only works in 2D!')
MaxN = Model % Mesh % MaxElementNodes
TimeSinceLast = 0
Mesh => Solver % Mesh
NoNodes = Mesh % NumberOfNodes
FrontMaskName = 'Calving Front Mask'
TopMaskName = 'Top Surface Mask'
BotMaskName = 'Bottom Surface Mask'
ALLOCATE( FrontPerm(NoNodes), TopPerm(NoNodes), BotPerm(NoNodes))
CALL MakePermUsingMask( Model,Solver,Mesh,FrontMaskName, &
.FALSE., FrontPerm, FrontNodes )
CALL MakePermUsingMask( Model,Solver,Mesh,TopMaskName, &
.FALSE., TopPerm, TopNodes )
CALL MakePermUsingMask( Model,Solver,Mesh,BotMaskName, &
.FALSE., BotPerm, BotNodes )
ALLOCATE( FrontValues(FrontNodes * 2) )
Mesh0 => AllocateMesh()
Mesh0 = Mesh
Mesh0 % Name = TRIM(Mesh % Name)//'_initial'
CALL Info('Calving','Created initial reference mesh to remap front, maintaining quality')
ALLOCATE( Nodes0 )
ALLOCATE( Nodes0 % x(NoNodes), Nodes0 % y(NoNodes), Nodes0 % z(NoNodes) )
Nodes0 % x = Mesh % Nodes % x
Nodes0 % y = Mesh % Nodes % y
Nodes0 % z = Mesh % Nodes % z
Mesh0 % Nodes => Nodes0
Permutation => FrontPerm
Calving1Values => FrontValues(1::2)
Calving2Values => FrontValues(2::2)
Calving1Values = 0.0_dp
Calving2Values = 0.0_dp
SolverParams => GetSolverParams()
ForceCalving = GetLogical(SolverParams, 'Force Calving', Found)
IF(ForceCalving) THEN
ForceCalveSize = GetConstReal (SolverParams, 'Force Calving Size', Found)
IF(.NOT.Found) CALL Fatal(SolverName, "Force Calving Size not found.")
Calving1Values = -ForceCalveSize
CalvingOccurs =.TRUE.
CALL ListAddLogical( Model % Simulation, 'CalvingOccurs', CalvingOccurs )
RETURN
END IF
ENDIF
Solver % Variable % Values => FrontValues
Solver % Variable % Perm => FrontPerm
Var => VariableGet(Solver % Mesh % Variables, ComponentName(Solver % Variable % Name, 1), .TRUE.)
Var % Values => Calving1Values
Var % Perm => Permutation
Var => VariableGet(Solver % Mesh % Variables, ComponentName(Solver % Variable % Name, 2), .TRUE.)
Var % Values => Calving2Values
Var % Perm => Permutation
IF(FirstTime .OR. Solver % Mesh % Changed) THEN
FirstTime = .FALSE.
Vel1Sol => VariableGet( Solver % Mesh % Variables, 'Velocity 1', UnfoundFatal=.TRUE.)
Vel1Perm => Vel1Sol % Perm
Vel1Matrix => Vel1Sol % Solver % Matrix
DOFs = DIM + 1
MaxNeighbours = DIM * 10
ALLOCATE(Vel1InvPerm(MAXVAL(Vel1Perm)*DOFs))
ALLOCATE(NodeNeighbours(NoNodes,MaxNeighbours))
ALLOCATE(NumNeighbours(NoNodes))
NodeNeighbours = 0
NumNeighbours = 0
Vel1InvPerm = 0
j = 0
DO i=1,SIZE(Vel1Perm)
IF(Vel1Perm(i) == 0) CYCLE
j = j + 1
Vel1InvPerm( (Vel1Perm(i)*DOFs-2) : (Vel1Perm(i)*DOFs) ) = j
END DO
DO i = 1,NoNodes
CALL FindNodeNeighbours(i)
NumNeighbours(i) = SIZE(ThisNodeNeighbours)
NodeNeighbours(i,1:NumNeighbours(i)) = ThisNodeNeighbours
END DO
END IF
PRINT *, '****Calving Timestep : ',t
rt = RealTime() - rt0
IF(ParEnv % MyPE == 0) &
PRINT *, 'Calving, time taken for variable loading etc:', rt
rt0 = RealTime()
MaxN = Model % Mesh % MaxElementNodes
OldWay = ListGetLogical(SolverParams, "Old Way", Found)
IF(.NOT. Found) OldWay = .FALSE.
BasalFS = ListGetLogical(SolverParams, "Basal FreeSurface", Found)
IF(.NOT. Found) BasalFS = .TRUE.
IF(BasalFS) THEN
BasalFSVarName = ListGetString(SolverParams, "Basal FreeSurface Variable Name",Found)
IF(.NOT. Found) CALL Fatal(SolverName, &
"Basal FreeSurface = True but no Basal FreeSurface Variable Name found!")
END IF
Material => GetMaterial(Model % Mesh % Elements(Solver % ActiveElements(1)))
Cauchy = ListGetLogical( Material , 'Cauchy', Found )
IF(.NOT. Found) THEN
Cauchy = .FALSE.
CALL Warn(SolverName, "Couldn't find 'cauchy' logical in material, &
&assuming deviatoric stress.")
END IF
FlowVarName = ListGetString(SolverParams, "Flow Solution Variable Name",Found)
IF(.NOT. Found) FlowVarName = "Flow Solution"
FlowSol => VariableGet(Model % Variables, FlowVarName, .TRUE., UnfoundFatal=.TRUE.)
FreeConnect = GetConstReal( Model % Constants, "FreeConnect", Found )
IF(.NOT.Found) CALL Fatal(SolverName, "Unable to find FreeConnect")
Dw = GetConstReal( Model % Constants, "Water Depth", Found )
IF(.NOT.Found) THEN
CALL Warn(SolverName, "Unable to find Water Depth, assuming zero.")
Dw = 0.0_dp
END IF
Rho = GetConstReal( Model % Constants, "Rho", Found )
IF(.NOT.Found) CALL Fatal(SolverName, "Unable to find Rho.")
RhoWS = GetConstReal( Model % Constants, "RhoWS", Found )
IF(.NOT.Found) CALL Fatal(SolverName, "Unable to find RhoW.")
RhoWF = GetConstReal( Model % Constants, "RhoWF", Found )
IF(.NOT.Found) CALL Fatal(SolverName, "Unable to find RhoWF.")
g = GetConstReal( Model % Constants, "g", Found )
IF(.NOT.Found) CALL Fatal(SolverName, "Unable to find Gravity.")
IF(g < 0.0_dp) g = -1.0_dp * g
SeaLevel = GetConstReal( Model % Constants, "Sea Level", Found )
IF(.NOT.Found) THEN
WRITE(Message,'(A)') 'Variable Sea level not found. &
&Setting to 0.0'
CALL Info('Calving', Message, level=2)
SeaLevel = 0.0_dp
END IF
STuningParam = GetConstReal( Model % Constants, "Surface Crevasse Tuning Parameter", Found )
IF(.NOT.Found) THEN
WRITE(Message,'(A)') 'Surface Crevasse Tuning Parameter not found. &
Setting to 1.0'
CALL Info('Calving', Message, level=2)
STuningParam = 1.0_dp
END IF
BTuningParam = GetConstReal( Model % Constants, "Basal Crevasse Tuning Parameter", Found )
IF(.NOT.Found) THEN
WRITE(Message,'(A)') 'Basal Crevasse Tuning Parameter not found. &
Setting to 1.0'
CALL Info('Calving', Message, level=2)
BTuningParam = 1.0_dp
END IF
SolverParams => GetSolverParams()
DwMode = GetString (SolverParams, 'Dw Mode', Found)
IF(.NOT.Found) THEN
CALL Warn(SolverName, "Dw Mode not found, assuming off.")
DwMode = "off"
END IF
DwMode = TRIM(DwMode)
IF(DwMode /= "off") THEN
DwStart = GetConstReal (SolverParams, 'Dw Start', Found)
IF(.NOT.Found) CALL Fatal(SolverName, "Dw Start not found.")
DwStop = GetConstReal (SolverParams, 'Dw Stop', Found)
IF(.NOT.Found) CALL Fatal(SolverName, "Dw Stop not found.")
END IF
YieldStress = ListGetConstReal(SolverParams, "Yield Stress", Found)
IF(.NOT. Found) THEN
YieldStress = 0.0_dp
CALL Warn(SolverName, "No yield stress found, assuming 0.0")
ELSE
WRITE(Message,'(A,f8.2)') 'Yield Stress = ',YieldStress
CALL Info(SolverName, Message)
END IF
BasalCrevasseModel = ListGetLogical(SolverParams, "Basal Crevasse Model", Found)
IF(.NOT. Found) THEN
BasalCrevasseModel = .TRUE.
CALL Warn(SolverName,"No 'Basal Crevasse Model' found, assuming True")
END IF
IF(BasalCrevasseModel) THEN
CALL Info(SolverName,"Using Basal Crevasse Model, &
&calving occurs when surface and basal crevasses meet", Level=2)
ELSE
CALL Info(SolverName,"Using Surface Crevasse Model, &
&calving occurs when surface crevasses meet sea level",Level=2)
END IF
PlaneStressOnly = ListGetLogical(SolverParams, "Plane Stress Only", Found)
IF(.NOT. Found) PlaneStressOnly = .FALSE.
SELECT CASE(DwMode)
CASE("off")
WaterDepth = 0.0
CASE ("constant")
WaterDepth = Dw
CASE("binary")
DwSeason = .FALSE.
IF(DwStart .LT. DwStop) THEN
IF((season .GT. DwStart) .AND. (season .LT. DwStop)) DwSeason = .TRUE.
ELSE
IF((season .GT. DwStart ) .OR. (season .LT. DwStop )) DwSeason = .TRUE.
END IF
IF(DwSeason) THEN
WaterDepth = Dw
ELSE
WaterDepth = 0.0
ENDIF
CASE DEFAULT
CALL Fatal(SolverName,"Invalid Dw mode selection")
END SELECT
Length = 0.0
DO i = 1, NoNodes
IF(Permutation(i) == 0) CYCLE
NodeLength = Model % Nodes % x(i)
IF(NodeLength > Length) Length = NodeLength
END DO
PRINT *, '**** Calving Glacier Length = ',Length
CalvingCoordHolder = Length
FreeConnected = Length - FreeConnect
DO i = 1, NoNodes
xcoord = Mesh % Nodes % x(i)
ycoord = Mesh % Nodes % y(i)
IF(.NOT. OldWay) THEN
localM=0.0_dp
localM(1,1)=StressValues( StressDOFs * (StressPerm(i) - 1 ) + 1)
localM(2,2)=StressValues( StressDOFs * (StressPerm(i) - 1 ) + 2)
localM(1,2)=StressValues( StressDOFs * (StressPerm(i) - 1 ) + 4)
localM(2,1)=localM(1,2)
IF(.NOT. Cauchy) THEN
DO j=1,2
localM(j,j)=localM(j,j) - FlowSol % Values(FlowSol % Perm(i)*FlowSol % DOFs)
END DO
END IF
CALL DGEEV('N','N',2,localM,2,EigValues,EI,Dumy,1,Dumy2,1,Work,8,ierr )
IF (ierr/=0) THEN
WRITE(Message,'(A,i0)') 'Failed to compute EigenValues, error code: ',ierr
CALL FATAL(SolverName, Message)
END IF
NodeStress = MAXVAL(EigValues)
NodeWPressure = -WPressureValues(WPressurePerm(i))
IF(NodeWPressure < 0.0_dp) NodeWPressure = 0.0_dp
CalvingSurfIndex = NodeStress + (WaterDepth * RhoWF * g) - YieldStress
CalvingBasalIndex = NodeStress + NodeWPressure - YieldStress
ELSE
CALL Info('Calving', 'Calculating calving criterion the old way', level=2)
NodeDepth = DepthValues(DepthPerm(i))
NodeStress1 = Stress1Values(Stress1Perm(i))
IF(Cauchy) &
NodeStress1 = NodeStress1 + FlowSol % Values(FlowSol % Perm(i)*FlowSol % DOFs)
NodeWPressure = -WPressureValues(WPressurePerm(i))
IF(NodeWPressure < 0.0_dp) NodeWPressure = 0.0_dp
IF(PlaneStressOnly) THEN
CalvingSurfIndex = ( STuningParam * 2.0 * NodeStress1 ) - &
(NodeDepth * g * Rho) + (WaterDepth * RhoWF * g) - YieldStress
CalvingBasalIndex = ( BTuningParam * 2.0 * NodeStress1 ) - &
(NodeDepth * g * Rho) + NodeWPressure - YieldStress
ELSE
NodeStress4 = Stress4Values(Stress4Perm(i))
Te = ((NodeStress1**2) + (NodeStress4**2)) ** 0.5
sign = NodeStress1/abs(NodeStress1)
CalvingSurfIndex = ( STuningParam * 2.0 * sign * Te ) - &
(NodeDepth * g * Rho) + (WaterDepth * RhoWF * g) - YieldStress
CalvingBasalIndex = ( BTuningParam * 2.0 * sign * Te ) - &
(NodeDepth * g * Rho) + NodeWPressure - YieldStress
END IF
END IF
CSurfIndexValues(CSurfIndexPerm(i)) = CalvingSurfIndex
CBasalIndexValues(CBasalIndexPerm(i)) = CalvingBasalIndex
END DO
rt = RealTime() - rt0
IF(ParEnv % MyPE == 0) &
PRINT *, 'Calving, time taken for evaluating CIndex:', rt
rt0 = RealTime()
IF(BasalCrevasseModel) THEN
CrevasseGroupValues = 0
CIndexValues => CSurfIndexValues
CIndexPerm => CSurfIndexPerm
CALL FindCrevasseGroups(SurfaceCrevasseGroups,.TRUE., TopPerm)
CIndexValues => CBasalIndexValues
CIndexPerm => CBasalIndexPerm
CALL FindCrevasseGroups(BasalCrevasseGroups,.TRUE., BotPerm)
CALL FindCalvingBasal(SurfaceCrevasseGroups, BasalCrevasseGroups, BasalCalvingCoordinate)
ELSE
EvalResolution = 1.0_dp
NofEvalPoints = FLOOR(FreeConnect/EvalResolution)
EvalMesh => AllocateMesh()
EvalMesh % Name = "Eval_Mesh"
EvalMesh % NumberOfNodes = NofEvalPoints
EvalMesh % Nodes => EvalNodes
ALLOCATE(Field(NofEvalPoints), &
FieldPerm(NofEvalPoints), &
EvalPoints(NofEvalPoints,2), &
EvalNodes % x(NofEvalPoints), &
EvalNodes % y(NofEvalPoints), &
EvalNodes % z(NofEvalPoints))
Field = -1.0_dp
EvalPoints(:,2) = SeaLevel
DO i=1,NofEvalPoints
EvalPoints(i,1) = Length - i*EvalResolution
FieldPerm(i) = i
END DO
EvalMesh % Nodes % x = EvalPoints(:,1)
EvalMesh % Nodes % y = SeaLevel
EvalMesh % Nodes % z = 0.0_dp
CALL VariableAdd( EvalMesh % Variables, EvalMesh, Solver, "Calving Surface Index", 1, Field, FieldPerm )
CALL InterpolateMeshToMesh( Mesh, EvalMesh, Mesh % Variables, EvalMesh % Variables, .FALSE. )
CalvingOccurs = .FALSE.
Var => VariableGet( EvalMesh % Variables, 'Calving Surface Index', UnfoundFatal=.TRUE.)
DO i=1,NofEvalPoints
IF(Var % Values(Var % Perm(i)) < 0.0_dp ) CYCLE
CalvingOccurs = .TRUE.
PRINT *,'Surface Calving Event'
IF(EvalMesh % Nodes % x(i) < CalvingCoordHolder) &
CalvingCoordHolder = EvalMesh % Nodes % x(i)
END DO
END IF
IF(BasalCrevasseModel) THEN
CalvingOccurs = .FALSE.
IF(BasalCalvingOccurs) THEN
CalvingOccurs = .TRUE.
DO j = 1, NoNodes
IF(Permutation(j) == 0) CYCLE
Calving1Values(Permutation(j)) = BasalCalvingCoordinate - &
Mesh % Nodes % x(j)
IF(Calving1Values(Permutation(j)) .GE. 0.0_dp) &
Calving1Values(Permutation(j)) = 0.0_dp
END DO
PRINT *, 'Basal Calving Event at timestep ',t
PRINT *, 'Calving Coordinate :',BasalCalvingCoordinate
ELSE
Calving1Values = 0.0_dp
END IF
ELSE
IF(CalvingOccurs) THEN
DO j = 1, NoNodes
IF(Permutation(j) == 0) CYCLE
Calving1Values(Permutation(j)) = CalvingCoordHolder - &
Mesh % Nodes % x(j)
IF(Calving1Values(Permutation(j)) .GE. 0.0_dp) &
Calving1Values(Permutation(j)) = 0.0_dp
END DO
PRINT *, 'Calving Event at timestep ',t
PRINT *, 'Calving Coordinate :',CalvingCoordHolder
ELSE
Calving1Values = 0.0_dp
END IF
END IF
rt = RealTime() - rt0
IF(ParEnv % MyPE == 0) &
PRINT *, 'Calving, time taken for calving connectivity:', rt
rt0 = RealTime()
DO i=1,NoNodes
IF(BotPerm(i) > 0 .AND. FrontPerm(i) > 0) THEN
BotCornerIndex = i
END IF
END DO
DO i=Mesh % NumberOfBulkElements+1,&
Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
CurrentElement => Mesh % Elements(i)
IF(.NOT.(ANY(CurrentElement % nodeindexes == BotCornerIndex))) CYCLE
IF(ALL(FrontPerm(CurrentElement % nodeindexes) .GT. 0)) THEN
CornerElement => Mesh % Elements(i)
DO j=1,2
IF(CurrentElement % NodeIndexes(j) .NE. BotCornerIndex) THEN
BotSecondIndex = CurrentElement % NodeIndexes(j)
END IF
END DO
END IF
END DO
IF(Calving1Values(Permutation(BotCornerIndex)) .LT. 0.0_dp) THEN
CornerCalving = .TRUE.
ELSE
CornerCalving = .FALSE.
END IF
CALL GetElementNodes(CornerElementNodes, CornerElement)
CornerNormal = NormalVector(CornerElement, CornerElementNodes)
IF(Debug) PRINT *, 'Debug Calving, corner normal is: ' , &
CornerNormal(1), CornerNormal(2), CornerNormal(3)
IF(BasalFS) THEN
BedSecond = ListGetRealAtNode( Material, "Min "//BasalFSVarName, &
BotSecondIndex, UnfoundFatal=.TRUE. )
IF(Debug) PRINT *, 'Debug Calving, second node bed is: ',&
BedSecond,' and y coord is: ', Model % Nodes % y(BotSecondIndex)
PRINT *, 'Debug Calving, second node bed is: ',&
BedSecond,' and y coord is: ', Model % Nodes % y(BotSecondIndex)
BedSecondDiff = Model % Nodes % y(BotSecondIndex) - BedSecond
END IF
BedToler = 2.0_dp
normalcond = 0.95_dp
CornerBadBed = BasalFS .AND. (BedSecondDiff < BedToler)
CornerBadSlope = ABS(CornerNormal(2)) > normalcond
IF((CornerBadSlope .OR. CornerBadBed) .AND. (.NOT. CornerCalving)) THEN
IF(Debug) PRINT *,'Debug Calving, migrating mesh'
county = 1
GoToNode = BotSecondIndex
PrevNode = BotCornerIndex
KeepLooking = .TRUE.
DO WHILE (KeepLooking)
IF(Debug) PRINT *, 'Debug calving: looking!'
KeepLooking = .FALSE.
DO i=Mesh % NumberOfBulkElements+1,&
Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
CurrentElement => Mesh % Elements(i)
IF(.NOT.(ALL(FrontPerm(CurrentElement % nodeindexes) .GT. 0))) CYCLE
IF(.NOT.(ANY(CurrentElement % nodeindexes == GoToNode))) CYCLE
IF(ANY(CurrentElement % nodeindexes == PrevNode)) CYCLE
CALL GetElementNodes(CurrentElementNodes, Currentelement)
Normal = NormalVector(CurrentElement, CurrentElementNodes)
DO j=1,2
IF(CurrentElement % NodeIndexes(j) .NE. GoToNode) &
NextNode = CurrentElement % NodeIndexes(j)
END DO
IF(BasalFS) THEN
beddiff = Model % Nodes % y(NextNode) - ListGetRealAtNode( Material, &
"Min "//BasalFSVarName, NextNode, UnfoundFatal=.TRUE. )
END IF
CornerBadBed = BasalFS .AND. (beddiff < BedToler)
CornerBadSlope = ABS(CornerNormal(2)) > normalcond
IF(CornerBadBed .OR. CornerBadSlope) THEN
PrevNode = GoToNode
GoToNode = NextNode
county = county + 1
IF(Debug) PRINT *, 'Debug calving: Found another shift'
KeepLooking = .TRUE.
EXIT
END IF
END DO
END DO
RemeshOccurs = .TRUE.
ELSE
county = 0
END IF
rt = RealTime() - rt0
IF(ParEnv % MyPE == 0) &
PRINT *, 'Calving, time taken for corner problems:', rt
rt0 = RealTime()
IF(CalvingOccurs .OR. RemeshOccurs) THEN
ALLOCATE(InvFrontPerm(FrontNodes),&
CumDist(FrontNodes),&
PropCumDist(FrontNodes),&
TargetCumDist(FrontNodes),&
TargetPropDist(FrontNodes),&
TargetNodes % x(FrontNodes),&
TargetNodes % y(FrontNodes),&
TargetNodes % z(FrontNodes),&
CalvedNodes % x(FrontNodes))
DO i=1,NoNodes
IF(FrontPerm(i) .GT. 0) THEN
InvFrontPerm(FrontPerm(i)) = i
END IF
END DO
ALLOCATE(OrderPerm(FrontNodes), WorkReal(FrontNodes))
OrderPerm = [(i,i=1,FrontNodes)]
DO i=1,FrontNodes
WorkReal(i) = Mesh0 % Nodes % y(InvFrontPerm(i))
END DO
CALL SortD( FrontNodes, WorkReal, OrderPerm )
DEALLOCATE(WorkReal)
DO i=1,FrontNodes
j = InvFrontPerm(OrderPerm(i))
CalvedNodes % x(i) = Mesh % Nodes % x(j) + Calving1Values(Permutation(j))
IF(Debug) PRINT *,'Debug Calving, CalvedNodes node: ',j,' is ',&
CalvedNodes % x(i),' init coord: ',Mesh % Nodes % x(j)
END DO
TargetCumDist(1) = 0.0_dp
DO i=2,FrontNodes
dx = Mesh0 % Nodes % x(InvFrontPerm(OrderPerm(i))) - Mesh0 % Nodes % x(InvFrontPerm(OrderPerm(i-1)))
dy = Mesh0 % Nodes % y(InvFrontPerm(OrderPerm(i))) - Mesh0 % Nodes % y(InvFrontPerm(OrderPerm(i-1)))
TargetCumDist(i) = TargetCumDist(i-1) + (((dx**2) + (dy**2)) ** 0.5_dp)
END DO
TargetPropDist = TargetCumDist / MAXVAL(TargetCumDist)
CumDist(1:county+1) = 0.0_dp
DO i=county+2,FrontNodes
dx = CalvedNodes % x(i) - CalvedNodes % x(i-1)
dy = Mesh % Nodes % y(InvFrontPerm(OrderPerm(i))) - Mesh % Nodes % y(InvFrontPerm(OrderPerm(i-1)))
CumDist(i) = CumDist(i-1) + (((dx**2) + (dy**2)) ** 0.5_dp)
IF(Debug) PRINT *, 'Debug Calving: CumDist at node: ',&
InvFrontPerm(OrderPerm(i)),' is ',CumDist(i)
IF(Debug) PRINT *, 'Debug Calving: TargetDist at node: ',&
InvFrontPerm(OrderPerm(i)),' is ',TargetCumDist(i)
END DO
PropCumDist = CumDist / MAXVAL(CumDist)
TargetNodes % x(1) = CalvedNodes % x(county+1)
TargetNodes % y(1) = Mesh % Nodes % y(InvFrontPerm(OrderPerm(county+1)))
TargetNodes % x(FrontNodes) = CalvedNodes % x(FrontNodes)
TargetNodes % y(FrontNodes) = Mesh % Nodes % y(InvFrontPerm(OrderPerm(FrontNodes)))
DO i=2,FrontNodes-1
DO j=county+2,FrontNodes
IF(PropCumDist(j) .GT. TargetPropDist(i)) THEN
LocalDist = PropCumDist(j) - PropCumDist(j-1)
LocalDistNode = TargetPropDist(i) - PropCumDist(j-1)
PropDistNode = LocalDistNode / LocalDist
IF(Debug) PRINT *, 'Debug Calving: PropDist at node: ',&
InvFrontPerm(OrderPerm(i)),' is ',PropDistNode
TargetNodes % x(i) = ((1 - PropDistNode) * CalvedNodes % x(j-1)) + &
(PropDistNode * CalvedNodes % x(j))
TargetNodes % y(i) = ((1 - PropDistNode) * Mesh % Nodes % y(InvFrontPerm(OrderPerm(j-1)))) + &
(PropDistNode * Mesh % Nodes % y(InvFrontPerm(OrderPerm(j))))
EXIT
END IF
END DO
END DO
DO i=1,FrontNodes
Calving1Values(Permutation(InvFrontPerm(OrderPerm(i)))) = TargetNodes % x(i) &
- Mesh % Nodes % x(InvFrontPerm(OrderPerm(i)))
Calving2Values(Permutation(InvFrontPerm(OrderPerm(i)))) = TargetNodes % y(i) &
- Mesh % Nodes % y(InvFrontPerm(OrderPerm(i)))
IF(Debug) THEN
PRINT *,'Debug Calving: Node: ',InvFrontPerm(OrderPerm(i)),' pos x: ',&
Mesh % nodes % x(InvFrontPerm(OrderPerm(i))),&
' pos y: ',Mesh % nodes % y(InvFrontPerm(OrderPerm(i)))
PRINT *,'Moving to: x: ',TargetNodes % x(i),' y: ',TargetNodes % y(i)
PRINT *,'Displacement 1: ',Calving1Values(Permutation(InvFrontPerm(OrderPerm(i)))),&
'Displacement 2: ',Calving2Values(Permutation(InvFrontPerm(OrderPerm(i))))
END IF
END DO
END IF
CALL ListAddLogical( Model % Simulation, 'CalvingOccurs', CalvingOccurs )
CALL ListAddLogical( Model % Simulation, 'RemeshOccurs', RemeshOccurs )
rt = RealTime() - rt0
IF(ParEnv % MyPE == 0) &
PRINT *, 'Calving, time taken for calculating displacements (end):', rt
rt0 = RealTime()
CONTAINS
SUBROUTINE FindNodeNeighbours(NodeNumber)
INTEGER :: NodeNumber, i, count
NoNeighbours = Vel1Matrix % Rows((Vel1Perm(NodeNumber)*DOFs)+1) - Vel1Matrix % Rows(Vel1Perm(NodeNumber)*DOFs)
IF(MOD(NoNeighbours, DOFs).NE. 0) CALL Fatal(SolverName,"This shouldn't have happened...")
NoNeighbours = (NoNeighbours / DOFs) - 1
IF(NoNeighbours .GT. MaxNeighbours) CALL Fatal(SolverName,"Need more neighbour slots!")
IF(ALLOCATED(ThisNodeNeighbours)) DEALLOCATE(ThisNodeNeighbours)
ALLOCATE(ThisNodeNeighbours(NoNeighbours))
ThisNodeNeighbours = 0
count = 0
DO i=Vel1Matrix % Rows(Vel1Perm(NodeNumber)*DOFs),&
(Vel1Matrix % Rows((Vel1Perm(NodeNumber)*DOFs)+1)-1)
IF(MOD(i,DOFs) .NE. 0) CYCLE
IF(Vel1InvPerm(Vel1Matrix % Cols(i)) == NodeNumber) CYCLE
count = count + 1
ThisNodeNeighbours(count) = &
Vel1InvPerm(Vel1Matrix % Cols(i))
END DO
END SUBROUTINE FindNodeNeighbours
SUBROUTINE FindCrevasseGroups(CrevasseGroups, CheckValidity, MaskPerm)
TYPE(CrevasseGroups_t), INTENT(INOUT) :: CrevasseGroups
INTEGER :: MaxGroups = 100, MaxNodesPerGroup = 10000, locali
LOGICAL :: CheckValidity, FoundIt
INTEGER, POINTER, OPTIONAL, INTENT(IN) :: MaskPerm(:)
ALLOCATE( &
CrevasseGroups % NodeIndexes(MaxGroups,MaxNodesPerGroup), &
CrevasseGroups % NotEmpty(MaxGroups), &
CrevasseGroups % NoNodes(MaxGroups), &
CrevasseGroups % Valid(MaxGroups))
CrevasseGroups % NodeIndexes = 0
CrevasseGroups % NoNodes = 0
CrevasseGroups % NotEmpty = .FALSE.
CrevasseGroups % Valid = .FALSE.
CrevasseGroups % CurrentGroup = 0
DO i=1,NoNodes
IF(DistanceValues(DistancePerm(i))>FreeConnect) CYCLE
IF(CIndexValues(CIndexPerm(i))<0) CYCLE
IF(FrontPerm(i) > 0) CYCLE
FoundIt = .FALSE.
DO locali = 1, SurfaceCrevasseGroups % CurrentGroup
IF(ANY(SurfaceCrevasseGroups % NodeIndexes( &
locali,1:SurfaceCrevasseGroups % NoNodes(locali)) .EQ. i)) THEN
FoundIt = .TRUE.
EXIT
END IF
END DO
IF(ALLOCATED(BasalCrevasseGroups % NodeIndexes)) THEN
DO locali = 1, BasalCrevasseGroups % CurrentGroup
IF(ANY(BasalCrevasseGroups % NodeIndexes( &
locali,1:BasalCrevasseGroups % NoNodes(locali)) .EQ. i)) THEN
FoundIt = .TRUE.
EXIT
END IF
END DO
END IF
IF(FoundIt) CYCLE
CrevasseGroups % CurrentGroup = CrevasseGroups % CurrentGroup + 1
CrevasseGroups % NodeIndexes(CrevasseGroups % CurrentGroup,1) = i
CrevasseGroups % NotEmpty(CrevasseGroups % CurrentGroup) = .TRUE.
CrevasseGroups % NoNodes(CrevasseGroups % CurrentGroup) = &
CrevasseGroups % NoNodes(CrevasseGroups % CurrentGroup) + 1
CrevasseGroupValues(CrevasseGroupPerm(i)) = CrevasseGroups % CurrentGroup
NextSlot = 2
CALL SearchNeighbours(i, CrevasseGroups)
NextSlot = 1
END DO
IF(CheckValidity) THEN
DO i=1,CrevasseGroups % CurrentGroup
DO j=1,SIZE(CrevasseGroups % NodeIndexes,2)
IF(CrevasseGroups % NodeIndexes(i,j)==0) EXIT
IF(MaskPerm(CrevasseGroups % NodeIndexes(i,j))>0) THEN
CrevasseGroups % Valid(i) = .TRUE.
EXIT
END IF
END DO
END DO
END IF
END SUBROUTINE FindCrevasseGroups
RECURSIVE SUBROUTINE SearchNeighbours(nodenum, CrevasseGroups)
INTEGER :: nodenum, neighbourindex
INTEGER :: localj,locali
TYPE(CrevasseGroups_t) :: CrevasseGroups
LOGICAL :: FoundIt
IF(Debug) PRINT *,'Debug, nextslot, nodenum: ', nextslot, nodenum
DO localj = 1,NumNeighbours(nodenum)
neighbourindex = NodeNeighbours(nodenum,localj)
IF(DistanceValues(DistancePerm(neighbourindex))>FreeConnect) CYCLE
IF(CIndexValues(CIndexPerm(neighbourindex))<0) CYCLE
IF(FrontPerm(localj) > 0) CYCLE
FoundIt = .FALSE.
DO locali = 1, SurfaceCrevasseGroups % CurrentGroup
IF(ANY(SurfaceCrevasseGroups % NodeIndexes(&
locali,1:SurfaceCrevasseGroups % NoNodes(locali)) &
.EQ. neighbourindex)) THEN
FoundIt = .TRUE.
EXIT
END IF
END DO
IF(ALLOCATED(BasalCrevasseGroups % NodeIndexes)) THEN
DO locali = 1, BasalCrevasseGroups % CurrentGroup
IF(ANY(BasalCrevasseGroups % NodeIndexes(&
locali,1:BasalCrevasseGroups % NoNodes(locali)) &
.EQ. neighbourindex)) THEN
FoundIt = .TRUE.
EXIT
END IF
END DO
END IF
IF(FoundIt) CYCLE
CrevasseGroups % NodeIndexes(CrevasseGroups % CurrentGroup, NextSlot) = neighbourindex
CrevasseGroups % NoNodes(CrevasseGroups % CurrentGroup) = &
CrevasseGroups % NoNodes(CrevasseGroups % CurrentGroup) + 1
CrevasseGroupValues(CrevasseGroupPerm(neighbourindex)) = CrevasseGroups % CurrentGroup
NextSlot = NextSlot + 1
IF(NextSlot > SIZE(CrevasseGroups % NodeIndexes, 2)) CALL Fatal(SolverName, &
"More than 10000 nodes in a crevasse group? Almost certainly an error in setup")
CALL SearchNeighbours(neighbourindex,CrevasseGroups)
END DO
END SUBROUTINE SearchNeighbours
SUBROUTINE FindCalvingBasal(SurfaceCrevasseGroups, BasalCrevasseGroups, BasalCalvingCoordinate)
TYPE(CrevasseGroups_t), INTENT(IN) :: SurfaceCrevasseGroups, BasalCrevasseGroups
REAL (KIND=dp), INTENT(OUT) :: BasalCalvingCoordinate
INTEGER :: i,j,k,m, BasalNode, SurfaceNode
BasalCalvingOccurs = .FALSE.
BasalCalvingCoordinate = HUGE(BasalCalvingCoordinate)
DO i = 1, COUNT(SurfaceCrevasseGroups % NotEmpty)
IF(.NOT.(SurfaceCrevasseGroups % Valid(i))) CYCLE
DO j = 1, COUNT(BasalCrevasseGroups % NotEmpty)
IF(.NOT.(BasalCrevasseGroups % Valid(j))) CYCLE
DO k = 1,SIZE(SurfaceCrevasseGroups % NodeIndexes, 2)
IF(SurfaceCrevasseGroups % NodeIndexes(i,k)==0) EXIT
SurfaceNode = SurfaceCrevasseGroups % NodeIndexes(i,k)
DO m = 1,SIZE(BasalCrevasseGroups % NodeIndexes, 2)
IF(BasalCrevasseGroups % NodeIndexes(j,m)==0) EXIT
BasalNode = BasalCrevasseGroups % NodeIndexes(j,m)
IF(SurfaceNode == BasalNode) THEN
IF(Mesh % Nodes % x(SurfaceNode) .LT. BasalCalvingCoordinate) THEN
BasalCalvingCoordinate = Mesh % Nodes % x(SurfaceNode)
BasalCalvingOccurs = .TRUE.
IF(Debug) THEN
PRINT *, "Debugging Calving, Surface node x: ", &
Mesh % Nodes % x(SurfaceNode)," y: ",&
Mesh % Nodes % y(SurfaceNode)
PRINT *, "Debugging Calving, Basal node x: ", &
Mesh % Nodes % x(BasalNode)," y: ",&
Mesh % Nodes % y(BasalNode)
END IF
END IF
ELSE
IF(ANY(NodeNeighbours(BasalNode,:)==SurfaceNode)) THEN
CALL CheckCIndexOverlap(SurfaceNode, BasalNode, OverlapCalvingCoordinate, OverlapOccurs)
IF(OverlapOccurs .AND. (OverlapCalvingCoordinate .LT. BasalCalvingCoordinate)) THEN
BasalCalvingCoordinate = OverlapCalvingCoordinate
BasalCalvingOccurs = .TRUE.
END IF
END IF
END IF
END DO
END DO
END DO
END DO
END SUBROUTINE FindCalvingBasal
SUBROUTINE CheckCIndexOverlap(SurfaceNode, BasalNode, OverlapCoord, OverlapOccurs)
IMPLICIT NONE
REAL(KIND=dp) :: CSurfSurf, CSurfBasal, CBasalSurf, &
CBasalBasal, XSurf, YSurf, XBasal, YBasal, dx, dy,dxdy, dCSurf, &
dCBasal, xzerobasal, yzerobasal, xzerosurf, yzerosurf, &
dbindexdy,dsindexdy
REAL(KIND=dp), INTENT(OUT) :: OverlapCoord
INTEGER :: SurfaceNode, BasalNode
LOGICAL, INTENT(OUT) :: OverlapOccurs
OverlapOccurs = .FALSE.
CSurfSurf = CSurfIndexValues(CSurfIndexPerm(SurfaceNode))
CBasalSurf = CBasalIndexValues(CBasalIndexPerm(SurfaceNode))
CSurfBasal = CSurfIndexValues(CSurfIndexPerm(BasalNode))
CBasalBasal = CBasalIndexValues(CBasalIndexPerm(BasalNode))
XSurf = Mesh % Nodes % x(SurfaceNode)
YSurf = Mesh % Nodes % y(SurfaceNode)
XBasal = Mesh % Nodes % x(BasalNode)
YBasal = Mesh % Nodes % y(BasalNode)
IF(YSurf .LE. YBasal) THEN
IF(Debug) PRINT *, 'DEBUG Calving: Basal Node above Surf Node, calving...'
OverlapOccurs = .TRUE.
OverlapCoord = (XSurf + XBasal)/2.0
ELSE
dx = XSurf - XBasal
dy = YSurf - YBasal
dxdy = dx/dy
dCSurf = CSurfSurf - CSurfBasal
dCBasal = CBasalSurf - CBasalBasal
dsindexdy = dCSurf/dy
dbindexdy = -g*(RhoWF - Rho)
yzerobasal = YBasal - (CBasalBasal/dbindexdy)
yzerosurf = YSurf - (CSurfSurf/dsindexdy)
IF(yzerosurf .LT. yzerobasal) THEN
OverlapOccurs = .TRUE.
xzerobasal = xbasal + ((yzerobasal - YBasal)*dxdy)
xzerosurf = xsurf + ((yzerosurf - YSurf)*dxdy)
OverlapCoord = MIN(xzerosurf, xzerobasal)
OverlapCoord = MAX(OverlapCoord,MIN(XSurf, XBasal))
ELSE
OverlapOccurs = .FALSE.
ENDIF
END IF
IF(OverlapOccurs .AND. Debug) THEN
PRINT *, "Overlap occurs!, OverlapCoord: ",OverlapCoord
PRINT *, "Surf: ",SurfaceNode," x: ",Mesh % Nodes % x(SurfaceNode),&
"y: ",Mesh % Nodes % y(SurfaceNode)
PRINT *, "Base: ",BasalNode," x: ",Mesh % Nodes % x(BasalNode),&
"y: ",Mesh % Nodes % y(BasalNode)
END IF
END SUBROUTINE CheckCIndexOverlap
END SUBROUTINE Find_Calving