Path: blob/devel/elmerice/Solvers/CalvingGlacierAdvance3D.F90
3204 views
!/*****************************************************************************/1! *2! * Elmer/Ice, a glaciological add-on to Elmer3! * http://elmerice.elmerfem.org4! *5! *6! * This program is free software; you can redistribute it and/or7! * modify it under the terms of the GNU General Public License8! * as published by the Free Software Foundation; either version 29! * of the License, or (at your option) any later version.10! *11! * This program is distributed in the hope that it will be useful,12! * but WITHOUT ANY WARRANTY; without even the implied warranty of13! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14! * GNU General Public License for more details.15! *16! * You should have received a copy of the GNU General Public License17! * along with this program (in file fem/GPL-2); if not, write to the18! * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19! * Boston, MA 02110-1301, USA.20! *21! *****************************************************************************/22! ******************************************************************************23! *24! * Authors: Eef van Dongen, Joe Todd25! * Email:26! * Web: http://elmerice.elmerfem.org27! *28! *29! *****************************************************************************30!31! A routine for getting frontal advance in 3D, given velocity and melt32! nodes on the intersection of Front and LateralMargin are also allowed to advance33! In order to assure the glacier still aligns with the valley walls,34! 'rails' are prescribed. The points on the rails need to be given in two35! ASCII files (x y), one for left and one for right.36! x and y values need to be sorted, but the direction is not of importance. (?)37! NOTE: if the prescribed timestep is too large and 'rails' are very nonsmooth38! this implementation may not obey mass conservation.39SUBROUTINE GlacierAdvance3D ( Model, Solver, dt, TransientSimulation )4041USE CalvingGeometry42USE DefUtils43IMPLICIT NONE4445!-----------------------------------------------46TYPE(Model_t) :: Model47TYPE(Solver_t), TARGET :: Solver48REAL(KIND=dp) :: dt49LOGICAL :: TransientSimulation50!-----------------------------------------------51TYPE(Mesh_t), POINTER :: Mesh52TYPE(Nodes_t), TARGET :: FrontNodes53TYPE(ValueList_t), POINTER :: Params, Material54TYPE(Variable_t), POINTER :: Var, VeloVar, MeltVar, NormalVar, TangledVar, &55DistVar56! TO DO clean all unused variables57INTEGER :: i, j,jmin, k, m, n, DOFs, TotalNodes,&58FaceNodeCount, DummyInt, hits, ierr, FrontLineCount, county,&59ShiftIdx, ShiftToIdx, PivotIdx, CornerIdx, &60SecondIdx, FirstTangleIdx, LastTangleIdx, Nl, Nr, Naux, ok, Nrail,&61NNodes, NBulk, NBdry, counter, LeftBCtag, RightBCtag, FrontBCtag,&62OnRails63INTEGER, POINTER :: Perm(:), FrontPerm(:)=>NULL(), TopPerm(:)=>NULL(), &64FrontNodeNums(:)=>NULL(),LeftPerm(:)=>NULL(), RightPerm(:)=>NULL(), &65NodeIndexes(:),InflowPerm(:)=>NULL()66INTEGER, ALLOCATABLE :: FrontLocalNodeNumbers(:), &67NodeNumbers(:), UpdatedDirection(:)68REAL(KIND=dp) :: NodeVelo(3), NodeMelt(3), NodeNormal(3), RailDir(2),&69MeltRate, Displace(3), y_coord(2), epsShift, LongRangeLimit, MaxDisplacement, &70EpsTangle,thisEps,Shift, thisY,xx,yy,TempDist,MinDist,xt,yt,t, &71a1(2), a2(2), b1(2), b2(2), b3(2), intersect(2), DistRailNode, RDisplace(3),&72buffer, VeloFactor, zb73REAL(KIND=dp), POINTER :: Advance(:)74REAL(KIND=dp), ALLOCATABLE :: Rot_y_coords(:,:), Rot_z_coords(:,:), &75xL(:),yL(:),xR(:),yR(:),xRail(:),yRail(:)76LOGICAL :: Found, Debug, Parallel, Boss, ShiftLeft, LeftToRight, MovedOne, ShiftSecond, &77Protrusion, SqueezeLeft, SqueezeRight, FirstTime=.TRUE., intersect_flag, FrontMelting, &78MovePastRailNode, HitsRails, Reverse, ThisBC, MoveBulk, MoveBase,&79UnFoundFatal80LOGICAL, ALLOCATABLE :: DangerZone(:), WorkLogical(:), &81DontMove(:), FrontToRight(:), FrontToLeft(:)82CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, VeloVarName, MeltVarName, &83NormalVarName, FrontMaskName, TopMaskName, &84LeftMaskName, RightMaskName, LeftRailFName, RightRailFName,&85InflowMaskName86INTEGER,parameter :: io=2087SAVE :: FirstTime ! TO DO not actually using FirstTime here?8889!-----------------------------------------------90! Initialisation91!-----------------------------------------------9293Debug = .FALSE.94Parallel = (ParEnv % PEs > 1)95Boss = ParEnv % MyPE == 09697SolverName = "GlacierAdvance3D"98Params => Solver % Values99Mesh => Solver % Mesh100101!The main solver var contains the magnitude of front advance102Var => Solver % Variable103Advance => Var % Values104Perm => Var % Perm105DOFs = Var % DOFs106IF(Var % DOFs /= 3) CALL Fatal(SolverName, "Variable should have 3 DOFs...")107108!Get the flow solution109VeloVarName = ListGetString(Params, "Flow Solution Variable Name", Found)110IF(.NOT. Found) THEN111CALL Info(SolverName, "Flow Solution Variable Name not found, assuming 'Flow Solution'")112VeloVarName = "Flow Solution"113END IF114VeloVar => VariableGet(Mesh % Variables, VeloVarName, .TRUE., UnfoundFatal=.TRUE.)115116LeftRailFName = ListGetString(Params, "Left Rail File Name", Found)117IF(.NOT. Found) THEN118CALL Info(SolverName, "Left Rail File Name not found, assuming './LeftRail.xy'")119LeftRailFName = "LeftRail.xy"120END IF121Nl = ListGetInteger(Params, "Left Rail Number Nodes", Found)122IF(.NOT.Found) THEN123WRITE(Message,'(A,A)') 'Left Rail Number Nodes not found'124CALL FATAL(SolverName, Message)125END IF126!TO DO only do these things if firsttime=true?127OPEN(unit = io, file = TRIM(LeftRailFName), status = 'old',iostat = ok)128print *, ok129IF (ok /= 0) THEN130WRITE(message,'(A,A)') 'Unable to open file ',TRIM(LeftRailFName)131CALL FATAL(Trim(SolverName),Trim(message))132END IF133ALLOCATE(xL(Nl), yL(Nl))134135! read data136DO i = 1, Nl137READ(io,*,iostat = ok, end=200) xL(i), yL(i)138END DO139200 Naux = Nl - i140IF (Naux > 0) THEN141WRITE(message,'(I0,A,I0,A,A)') Naux,' out of ',Nl,' datasets in file ', TRIM(LeftRailFName)142CALL INFO(Trim(SolverName),Trim(message))143END IF144CLOSE(io)145RightRailFName = ListGetString(Params, "Right Rail File Name", Found)146IF(.NOT. Found) THEN147CALL Info(SolverName, "Right Rail File Name not found, assuming './RightRail.xy'")148RightRailFName = "RightRail.xy"149END IF150151Nr = ListGetInteger(Params, "Right Rail Number Nodes", Found)152IF(.NOT.Found) THEN153WRITE(Message,'(A,A)') 'Right Rail Number Nodes not found'154CALL FATAL(SolverName, Message)155END IF156!TO DO only do these things if firsttime=true?157OPEN(unit = io, file = TRIM(RightRailFName), status = 'old',iostat = ok)158159IF (ok /= 0) THEN160WRITE(message,'(A,A)') 'Unable to open file ',TRIM(RightRailFName)161CALL FATAL(Trim(SolverName),Trim(message))162END IF163ALLOCATE(xR(Nr), yR(Nr))164165! TO DO would be nice if solver warns in case there is more data in file than number Nr/Nl tells166! read data167DO i = 1, Nr168READ(io,*,iostat = ok, end=100) xR(i), yR(i)169END DO170100 Naux = Nr - i171IF (Naux > 0) THEN172WRITE(message,'(I0,A,I0,A,A)') Naux,' out of ',Nl,' datasets in file ', TRIM(RightRailFName)173CALL INFO(Trim(SolverName),Trim(message))174END IF175CLOSE(io)176177!Get melt rate178MeltVarName = ListGetString(Params, "Melt Variable Name", Found)179IF(.NOT. Found) THEN180CALL Info(SolverName, "Melt Variable Name not found, assuming no frontal melting")181FrontMelting = .FALSE.182ELSE183FrontMelting = .TRUE.184MeltVar => VariableGet(Mesh % Variables, MeltVarName, .TRUE., UnfoundFatal=.TRUE.)185END IF186187!Get front normal vector188NormalVarName = ListGetString(Params, "Normal Vector Variable Name", UnfoundFatal=.TRUE.)189NormalVar => VariableGet(Mesh % Variables, NormalVarName, .TRUE., UnfoundFatal=.TRUE.)190191MaxDisplacement = ListGetConstReal(Params, "Maximum Node Displacement", Found)192IF(.NOT.Found) THEN193CALL Info(SolverName, "'Maximum Node Displacement' not found, setting to 1.0E4.")194MaxDisplacement = 1.0E4_dp195END IF196197VeloFactor = ListGetConstReal(Params, "Lateral Margin Velocity Factor", Found)198IF(.NOT.Found) THEN199CALL Info(SolverName, "'Lateral Margin Velocity Factor' not found, setting to 1.0.")200VeloFactor = 1.0_dp201END IF202203buffer = ListGetConstReal(Params, "Rail Buffer", Found, DefValue=0.1_dp)204IF(.NOT. Found) CALL Info(SolverName, "No Rail Buffer set using default 0.1")205206MoveBulk = ListGetLogical(Params,"MoveBulk", Found, DefValue=.FALSE.)207IF(.NOT. Found) CALL Info(SolverName, "Not moving bulk as default")208209MoveBase = ListGetLogical(Params,"Account for bedrock", Found, DefValue=.FALSE.)210! still in testing211!IF(.NOT. Found) CALL Fatal(SolverName, "'Account for bedrock' not found")212213!Get the front line214FrontMaskName = "Calving Front Mask"215TopMaskName = "Top Surface Mask"216217CALL MakePermUsingMask( Model, Solver, Mesh, TopMaskName, &218.FALSE., TopPerm, dummyint)219220CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &221.FALSE., FrontPerm, FaceNodeCount)222223LeftMaskName = "Left Sidewall Mask"224RightMaskName = "Right Sidewall Mask"225226!Generate perms to quickly get nodes on each boundary227CALL MakePermUsingMask( Model, Solver, Mesh, LeftMaskName, &228.FALSE., LeftPerm, dummyint)229CALL MakePermUsingMask( Model, Solver, Mesh, RightMaskName, &230.FALSE., RightPerm, dummyint)231232InflowMaskName = "Inflow Mask"233CALL MakePermUsingMask( Model, Solver, Mesh, InflowMaskName, &234.FALSE., InflowPerm, dummyint)235236!--------------------------------------237! Action: Compute lagrangian displacement for all nodes238! This is the main function of the Solver.239! TO DO: check for 'tangled' regions, see CalvingFrontAdvance3D.F90240!--------------------------------------241242NNodes = Mesh % NumberOfNodes243NBulk = Mesh % NumberOfBulkElements244NBdry = Mesh % NumberOfBoundaryElements245246ALLOCATE(FrontToRight(NNodes), FrontToLeft(NNodes))247FrontToRight = .FALSE.; FrontToLeft = .FALSE.248249Advance = 0.0_dp250IF(MoveBulk) THEN ! for a fully Lagrangian mesh251DO i=1, Mesh % NumberOfNodes252IF(InflowPerm(i) > 0) CYCLE253IF(FrontPerm(i) == 0 .AND. LeftPerm(i) == 0 .AND. RightPerm(i) == 0) THEN254NodeVelo(1) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 1)255NodeVelo(2) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 2)256NodeVelo(3) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 3)257258Displace(1) = NodeVelo(1)259Displace(2) = NodeVelo(2)260Displace(3) = NodeVelo(3)261Displace = Displace * dt262263Advance((Perm(i)-1)*DOFs + 1) = Displace(1)264Advance((Perm(i)-1)*DOFs + 2) = Displace(2)265Advance((Perm(i)-1)*DOFs + 3) = Displace(3)266END IF267END DO268END IF269270DO i=1,Mesh % NumberOfNodes271IF(Perm(i) <= 0) CYCLE272IF(FrontPerm(i) == 0 .AND. LeftPerm(i) == 0 .AND. RightPerm(i) == 0) CYCLE273IF(InflowPerm(i) > 0) CYCLE274275IF(FrontMelting .AND. (FrontPerm(i) >0 )) THEN276IF(MeltVar % Perm(i) <= 0) &277CALL Fatal(SolverName, "Permutation error on front node!")278279280!Scalar melt value from Plume solver281MeltRate = MeltVar % Values(MeltVar % Perm(i))282283NodeNormal(1) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 1)284NodeNormal(2) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 2)285NodeNormal(3) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 3)286287NodeMelt = NodeNormal * MeltRate288ELSE289NodeMelt = 0.0_dp290END IF291292!Compute front normal component of velocity293NodeVelo(1) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 1)294NodeVelo(2) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 2)295NodeVelo(3) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 3)296297IF(FrontPerm(i) > 0) THEN298IF(LeftPerm(i) > 0 .OR. RightPerm(i) > 0) THEN299NodeVelo = NodeVelo * VeloFactor300END IF301END IF302303Displace = 0.0304IF ( FrontPerm(i) > 0 ) THEN305Displace(1) = NodeVelo(1) - NodeMelt(1)306Displace(2) = NodeVelo(2) - NodeMelt(2)307Displace(3) = NodeVelo(3) - NodeMelt(3)308Displace = Displace * dt309END IF310311OnRails = 0312! if not lateral node need to check we don't cross rails if fjord narrowing313IF(LeftPerm(i) == 0 .AND. RightPerm(i) == 0) THEN314a1(1) = Solver % Mesh % Nodes % x(i)315a1(2) = Solver % Mesh % Nodes % y(i)316a2(1) = a1(1) + Displace(1)317a2(2) = a1(2) + Displace(2)318319DO j=1, Nl-1320b1(1) = xL(j); b1(2) = yL(j)321b2(1) = xL(j+1); b2(2) = yL(j+1)322IF(j < NL - 1) THEN323b3(1) = xL(j+2); b3(2) = yL(j+2)324END IF325tempdist = PointLineSegmDist2D(b1, b2, a1)326IF(tempdist < buffer + AEPS) THEN327FrontToLeft(i) = .TRUE.328OnRails = 1 ! on rails so treat as edge329EXIT330END IF331332CALL LineSegmentsIntersect(a1, a2, b1, b2, intersect, HitsRails)333334IF(HitsRails) THEN335FrontToLeft(i) = .TRUE.336! check direction337Reverse = .FALSE.338IF (PointDist2D(intersect,b2) > PointDist2D(a1, b2)) Reverse = .TRUE.339340IF(Reverse) THEN341b1(1) = xL(j+1); b1(2) = yL(j+1)342b2(1) = xL(j); b2(2) = yL(j)343IF(j > 1) THEN344b3(1) = xL(j-1); b3(2) = yL(j-1)345END IF346END IF347EXIT348END IF349END DO350351IF(.NOT. HitsRails) THEN ! didn't hit left rail352DO j=1, Nr-1353b1(1) = xR(j); b1(2) = yR(j)354b2(1) = xR(j+1); b2(2) = yR(j+1)355IF(j < Nr - 1) THEN356b3(1) = xR(j+2); b3(2) = yR(j+2)357END IF358tempdist = PointLineSegmDist2D(b1, b2, a1)359IF(tempdist < buffer + AEPS) THEN360FrontToRight(i) = .TRUE.361OnRails = 2! on rails so treat as edge362EXIT363END IF364365CALL LineSegmentsIntersect(a1, a2, b1, b2, intersect, HitsRails)366367IF(HitsRails) THEN368FrontToRight(i) = .TRUE.369! check direction370Reverse = .FALSE.371IF (PointDist2D(intersect,b2) > PointDist2D(a1, b2)) Reverse = .TRUE.372373IF(Reverse) THEN374b1(1) = xR(j+1); b1(2) = yR(j+1)375b2(1) = xR(j); b2(2) = yR(j)376IF(j > 1) THEN377b3(1) = xR(j-1); b3(2) = yR(j-1)378END IF379END IF380EXIT381END IF382END DO383END IF384385IF(HitsRails) THEN ! hit a rail b1, b2, and b3 should be correct from above386! limit to rail and then move along387Displace(1:2) = intersect-a1388389!remaining displacement390RDisplace = 0.0_dp391RDisplace(1) = (NodeVelo(1) - NodeMelt(1)) * dt - Displace(1)392RDisplace(2) = (NodeVelo(2) - NodeMelt(2)) * dt - Displace(2)393394DistRailNode = PointDist2D(intersect, b2)395TempDist = ( RDisplace(1)**2 + RDisplace(2)**2 ) ** 0.5396397!check if move past rail node398MovePastRailNode = .FALSE.399IF(TempDist > DistRailNode) MovePastRailNode=.TRUE.400401!project along rail402IF(.NOT. MovePastRailNode) THEN403404RailDir = b1 - b2405Displace(1:2) = Displace(1:2) + DOT_PRODUCT(RDisplace(1:2),RailDir) * &406RailDir / DOT_PRODUCT(RailDir,RailDir)407408ELSE409410IF((Reverse .AND. j == 1) .AND. (.NOT. Reverse .AND. j == Nr - 1)) &411CALL FATAL(SolverName, 'Moving past the end of the rails')412413RailDir = b1 - b2414Displace(1:2) = Displace(1:2) + b2 - a1 ! get to new rail node415!TempDist is total distance it would have travelled only along its original segment416TempDist=DOT_PRODUCT(RDisplace(1:2),RailDir) * &417(RailDir(1)**2+RailDir(2)**2)**0.5 * dt / DOT_PRODUCT(RailDir,RailDir)418TempDist=ABS(TempDist) ! distance no sign419420IF(TempDist < DistRailNode) THEN421CALL WARN(SolverName, 'Node outside rails and moving past rail node')422TempDist = DistRailNode423END IF424425t=(TempDist - DistRailNode)/TempDist426427! new rail direction428RailDir = b2 - b3429! add proportion left to travel along new direction430Displace(1:2) = Displace(1:2)+DOT_PRODUCT(RDisplace(1:2),RailDir) * &431RailDir * dt * t / DOT_PRODUCT(RailDir,RailDir)432END IF433END IF434END IF435436! NOTE: Displace overwritten on corner of left-front and right-front437! melt not taken into account on those corner nodes438IF ((LeftPerm(i)>0) .OR. (RightPerm(i)>0) .OR. (OnRails > 0) ) THEN439! Strategy to project displace from x to x+v*dt along rail direction:440! - find closest rail node, then find cosest rail segment.441! - three cases to find which rail segment should be used:442! 1) x is rail node, then just find out which segment closest to x+dt*v443! 2) both x and x+dt*v are on one rail segment444! 3) x is on one segment and x+dt*v on another445! only do x,y direction; vertical update is handled by freesurf.446! NOTE mass is not strictly conserved but for small timesteps and447! a thin lateral boundary artificial mass change should be insignificant.448xx = Solver % Mesh % Nodes % x(i)449yy = Solver % Mesh % Nodes % y(i)450NodeVelo(1:2) = NodeVelo(1:2) - NodeMelt(1:2)451xt=xx+(NodeVelo(1))*dt452yt=yy+(NodeVelo(2))*dt453IF (LeftPerm(i)>0 .OR. OnRails == 1) THEN454Nrail= Nl455ALLOCATE(xRail(Nrail), yRail(Nrail))456xRail = xL457yRail = yL458ELSE459Nrail= Nr460ALLOCATE(xRail(Nrail), yRail(Nrail))461xRail = xR462yRail = yR ! TO DO use pointers instead?463END IF464MinDist=(xRail(1)-xRail(Nrail))**2.+(yRail(1)-yRail(Nrail))**2.465! MinDist is actually maximum distance, needed for finding closest rail node466DO j=1,Nrail ! Find closest point on rail467TempDist=(xRail(j)-xx)**2.+(yRail(j)-yy)**2.468IF(TempDist < MinDist) THEN469MinDist=TempDist470jmin=j471END IF472END DO473IF(jmin+1>Nrail) PRINT *, 'jmin=',jmin,'ERROR: advancing/retreating beyond rail!'474!NOTE, this assumes rails are starting at back and going towards front, should check k > 0 as well?475IF (MinDist < AEPS) THEN ! min distance very close to 0476! case 1) mesh node is a rail point477! this likely happens at t=0.478MovePastRailNode=.FALSE. !if both at a rail node and passing next rail node, rail resolution is smaller than displacement per timestep479! we assume that's never the case. TO DO include assert480! check whether x+v*dt is closest to segment jmin+1 or jmin-1481IF(PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &482(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &483> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &484(/xRail(jmin-1),yRail(jmin-1)/),(/xt,yt/))) THEN485k=jmin-1 ! x+v*dt is on jmin-1 -- jmin486ELSE487k=jmin+1488END IF489PRINT *, 'NOTE! mesh node on a rail node!'490ELSE ! x is not a rail node, check whether x is closest to jmin+1 or jmin-1491IF(jmin==1) THEN492IF(PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &493(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &494> PointLineSegmDist2D((/xRail(jmin+1),yRail(jmin+1)/), &495(/xRail(jmin+2),yRail(jmin+2)/),(/xt,yt/))) THEN496! x+v*dt also closest to jmin--jmin-1497MovePastRailNode=.TRUE. ! case 2) x+dt*v and x are on same segment498k=jmin+1499ELSE500! case 3) advancing past rail segment501MovePastRailNode=.FALSE.502k=jmin+1 ! x is moving from jmin-1--jmin to jmin--jmin+1503END IF504ELSE505IF(PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &506(/xRail(jmin+1),yRail(jmin+1)/),(/xx,yy/)) &507> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &508(/xRail(jmin-1),yRail(jmin-1)/),(/xx,yy/))) THEN509! x closest to jmin-1 -- jmin segment510IF (PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &511(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &512> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &513(/xRail(jmin-1),yRail(jmin-1)/),(/xt,yt/))) THEN514! x+v*dt also closest to jmin--jmin-1515MovePastRailNode=.FALSE. ! case 2) x+dt*v and x are on same segment516k=jmin-1 ! x and x+v*dt are closest to jmin>jmin-1 segment517ELSE518! case 3) advancing past rail segment519MovePastRailNode=.TRUE.520k=jmin+1 ! x is moving from jmin-1--jmin to jmin--jmin+1521END IF522ELSE ! x closest to jmin -- jmin+1 segment, but closer to jmin than jmin+1523! assuming not moving past jmin+1 (see above assumption on time step and rail resolution)524IF (PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &525(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &526> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &527(/xRail(jmin-1),yRail(jmin-1)/),(/xt,yt/))) THEN528! Case 3) x advancing past rail segment529MovePastRailNode=.TRUE.530k=jmin-1 ! x is moving from jmin+1>jmin to jmin>jmin-1531ELSE532! Case 2) x+v*dt and x are on same segment jmin>jmin+1533MovePastRailNode=.FALSE.534k=jmin+1535END IF536END IF537END IF538END IF539IF(MovePastRailNode) THEN540! check not moving past last node541IF((k > jmin .AND. jmin == Nrail) .OR. (k < jmin .AND. jmin == 1)) &542CALL FATAL(SolverName, 'Moving past the end of the rails')543! k is defined such that the node should after displacement lay on jmin -- k segment544! nodes first move along the current rail segment to the nearest rail node jmin.545! whatever magnitude of the horizontal part of v*dt is left546! will be the distance the node travels on the new segment.547RailDir=(/xRail(jmin),yRail(jmin)/)-(/xx,yy/) ! direction of current rail548Displace(1:2)=(/xRail(jmin),yRail(jmin)/)-(/xx,yy/) ! get to new rail node549!TempDist is total distance it would have travelled only along its original segment550TempDist=DOT_PRODUCT(NodeVelo(1:2),RailDir) * &551(RailDir(1)**2+RailDir(2)**2)**0.5 * dt / DOT_PRODUCT(RailDir,RailDir)552TempDist=ABS(TempDist) ! distance no sign553! t is the proportion left to travel along new segment554DistRailNode = ((xx-xRail(jmin))**2.+(yy-yRail(jmin))**2.)**0.5555IF(TempDist < DistRailNode) THEN556CALL WARN(SolverName, 'Node outside rails and moving past rail node')557TempDist = DistRailNode558END IF559560t=(TempDist - DistRailNode)/TempDist561562! new rail direction563RailDir=(/xRail(jmin),yRail(jmin)/)-(/xRail(k),yRail(k)/)564! add proportion left to travel along new direction565Displace(1:2) = Displace(1:2)+DOT_PRODUCT(NodeVelo(1:2),RailDir) * &566RailDir * dt * t / DOT_PRODUCT(RailDir,RailDir)567ELSE ! not moving past node, just project onto current rail568RailDir=(/xRail(jmin),yRail(jmin)/)-(/xRail(k),yRail(k)/)569Displace(1:2) = DOT_PRODUCT(NodeVelo(1:2),RailDir) * &570RailDir / DOT_PRODUCT(RailDir,RailDir)571Displace(1:2) = Displace(1:2) * dt572END IF573! TO DO write warning if distance point on margin to rail segment too large?574! TO DO also write warning if glacier advances out of range of rails?575! TO DO ASSERT that ||NewDisplace|| <= ||V||*dt576DEALLOCATE(xRail,yRail)577END IF578579580IF(MAXVAL(Displace) > MaxDisplacement) THEN581WRITE(Message,'(A,i0,A)') "Maximum allowable front displacement exceeded for node ",i,". Limiting..."582CALL Warn(SolverName, Message)583Displace = Displace * (MaxDisplacement/MAXVAL(Displace))584END IF585586Advance((Perm(i)-1)*DOFs + 1) = Displace(1)587Advance((Perm(i)-1)*DOFs + 2) = Displace(2)588Advance((Perm(i)-1)*DOFs + 3) = Displace(3)589590END DO591592!do we need to check base base of new advance location?593IF(MoveBase) THEN594595i = ListGetInteger( CurrentModel % Bodies(Mesh % Elements(1) % BodyId) % Values, &596'Material')597Material => CurrentModel % Materials(i) % Values !TODO, this is not generalised598599DO i=1, Mesh % NumberOfNodes600IF(Perm(i) == 0) CYCLE601IF(FrontPerm(i) == 0) CYCLE602Mesh % Nodes % x(i) = Mesh % Nodes % x(i) + Advance((Perm(i)-1)*DOFs + 1)603Mesh % Nodes % y(i) = Mesh % Nodes % y(i) + Advance((Perm(i)-1)*DOFs + 2)604Mesh % Nodes % z(i) = Mesh % Nodes % z(i) + Advance((Perm(i)-1)*DOFs + 3)605zb = ListGetRealAtNode(Material, "Min Zs Bottom",i,UnfoundFatal=.TRUE.)606607Mesh % Nodes % x(i) = Mesh % Nodes % x(i) - Advance((Perm(i)-1)*DOFs + 1)608Mesh % Nodes % y(i) = Mesh % Nodes % y(i) - Advance((Perm(i)-1)*DOFs + 2)609Mesh % Nodes % z(i) = Mesh % Nodes % z(i) - Advance((Perm(i)-1)*DOFs + 3)610611IF(Mesh % Nodes % z(i) + Advance((Perm(i)-1)*DOFs + 3) < zb) THEN612Advance((Perm(i)-1)*DOFs + 3) = zb - Mesh % Nodes % z(i)613IF(Mesh % Nodes % z(i) < zb) THEN614Advance((Perm(i)-1)*DOFs + 3) = 0.0_dp615END IF616END IF617END DO618END IF619620621! find lateral boundary tags622DO i=1,Model % NumberOfBCs623ThisBC = ListGetLogical(Model % BCs(i) % Values,LeftMaskName,Found)624IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE625LeftBCtag = Model % BCs(i) % Tag626EXIT627END DO628DO i=1,Model % NumberOfBCs629ThisBC = ListGetLogical(Model % BCs(i) % Values,RightMaskName,Found)630IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE631RightBCtag = Model % BCs(i) % Tag632EXIT633END DO634DO i=1,Model % NumberOfBCs635ThisBC = ListGetLogical(Model % BCs(i) % Values,FrontMaskName,Found)636IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE637FrontBCtag = Model % BCs(i) % Tag638EXIT639END DO640641!reassign any elements that now only contain nodes on lateral margins642DO i=NBulk+1, NBulk+NBdry643IF(Mesh % Elements(i) % BoundaryInfo % constraint /= FrontBCtag) CYCLE644NodeIndexes => Mesh % Elements(i) % NodeIndexes645n = Mesh % Elements(i) % TYPE % NumberOfNodes646counter = 0647DO j=1,n648IF(RightPerm(NodeIndexes(j)) > 0) CYCLE649IF(FrontToRight(NodeIndexes(j))) CYCLE650counter = counter + 1651END DO652653IF(counter == 0) Mesh % Elements(i) % BoundaryInfo % constraint = RightBCtag654END DO655656!reassign any elements that now only contain nodes on lateral margins657DO i=NBulk+1, NBulk+NBdry658IF(Mesh % Elements(i) % BoundaryInfo % constraint /= FrontBCtag) CYCLE659NodeIndexes => Mesh % Elements(i) % NodeIndexes660n = Mesh % Elements(i) % TYPE % NumberOfNodes661counter = 0662DO j=1,n663IF(LeftPerm(NodeIndexes(j)) > 0) CYCLE664IF(FrontToLeft(NodeIndexes(j))) CYCLE665counter = counter + 1666END DO667668IF(counter == 0) Mesh % Elements(i) % BoundaryInfo % constraint = LeftBCtag669END DO670671!---------------------------------------672!Done, just deallocations673674FirstTime = .FALSE.675676DEALLOCATE(FrontPerm, TopPerm, LeftPerm, RightPerm, InflowPerm)677678END SUBROUTINE GlacierAdvance3D679680681