Path: blob/devel/elmerice/UserFunctions/USF_GlacierMeshMetric.F90
3196 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: Joe Todd25! * Email:26! * Web: http://elmerice.elmerfem.org27! *28! * Original Date: 18/10/1929! *30! *****************************************************************************31!> Computes anisotropic target element size based on distance from calving front32SUBROUTINE GlacierMeshMetricAniso(Model, nodenumber, y, TargetLength)3334USE DefUtils3536IMPLICIT NONE3738TYPE(Model_t) :: Model39INTEGER :: nodenumber40REAL(KIND=dp) :: y, TargetLength(:)41!----------------------------------------------------------42TYPE(Mesh_t), POINTER :: Mesh43TYPE(ValueList_t), POINTER :: Material44TYPE(Variable_t), POINTER :: TimeVar45TYPE(Solver_t), POINTER :: Solver46REAL(KIND=dp) :: xx,yy,zz,t,told, this_dist, MinDist2, Dist,&47lc_mindist, lc_maxdist, lc_min, lc_max,s,dx,dz,NodeDepth,NodeElev48REAL(KIND=dp), DIMENSION(3) :: Point49INTEGER, POINTER :: FrontPerm(:),BottomPerm(:),SurfacePerm(:),Nodeindexes(:)50INTEGER :: i,NNodes, NFront, layers, nbottom, n, BCTag, nsurface51LOGICAL :: NewTime,FirstTime=.TRUE., Debug, Found, ExtrudeLayers, ThisBC52LOGICAL, ALLOCATABLE :: BottomElemMask(:), SurfElemMask(:)53CHARACTER(LEN=MAX_NAME_LEN) :: FrontMaskName,BottomMaskName,SurfaceMaskName5455SAVE :: FirstTime, told, FrontPerm, Mesh, NNodes, nfront, lc_maxdist, lc_mindist,&56lc_max, lc_min, dz, newtime, ExtrudeLayers, layers, BottomElemMask, BottomPerm,&57SurfElemMask, SurfacePerm5859Debug = .FALSE.60Timevar => VariableGet( Model % Variables,'Time')61t = TimeVar % Values(1)62Solver => Model % Solver63FrontMaskName="Calving Front Mask"64BottomMaskName="Bottom Surface Mask"65SurfaceMaskName='Top Surface Mask'6667IF (FirstTime) THEN68FirstTime = .FALSE.69NewTime = .TRUE.70told = t7172Mesh => Model % Mesh73Material => GetMaterial(Mesh % Elements(1)) !TODO, this is not generalised7475lc_maxdist = ListGetConstReal(Material, "GlacierMeshMetric Max Distance", DefValue=2000.0_dp)76lc_mindist = ListGetConstReal(Material, "GlacierMeshMetric Min Distance", DefValue=200.0_dp)77lc_max = ListGetConstReal(Material, "GlacierMeshMetric Max LC", DefValue=500.0_dp)78lc_min = ListGetConstReal(Material, "GlacierMeshMetric Min LC", DefValue=75.0_dp)79ExtrudeLayers = ListGetLogical(Material,"GlacierMeshMetric Vertical From Layers", DefValue=.FALSE.)80IF(ExtrudeLayers) THEN81layers = ListGetInteger(Material, "GlacierMeshMetric Vertical Layers", Found=Found)82IF(.NOT. Found) CALL FATAL('GlacierMeshMetric', 'Vertical requested by layers but number of layers not given')83ELSE84dz = ListGetConstReal(Material, "GlacierMeshMetric Vertical LC", DefValue=50.0_dp)85END IF86END IF8788IF(t > told) NewTime = .TRUE. !TODO - replace this with Samuel's mesh counter logic89IF(NewTime) THEN90told = t91NewTime = .FALSE.9293Mesh => Model % Mesh94NNodes = Mesh % NumberOfNodes9596!mask is the most computationally expense element of this routine97IF(ASSOCIATED(FrontPerm)) DEALLOCATE(FrontPerm)98CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &99.FALSE., FrontPerm, nfront, ParallelComm = .FALSE.)100101IF(ExtrudeLayers) THEN102103! create top and bottom perms104IF(ASSOCIATED(BottomPerm)) DEALLOCATE(BottomPerm)105CALL MakePermUsingMask( Model, Solver, Mesh, BottomMaskName, &106.FALSE., BottomPerm, nbottom, ParallelComm = .FALSE.)107IF(ASSOCIATED(SurfacePerm)) DEALLOCATE(SurfacePerm)108CALL MakePermUsingMask( Model, Solver, Mesh, SurfaceMaskName, &109.FALSE., SurfacePerm, nsurface, ParallelComm = .FALSE.)110111!create mask of elems as with an unstructred mesh all nodes can be in mask but not elem112DO i=1,Model % NumberOfBCs113ThisBC = ListGetLogical(Model % BCs(i) % Values, BottomMaskName, Found)114IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE115BCtag = Model % BCs(i) % Tag116EXIT117END DO118119IF(ALLOCATED(BottomElemMask)) DEALLOCATE(BottomElemMask)120ALLOCATE(BottomElemMask(Mesh % NumberOfBulkElements &121+ Mesh % NumberOfBoundaryElements))122BottomElemMask = .TRUE.123DO i=Mesh % NumberOfBulkElements+1, &124Mesh % NumberOfBulkElements+Mesh % NumberOfBoundaryElements125IF(Mesh % Elements(i) % BoundaryInfo % constraint == BCTag) &126BottomElemMask(i) = .FALSE.127END DO128129!create mask of elems as with an unstructred mesh all nodes can be in mask but not elem130DO i=1,Model % NumberOfBCs131ThisBC = ListGetLogical(Model % BCs(i) % Values, SurfaceMaskName, Found)132IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE133BCtag = Model % BCs(i) % Tag134EXIT135END DO136137IF(ALLOCATED(SurfElemMask)) DEALLOCATE(SurfElemMask)138ALLOCATE(SurfElemMask(Mesh % NumberOfBulkElements &139+ Mesh % NumberOfBoundaryElements))140SurfElemMask = .TRUE.141DO i=Mesh % NumberOfBulkElements+1, &142Mesh % NumberOfBulkElements+Mesh % NumberOfBoundaryElements143IF(Mesh % Elements(i) % BoundaryInfo % constraint == BCTag) &144SurfElemMask(i) = .FALSE.145END DO146END IF147148END IF149150xx = Mesh % Nodes % x(nodenumber)151yy = Mesh % Nodes % y(nodenumber)152zz = Mesh % Nodes % z(nodenumber)153154MinDist2 = HUGE(MinDist2)155DO i=1,NNodes156IF(FrontPerm(i) == 0) CYCLE157!Note - sqrt is an expensive FLOP so only do it once...158this_dist = ((xx - Mesh % Nodes % x(i))**2.0) + &159((yy - Mesh % Nodes % y(i))**2.0) + &160((zz - Mesh % Nodes % z(i))**2.0)161MinDist2 = MIN(this_dist, MinDist2)162END DO163Dist = SQRT(MinDist2)164165!Apply caps to this distance:166Dist = MAX(Dist,lc_mindist)167Dist = MIN(Dist,lc_maxdist)168169s = (Dist - lc_mindist) / (lc_maxdist - lc_mindist)170dx = s*lc_max + (1-s)*lc_min171172TargetLength(1) = dx173TargetLength(2) = dx174175IF(ExtrudeLayers) THEN176177Point(1) = xx178Point(2) = yy179Point(3) = 0.0_dp180181NodeDepth = GetZFromMask(Mesh, Point, BottomPerm, BottomElemMask)182NodeElev = GetZFromMask(Mesh, Point, SurfacePerm, SurfElemMask)183184dz = (NodeElev-NodeDepth)/(layers-1)185186TargetLength(3) = dz187ELSE188TargetLength(3) = dz189END IF190191IF(Debug) PRINT *,'Node ',nodenumber,'TargetLength: ',TargetLength,' dist: ',Dist,' s: ',s192193CONTAINS194195FUNCTION GetZFromMask(Mesh, Point, NodePerm, ElemMask) RESULT(NodeDepth)196197TYPE(Mesh_t), POINTER :: Mesh198REAL(KIND=dp), DIMENSION(3) :: Point199INTEGER, POINTER :: NodePerm(:)200LOGICAL, ALLOCATABLE :: ElemMask(:)201REAL(KIND=dp) :: NodeDepth202!-----------------------------------------203TYPE(Element_t),POINTER :: Element204TYPE(Nodes_t) :: ElementNodes205REAL(KIND=dp), POINTER :: ElementValues(:)206REAL(KIND=dp), DIMENSION(3) :: NodeCoord, LocalCoordinates207REAL(KIND=dp), DIMENSION(2) :: Distances, Depths, Weights208REAL(KIND=dp) :: eps_global_limit, eps_local_limit,&209eps_global, eps_local, eps_numeric210REAL(KIND=dp) :: MinDist,MinDist2,dist211INTEGER :: i,n,NodeIndx,NodeIndx2212LOGICAL :: Found213214eps_global = 2.0e-10_dp215eps_local = 1.0e-10_dp216eps_numeric = 1.0e-10_dp217eps_global_limit = 1.0E-2_dp218eps_local_limit = 1.0E-2_dp219220n = Mesh % MaxElementNodes221ALLOCATE( ElementNodes % x(n), ElementNodes % y(n), &222ElementNodes % z(n), ElementValues(n) )223224DO WHILE(.TRUE.)225DO i=1, Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements226227IF(ElemMask(i)) CYCLE228229Element => Mesh % Elements(i)230n = Element % TYPE % NumberOfNodes231NodeIndexes => Element % NodeIndexes232233ElementNodes % x(1:n) = Mesh % Nodes % x(NodeIndexes)234ElementNodes % y(1:n) = Mesh % Nodes % y(NodeIndexes)235ElementNodes % z = 0.0_dp236Found = PointInElement( Element, ElementNodes, &237Point, LocalCoordinates, eps_global, eps_local, eps_numeric)238IF( Found ) EXIT239END DO240IF( Found ) EXIT241242eps_global = eps_global * 10.0_dp243eps_local = eps_local * 10.0_dp244IF(eps_global > eps_global_limit) EXIT245IF(eps_local > eps_local_limit) EXIT246END DO247248IF(.NOT. Found) THEN249250MinDist = HUGE(1.0_dp); MinDist2 = HUGE(1.0_dp)251DO i=1,NNodes252253IF(NodePerm(i) == 0) CYCLE254255NodeCoord(1) = Mesh % Nodes % x(i)256NodeCoord(2) = Mesh % Nodes % y(i)257NodeCoord(3) = 0.0_dp258259Dist = SUM( ( Point(:2) - NodeCoord(:2) )**2 )260IF( Dist < MinDist ) THEN261IF(MinDist < MinDist2) THEN262MinDist2 = MinDist263NodeIndx2 = NodeIndx264END IF265MinDist = Dist266NodeIndx = i267ELSE IF( Dist < MinDist2) THEN268MinDist2 = Dist269NodeIndx2 = i270END IF271END DO272273Distances(1) = MinDist ** 0.5274Distances(2) = MinDist2 ** 0.5275276Weights(1) = Distances(1) ** (-1.0_dp)277Weights(2) = Distances(2) ** (-1.0_dp)278279Depths(1) = Mesh % Nodes % z(NodeIndx) * Weights(1)280Depths(2) = Mesh % Nodes % z(NodeIndx2) * Weights(2)281282NodeDepth = SUM(Depths)/SUM(Weights)283ELSE284ElementValues(1:n) = Mesh % Nodes % z(NodeIndexes)285286NodeDepth = InterpolateInElement( &287Element, ElementValues, LocalCoordinates(1), &288LocalCoordinates(2), LocalCoordinates(3) )289END IF290END FUNCTION GetZFromMask291292END SUBROUTINE GlacierMeshMetricAniso293294295