1!/*****************************************************************************/ 2! * 3! * Elmer/Ice, a glaciological add-on to Elmer 4! * http://elmerice.elmerfem.org 5! * 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! * Authors: Joe Todd 26! * Email: 27! * Web: http://elmerice.elmerfem.org 28! * 29! * 30! ***************************************************************************** 31 32!A routine for getting frontal advance in 3D, given velocity and melt 33 34 SUBROUTINE FrontAdvance3D ( Model, Solver, dt, TransientSimulation ) 35 36 USE CalvingGeometry 37 USE DefUtils 38 IMPLICIT NONE 39 40!----------------------------------------------- 41 TYPE(Model_t) :: Model 42 TYPE(Solver_t), TARGET :: Solver 43 REAL(KIND=dp) :: dt 44 LOGICAL :: TransientSimulation 45!----------------------------------------------- 46 TYPE(Mesh_t), POINTER :: Mesh 47 TYPE(Nodes_t), TARGET :: FrontNodes, ColumnNodes 48 TYPE(ValueList_t), POINTER :: Params 49 TYPE(Variable_t), POINTER :: Var, VeloVar, MeltVar, NormalVar, TangledVar 50 INTEGER :: i, j, k, m, n, DOFs, TotalNodes, NodesPerLevel, ExtrudedLevels,& 51 FaceNodeCount, DummyInt, col, hits, ierr, FrontLineCount, county,& 52 ShiftIdx, ShiftToIdx, NoTangledGroups, PivotIdx, CornerIdx, & 53 SecondIdx, FirstTangleIdx, LastTangleIdx 54 INTEGER, POINTER :: Perm(:), FrontPerm(:)=>NULL(), TopPerm(:)=>NULL(), & 55 FrontNodeNums(:)=>NULL() 56 INTEGER, ALLOCATABLE :: FNColumns(:), FrontColumnList(:), FrontLocalNodeNumbers(:), & 57 NodeNumbers(:), TangledGroup(:), TangledPivotIdx(:), UpdatedDirection(:) 58 REAL(KIND=dp) :: FrontOrientation(3),RotationMatrix(3,3),& 59 NodeVelo(3), NodeMelt(3), NodeNormal(3), ColumnNormal(3), CornerDirection(2),& 60 MeltRate, Displace(3), NodeHolder(3), DangerGrad, ShiftTo, direction, & 61 ShiftDist, y_coord(2), epsShift, ShiftToY, LongRangeLimit, MaxDisplacement, LimitZ, & 62 p1(2),p2(2),q1(2),q2(2),intersect(2), LeftY, RightY, EpsTangle,thisEps,Shift, thisY 63 REAL(KIND=dp), POINTER :: Advance(:) 64 REAL(KIND=dp), ALLOCATABLE :: Rot_y_coords(:,:), Rot_z_coords(:,:), ColumnNormals(:,:), & 65 TangledShiftTo(:) 66 LOGICAL :: Found, Debug, Parallel, Boss, ShiftLeft, LeftToRight, MovedOne, ShiftSecond, & 67 Protrusion, SqueezeLeft, SqueezeRight, FirstTime=.TRUE., intersect_flag, FrontMelting, & 68 IgnoreVelo 69 LOGICAL, ALLOCATABLE :: DangerZone(:), WorkLogical(:), UpdatedColumn(:),& 70 Tangled(:), DontMove(:) 71 CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, VeloVarName, MeltVarName, & 72 NormalVarName, FrontMaskName, TopMaskName, TangledVarName 73 74 SAVE :: FirstTime 75 76 !----------------------------------------------- 77 ! Initialisation 78 !----------------------------------------------- 79 80 Debug = .FALSE. 81 Parallel = (ParEnv % PEs > 1) 82 Boss = ParEnv % MyPE == 0 83 84 SolverName = "FrontAdvance3D" 85 Params => Solver % Values 86 Mesh => Solver % Mesh 87 88 !The main solver var contains the magnitude of front advance 89 Var => Solver % Variable 90 Advance => Var % Values 91 Perm => Var % Perm 92 DOFs = Var % DOFs 93 IF(Var % DOFs /= 3) CALL Fatal(SolverName, "Variable should have 3 DOFs...") 94 95 IgnoreVelo = ListGetLogical(Params, "Ignore Velocity", Found) 96 IF(.NOT. Found) THEN 97 IgnoreVelo = .FALSE. 98 ELSE 99 CALL Info(SolverName, "Ignoring velocity (melt undercutting only)") 100 END IF 101 102 IF(.NOT. IgnoreVelo) THEN 103 !Get the flow solution 104 VeloVarName = ListGetString(Params, "Flow Solution Variable Name", Found) 105 IF(.NOT. Found) THEN 106 CALL Info(SolverName, "Flow Solution Variable Name not found, assuming 'Flow Solution'") 107 VeloVarName = "Flow Solution" 108 END IF 109 VeloVar => VariableGet(Mesh % Variables, VeloVarName, .TRUE., UnfoundFatal=.TRUE.) 110 END IF 111 112 !Get melt rate 113 MeltVarName = ListGetString(Params, "Melt Variable Name", Found) 114 IF(.NOT. Found) THEN 115 CALL Info(SolverName, "Melt Variable Name not found, assuming no frontal melting") 116 FrontMelting = .FALSE. 117 ELSE 118 FrontMelting = .TRUE. 119 MeltVar => VariableGet(Mesh % Variables, MeltVarName, .TRUE., UnfoundFatal=.TRUE.) 120 END IF 121 122 TangledVarName = "Tangled" 123 TangledVar => VariableGet(Mesh % Variables, TangledVarName, .TRUE., UnfoundFatal=.TRUE.) 124 TangledVar % Values = 0.0_dp 125 126 !Get front normal vector 127 NormalVarName = ListGetString(Params, "Normal Vector Variable Name", UnfoundFatal=.TRUE.) 128 NormalVar => VariableGet(Mesh % Variables, NormalVarName, .TRUE., UnfoundFatal=.TRUE.) 129 130 !Get the orientation of the calving front, compute rotation matrix 131 !TODO: generalize and link 132 FrontOrientation = GetFrontOrientation(Model) 133 RotationMatrix = ComputeRotationMatrix(FrontOrientation) 134 135 DangerGrad = ListGetConstReal(Params, "Front Gradient Threshold", Found) 136 IF(.NOT.Found) THEN 137 CALL Info(SolverName, "'Front Gradient Threshold' not found, setting to 5.0") 138 DangerGrad = 5.0 139 END IF 140 141 !When correcting for unprojectability, to prevent interp problems, 142 !ensure that it is SLIGHTLY beyond beyond parallel, by adding this 143 !value (metres) to the displacement 144 epsShift = ListGetConstReal(Params, "Front Projectability Epsilon", Found) 145 IF(.NOT.Found) THEN 146 CALL Info(SolverName, "'Front Projectability Epsilon' not found, setting to 1.0") 147 epsShift = 1.0 148 END IF 149 150 epsTangle = ListGetConstReal(Params, "Front Tangle Epsilon", Found) 151 IF(.NOT.Found) THEN 152 CALL Info(SolverName, "'Front Tangle Epsilon' not found, setting to 1.0") 153 epsTangle = 1.0 154 END IF 155 156 LongRangeLimit = ListGetConstReal(Params, "Column Max Longitudinal Range", Found) 157 IF(.NOT.Found) THEN 158 CALL Info(SolverName, "'Column Max Longitudinal Range' not found, setting to 300.0") 159 LongRangeLimit = 300.0_dp 160 END IF 161 162 MaxDisplacement = ListGetConstReal(Params, "Maximum Node Displacement", Found) 163 IF(.NOT.Found) THEN 164 CALL Info(SolverName, "'Maximum Node Displacement' not found, setting to 1.0E4.") 165 MaxDisplacement = 1.0E4_dp 166 END IF 167 168 !------------------------------------------- 169 ! Find FNColumns 170 CALL MPI_AllReduce(MAXVAL(Mesh % ParallelInfo % GlobalDOFs), TotalNodes, & 171 1, MPI_INTEGER, MPI_MAX, ELMER_COMM_WORLD,ierr) 172 173 ExtrudedLevels = ListGetInteger(CurrentModel % Simulation,'Extruded Mesh Levels',Found) 174 IF(.NOT. Found) ExtrudedLevels = & 175 ListGetInteger(CurrentModel % Simulation,'Remesh Extruded Mesh Levels',Found) 176 IF(.NOT. Found) CALL Fatal(SolverName,& 177 "Unable to find 'Extruded Mesh Levels' or 'Remesh Extruded Mesh Levels'") 178 NodesPerLevel = TotalNodes / ExtrudedLevels 179 180 ALLOCATE(FNColumns(Mesh % NumberOfNodes)) 181 FNColumns = MOD(Mesh % ParallelInfo % GlobalDOFs, NodesPerLevel) 182 183 !Get the front line 184 FrontMaskName = "Calving Front Mask" 185 TopMaskName = "Top Surface Mask" 186 187 CALL MakePermUsingMask( Model, Solver, Mesh, TopMaskName, & 188 .FALSE., TopPerm, dummyint) 189 190 CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, & 191 .FALSE., FrontPerm, FaceNodeCount) 192 193 CALL GetDomainEdge(Model, Mesh, TopPerm, FrontNodes, & 194 FrontNodeNums, Parallel, FrontMaskName, Simplify=.FALSE.) 195 196 !Pass FrontNodeNums to all CPUs 197 IF(Boss) FrontLineCount = SIZE(FrontNodeNums) 198 CALL MPI_BCAST(FrontLineCount , 1, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr) 199 200 !Determine whether front columns are arranged 201 !left to right, and reorder if not 202 IF(Boss) THEN 203 204 NodeHolder(1) = FrontNodes % x(1) 205 NodeHolder(2) = FrontNodes % y(1) 206 NodeHolder(3) = FrontNodes % z(1) 207 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 208 y_coord(1) = NodeHolder(2) 209 210 NodeHolder(1) = FrontNodes % x(FrontLineCount) 211 NodeHolder(2) = FrontNodes % y(FrontLineCount) 212 NodeHolder(3) = FrontNodes % z(FrontLineCount) 213 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 214 y_coord(2) = NodeHolder(2) 215 216 LeftToRight = y_coord(2) > y_coord(1) 217 218 IF(.NOT. LeftToRight) THEN 219 IF(Debug) PRINT *,'Debug, switching to LeftToRight' 220 FrontNodeNums = FrontNodeNums(FrontLineCount:1:-1) 221 FrontNodes % x = FrontNodes % x(FrontLineCount:1:-1) 222 FrontNodes % y = FrontNodes % y(FrontLineCount:1:-1) 223 FrontNodes % z = FrontNodes % z(FrontLineCount:1:-1) 224 END IF 225 END IF 226 227 IF(.NOT. Boss) ALLOCATE(FrontNodeNums(FrontLineCount)) 228 CALL MPI_BCAST(FrontNodeNums , FrontLineCount, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr) 229 230 !FrontNodeNums is the GlobalDOFs of the nodes on the front 231 !So this can be easily converted into a FNColumn like list 232 ALLOCATE(FrontColumnList(FrontLineCount), & 233 FrontLocalNodeNumbers(FrontLineCount), & 234 DangerZone(FrontLineCount), & 235 ColumnNormals(FrontLineCount,3)) 236 237 FrontColumnList = MOD(FrontNodeNums, NodesPerLevel) 238 FrontLocalNodeNumbers = -1 239 DangerZone = .FALSE. 240 ColumnNormals = 0.0_dp 241 242 DO i=1,FrontLineCount 243 n = FrontNodeNums(i) 244 DO j=1,Mesh % NumberOfNodes 245 IF(Mesh % ParallelInfo % GlobalDOFs(j) == n) THEN 246 FrontLocalNodeNumbers(i) = j 247 END IF 248 END DO 249 END DO 250 251 !-------------------------------------- 252 ! Action: Compute lagrangian displacement for all nodes 253 ! This is the main function of the Solver. 254 ! Everything following this DO loop is taking care of 255 ! unprojectability/high gradient etc 256 !-------------------------------------- 257 258 DO i=1,Mesh % NumberOfNodes 259 IF(Perm(i) <= 0) CYCLE 260 261 IF(FrontMelting) THEN 262 IF(MeltVar % Perm(i) <= 0) & 263 CALL Fatal(SolverName, "Permutation error on front node!") 264 265 266 !Scalar melt value from Plume solver 267 MeltRate = MeltVar % Values(MeltVar % Perm(i)) 268 269 NodeNormal(1) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 1) 270 NodeNormal(2) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 2) 271 NodeNormal(3) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 3) 272 273 NodeMelt = NodeNormal * MeltRate 274 ELSE 275 NodeMelt = 0.0_dp 276 END IF 277 278 IF(IgnoreVelo) THEN 279 NodeVelo = 0.0 280 ELSE 281 !Compute front normal component of velocity 282 NodeVelo(1) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 1) 283 NodeVelo(2) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 2) 284 NodeVelo(3) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 3) 285 END IF 286 287 Displace = 0.0 288 289 Displace(1) = NodeVelo(1) - NodeMelt(1) 290 Displace(2) = NodeVelo(2) - NodeMelt(2) 291 Displace(3) = NodeVelo(3) - NodeMelt(3) 292 293 Displace = Displace * dt 294 295 IF(MAXVAL(Displace) > MaxDisplacement) THEN 296 WRITE(Message,'(A,i0,A)') "Maximum allowable front displacement exceeded for node ",i,". Limiting..." 297 CALL Warn(SolverName, Message) 298 Displace = Displace * (MaxDisplacement/MAXVAL(Displace)) 299 END IF 300 301 Advance((Perm(i)-1)*DOFs + 1) = Displace(1) 302 Advance((Perm(i)-1)*DOFs + 2) = Displace(2) 303 Advance((Perm(i)-1)*DOFs + 3) = Displace(3) 304 305 !First and last (i.e. lateral margin) columns don't move 306 IF((FNColumns(i) == FrontColumnList(1)) .OR. & 307 (FNColumns(i) == FrontColumnList(FrontLineCount))) THEN 308 Advance((Perm(i)-1)*DOFs + 1) = 0.0_dp 309 Advance((Perm(i)-1)*DOFs + 2) = 0.0_dp 310 Advance((Perm(i)-1)*DOFs + 3) = 0.0_dp 311 END IF 312 END DO 313 314 315 !---------------------------------------------------------- 316 ! Now we need to look for and limit regions on the 317 ! where high gradient + 'straightness' makes 318 ! remeshing into vertical columns troublesome. 319 !---------------------------------------------------------- 320 ! 321 ! Five things: 322 ! - Limit horizontal range (otherwise, Remesh will smear a column of nodes 323 ! all over the place) 324 ! - Limit undercut range (longitudinal range) to prevent mesh degeneracy 325 ! - Prevent retreat at node near lateral margins 326 ! - Check for 'tangled' regions, where fixing unprojectability one way 327 ! causes unprojectability the other way. 328 ! - Prevent Unprojectability - requires knowledge of neighbouring columns 329 !---------------------------------------------------------- 330 331 !------------------------------------------- 332 ! Cycle columns, looking at average normal for the column 333 !------------------------------------------- 334 ! Normal vector is limited by projectability, so if average is high, 335 ! all are high 336 ! 337 ! Note that we are cycling the parallel gathered line, so each part 338 ! will only have a few columns (if any) 339 ! So, mark troublesome columns where present, then communicate 340 !------------------------------------------- 341 342 DO i=1,FrontLineCount 343 col = FrontColumnList(i) 344 345 hits = COUNT(FNColumns == col) 346 IF(hits == 0) CYCLE 347 348 ColumnNormal = 0.0_dp 349 350 !Gather normal vector 351 DO j=1,Mesh % NumberOfNodes 352 IF(FNColumns(j) == col) THEN 353 ColumnNormal(1) = ColumnNormal(1) + & 354 NormalVar % Values(((NormalVar % Perm(j)-1)*NormalVar % DOFs) + 1) 355 ColumnNormal(2) = ColumnNormal(2) + & 356 NormalVar % Values(((NormalVar % Perm(j)-1)*NormalVar % DOFs) + 2) 357 ColumnNormal(3) = ColumnNormal(3) + & 358 NormalVar % Values(((NormalVar % Perm(j)-1)*NormalVar % DOFs) + 3) 359 END IF 360 END DO 361 362 !unit vector 363 ColumnNormal = ColumnNormal / hits 364 !Convert to front coordinate system 365 ColumnNormal = MATMUL( RotationMatrix, ColumnNormal ) 366 !Save for later 367 ColumnNormals(i,1:3) = ColumnNormal(1:3) 368 369 !We're concerned with the lateral (rather than vertical) component 370 IF( ABS(ColumnNormal(2) / ColumnNormal(3)) > DangerGrad ) THEN 371 DangerZone(i) = .TRUE. 372 END IF 373 END DO 374 375 !Communicate between partitions 376 !This is an 'OR' condition insofar as only one partition 377 !will have actually computed the gradient 378 IF(Parallel) THEN 379 DO i=1,FrontLineCount 380 CALL SParIterAllReduceOR(DangerZone(i)) 381 END DO 382 END IF 383 384 !Mark before and after dangerzone too 385 ALLOCATE(WorkLogical(FrontLineCount)) 386 WorkLogical = .FALSE. 387 388 DO i=1,FrontLineCount 389 IF(DangerZone(i)) WorkLogical(i) = .TRUE. 390 391 IF(i > 1) THEN 392 IF(DangerZone(i-1)) WorkLogical(i) = .TRUE. 393 END IF 394 395 IF(i < FrontLineCount) THEN 396 IF(DangerZone(i+1)) WorkLogical(i) = .TRUE. 397 END IF 398 END DO 399 400 DangerZone = WorkLogical 401 DEALLOCATE(WorkLogical) 402 403 !Find and store leftmost and rightmost (rotated) coordinate of 404 !each column for checking projectability later 405 !Rot_y_coords(:,1) is leftmost, and (:,2) is right most y coord of 406 !each column's nodes, and Rot_z_coords(:,:) is the min(1)/max(2) z 407 ALLOCATE(Rot_y_coords(FrontLineCount,2),& 408 Rot_z_coords(FrontLineCount,2)) 409 Rot_y_coords(:,1) = HUGE(0.0_dp) 410 Rot_y_coords(:,2) = -HUGE(0.0_dp) 411 Rot_z_coords(:,1) = HUGE(0.0_dp) 412 Rot_z_coords(:,2) = -HUGE(0.0_dp) 413 414 DO i=1,FrontLineCount 415 col = FrontColumnList(i) 416 IF(COUNT(FNColumns == col) == 0) CYCLE 417 418 DO j=1,Mesh % NumberOfNodes 419 IF(FNColumns(j) /= col) CYCLE 420 421 NodeHolder(1) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1) 422 NodeHolder(2) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2) 423 NodeHolder(3) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3) 424 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 425 426 Rot_y_coords(i,1) = MIN(Rot_y_coords(i,1), NodeHolder(2)) 427 Rot_y_coords(i,2) = MAX(Rot_y_coords(i,2), NodeHolder(2)) 428 429 Rot_z_coords(i,1) = MIN(Rot_z_coords(i,1), NodeHolder(3)) 430 Rot_z_coords(i,2) = MAX(Rot_z_coords(i,2), NodeHolder(3)) 431 END DO 432 END DO 433 434 !----------------------------------- 435 ! Limit lateral range (to 0) in DangerZone 436 !----------------------------------- 437 ! The physical interpretation of this is that, when melt undercutting occurs 438 ! in a region of high gradient, the unmelted parts of that column also shift 439 ! with the melt. 440 ! This is a minor limitation, but better than Free Surface Equation! 441 442 DO i=1,FrontLineCount 443 IF(.NOT. DangerZone(i)) CYCLE 444 445 col = FrontColumnList(i) 446 hits = COUNT(FNColumns == col) 447 448 IF(hits == 0) CYCLE 449 450 ALLOCATE(NodeNumbers(hits), & 451 ColumnNodes % x(hits),& 452 ColumnNodes % y(hits),& 453 ColumnNodes % z(hits)) 454 455 ColumnNodes % NumberOfNodes = hits 456 457 !Gather nodenumbers in column 458 county = 0 459 DO j=1,Mesh % NumberOfNodes 460 IF(FNColumns(j) /= col) CYCLE 461 county = county + 1 462 463 NodeNumbers(county) = j 464 ColumnNodes % x(county) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1) 465 ColumnNodes % y(county) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2) 466 ColumnNodes % z(county) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3) 467 END DO 468 469 !direction - which way is this part of the front pointing? 470 ShiftLeft = ColumnNormals(i,2) > 0 471 IF(ShiftLeft) THEN 472 ShiftTo = HUGE(ShiftTo) 473 ELSE 474 ShiftTo = -HUGE(ShiftTo) 475 END IF 476 477 !Rotate points and find furthest left (or right) 478 DO j=1,ColumnNodes % NumberOfNodes 479 NodeHolder(1) = ColumnNodes % x(j) 480 NodeHolder(2) = ColumnNodes % y(j) 481 NodeHolder(3) = ColumnNodes % z(j) 482 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 483 484 IF(ShiftLeft) THEN 485 IF(NodeHolder(2) < ShiftTo) ShiftTo = NodeHolder(2) 486 ELSE 487 IF(NodeHolder(2) > ShiftTo) ShiftTo = NodeHolder(2) 488 END IF 489 END DO 490 491 !Now, for each node in column, compute the displacement (in rotated y coordinate) 492 DO j=1,ColumnNodes % NumberOfNodes 493 NodeHolder(1) = ColumnNodes % x(j) 494 NodeHolder(2) = ColumnNodes % y(j) 495 NodeHolder(3) = ColumnNodes % z(j) 496 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 497 498 ShiftDist = ShiftTo - NodeHolder(2) 499 500 Displace = 0.0_dp 501 Displace(2) = ShiftDist 502 503 Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace) 504 505 !Adjust the variable values to shift nodes in line. 506 Advance((Perm(NodeNumbers(j))-1)*DOFs + 1) = & 507 Advance((Perm(NodeNumbers(j))-1)*DOFs + 1) + Displace(1) 508 Advance((Perm(NodeNumbers(j))-1)*DOFs + 2) = & 509 Advance((Perm(NodeNumbers(j))-1)*DOFs + 2) + Displace(2) 510 511 IF(Debug) PRINT *,'node: ',NodeNumbers(j),' shifting: ',ShiftDist,' to ',ShiftTo,' point: ', & 512 ColumnNodes % x(j),ColumnNodes % y(j),ColumnNodes % z(j) 513 END DO 514 515 DEALLOCATE(NodeNumbers, & 516 ColumnNodes % x, & 517 ColumnNodes % y, & 518 ColumnNodes % z) 519 END DO 520 521 !----------------------------------- 522 ! Limit longitudinal range everywhere 523 !----------------------------------- 524 ! Two options for how to do this: 525 ! Drag nodes back with melt, or effectively 526 ! limit melt (keeping nodes forward) 527 ! Opt for the latter, or else we're 528 ! forcing melting to have an effect 529 !----------------------------------- 530 DO i=1,FrontLineCount 531 532 col = FrontColumnList(i) 533 hits = COUNT(FNColumns == col) 534 535 IF(hits == 0) CYCLE 536 537 IF((Rot_z_coords(i,2) - Rot_z_coords(i,1)) > LongRangeLimit) THEN 538 539 LimitZ = Rot_z_coords(i,2) - LongRangeLimit 540 Rot_z_coords(i,1) = LimitZ 541 542 DO j=1,Mesh % NumberOfNodes 543 IF(FNColumns(j) /= col) CYCLE 544 545 NodeHolder(1) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1) 546 NodeHolder(2) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2) 547 NodeHolder(3) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3) 548 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 549 550 IF(NodeHolder(3) >= LimitZ) CYCLE 551 552 Displace = 0.0_dp 553 Displace(3) = LimitZ - NodeHolder(3) 554 555 Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace) 556 557 !Adjust the variable values to shift nodes in line. 558 Advance((Perm(j)-1)*DOFs + 1) = & 559 Advance((Perm(j)-1)*DOFs + 1) + Displace(1) 560 Advance((Perm(j)-1)*DOFs + 2) = & 561 Advance((Perm(j)-1)*DOFs + 2) + Displace(2) 562 IF(Debug) PRINT *,ParEnv % MyPE,' Debug, limiting node range: col ',& 563 i,' node ',j,' limit: ',LimitZ,' displace: ',Displace 564 END DO 565 566 END IF 567 END DO 568 569 570 !----------------------------------- 571 ! Now check projectability 572 !----------------------------------- 573 ! If an unprojectable portion of the front is found, 574 ! the inland nodes remain in place, while those further 575 ! advanced shift sideways to maintain projectability 576 ! 577 ! Typical case is melt plume at end of recently calved 578 ! straight edge. 579 ! 580 ! requires MPI comms 581 582 !Gather rotated y coord of all columns 583 DO i=1,FrontLineCount 584 CALL MPI_AllReduce(MPI_IN_PLACE, Rot_y_coords(i,1), & 585 1, MPI_DOUBLE_PRECISION, MPI_MIN, ELMER_COMM_WORLD,ierr) 586 CALL MPI_AllReduce(MPI_IN_PLACE, Rot_y_coords(i,2), & 587 1, MPI_DOUBLE_PRECISION, MPI_MAX, ELMER_COMM_WORLD,ierr) 588 589 CALL MPI_AllReduce(MPI_IN_PLACE, Rot_z_coords(i,1), & 590 1, MPI_DOUBLE_PRECISION, MPI_MIN, ELMER_COMM_WORLD,ierr) 591 CALL MPI_AllReduce(MPI_IN_PLACE, Rot_z_coords(i,2), & 592 1, MPI_DOUBLE_PRECISION, MPI_MAX, ELMER_COMM_WORLD,ierr) 593 594 IF(Boss .AND. Debug) PRINT *,'Debug, rot_y_coords: ',i,rot_y_coords(i,:) 595 IF(Boss .AND. Debug) PRINT *,'Debug, rot_z_coords: ',i,rot_z_coords(i,:) 596 END DO 597 598 ALLOCATE(UpdatedColumn(FrontLineCount), & 599 UpdatedDirection(FrontLineCount), & 600 Tangled(FrontLineCount),& 601 TangledGroup(FrontLineCount),& 602 TangledPivotIdx(FrontLineCount),& 603 TangledShiftTo(FrontLineCount),& 604 DontMove(FrontLineCount)) 605 606 UpdatedColumn = .FALSE. 607 UpdatedDirection = 0 608 Tangled = .FALSE. 609 TangledGroup = 0 610 TangledPivotIdx = 0 611 TangledShiftTo = 0.0_dp 612 DontMove = .FALSE. 613 614 DontMove(1) = .TRUE. 615 DontMove(FrontLineCount) = .TRUE. 616 617 !TODO: Deal with DontMove and tangling properly... 618 ! Ensure that comms is not necessary for DontMove 619 620 !Test for thin sliver at lateral margins - potential to get 621 !stuck like this, so impose an angle here 622 !We require that the 2nd node from the end not retreat beyond 623 !a 45 degree angle inland. PYTHAGORAS 624 !Shift the 2nd column in the lateral direction only, 625 !to the point where it makes a 45 degree angle w/ 626 !the corner. 627 ! * 628 ! / | 629 ! / | 630 ! * <- * 631 632 DO i=1,2 633 634 IF(i==1) THEN 635 CornerIdx = 1 636 SecondIdx = 2 637 direction = 1.0_dp 638 ELSE 639 CornerIdx = FrontLineCount 640 SecondIdx = FrontLineCount-1 641 direction = -1.0_dp 642 END IF 643 644 !Conveniently, first time round we want the left most coord (Rot_y_coords(:,1)) 645 !whereas second time we want the right (Rot_y_cords(:,2)) 646 CornerDirection(1) = Rot_y_coords(SecondIdx,i) - Rot_y_coords(CornerIdx,1) 647 CornerDirection(2) = Rot_z_coords(SecondIdx,i) - Rot_z_coords(CornerIdx,1) 648 !Unit vector 649 CornerDirection = CornerDirection / (SUM(CornerDirection ** 2.0)**0.5) 650 651 IF(Debug) PRINT *,ParEnv % MyPE, 'CornerDirection ',i,': ',CornerDirection 652 653 IF( CornerDirection(2) < (-1.0_dp / (2.0_dp ** 0.5)) ) THEN 654 !Shift 2nd node and mark DontMove 655 656 ShiftToY = Rot_y_coords(CornerIdx,1) + & 657 direction * ((Rot_z_coords(CornerIdx,1) - Rot_z_coords(SecondIdx,1))) 658 659 Rot_y_coords(SecondIdx,1) = ShiftToY 660 Rot_y_coords(SecondIdx,2) = ShiftToY 661 662 DontMove(SecondIdx) = .TRUE. 663 IF(Debug) PRINT *,ParEnv % MyPE,' debug, side ',i,' of front is too inwards' 664 665 DO k=1,Mesh % NumberOfNodes 666 IF(FNColumns(k) /= FrontColumnList(SecondIdx)) CYCLE 667 668 NodeHolder(1) = Mesh % Nodes % x(k) + Advance((Perm(k)-1)*DOFs + 1) 669 NodeHolder(2) = Mesh % Nodes % y(k) + Advance((Perm(k)-1)*DOFs + 2) 670 NodeHolder(3) = Mesh % Nodes % z(k) + Advance((Perm(k)-1)*DOFs + 3) 671 672 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 673 674 Displace = 0.0_dp 675 Displace(2) = ShiftToY - NodeHolder(2) 676 677 Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace) 678 679 IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, shifting next to corner node ',k,& 680 NodeHolder,' by ',Displace 681 682 !Adjust the variable values to shift nodes in line. 683 Advance((Perm(k)-1)*DOFs + 1) = Advance((Perm(k)-1)*DOFs + 1) + Displace(1) 684 Advance((Perm(k)-1)*DOFs + 2) = Advance((Perm(k)-1)*DOFs + 2) + Displace(2) 685 END DO 686 687 END IF 688 END DO 689 690 !----------------------------------------------- 691 ! Cycle the line, looking for unprojectable 692 ! (but not tangled) regions. 693 ! e.g. plume melting behind a vertical portion 694 !----------------------------------------------- 695 696 !In case shifting nodes affects another partition, we loop so long as 697 !at least one partition has MovedOne 698 MovedOne = .TRUE. 699 county = 0 700 DO WHILE(MovedOne) 701 county = county + 1 702 IF(county > 100) CALL Fatal(SolverName, "Infinite loop!") 703 IF(Debug) PRINT *,ParEnv % MyPE, 'Debug, iterating projectability ', county 704 705 MovedOne = .FALSE. 706 UpdatedColumn = .FALSE. 707 708 DO i=2,FrontLineCount 709 710 !If already detangled, skip 711 !IF(Tangled(i)) CYCLE 712 713 !epsShift here 714 IF((Rot_y_coords(i,1) - Rot_y_coords(i-1,2)) < 0.9*epsShift) THEN 715 716 IF(Debug) PRINT *, 'Debug diff ',i,i-1, & 717 (Rot_y_coords(i,1) - Rot_y_coords(i-1,2)), epsShift 718 719 IF(DontMove(i) .AND. DontMove(i-1)) THEN 720 CALL Warn(SolverName,& 721 "Both nodes are marked Dont Move, stopping shifting.") 722 EXIT 723 END IF 724 !Work out which to shift 725 !If one is marked DontMove (corner node, or 2nd inland and weird shape) 726 ! then move the other 727 !Otherwise, shift whichever is further forward 728 IF(DontMove(i)) THEN 729 ShiftSecond = .FALSE. 730 DontMove(i-1) = .TRUE. 731 IF(Debug) PRINT *,ParEnv % MyPE,'Debug, do not move second: ',i 732 ELSE IF(DontMove(i-1)) THEN 733 ShiftSecond = .TRUE. 734 DontMove(i) = .TRUE. 735 IF(Debug) PRINT *,ParEnv % MyPE,'Debug, do not move first: ',i-1 736 ELSE 737 IF(SUM(Rot_z_coords(i,:)) > SUM(Rot_z_coords(i-1,:))) THEN 738 ShiftSecond = .TRUE. 739 ELSE 740 ShiftSecond = .FALSE. 741 END IF 742 END IF 743 744 IF(ShiftSecond) THEN 745 ShiftIdx = i 746 ShiftToIdx = i-1 747 ELSE 748 ShiftIdx = i-1 749 ShiftToIdx = i 750 END IF 751 752 !Calculate ShiftTo, depends on ShiftSecond 753 !Also update shifted Rot_y_coords 754 IF(ShiftSecond) THEN 755 !If this node has already been moved the other way, leave it alone 756 IF((UpdatedDirection(ShiftIdx) < 0) .AND. .NOT. DontMove(ShiftToIdx)) CYCLE 757 758 ShiftTo = Rot_y_coords(i-1,2) + epsShift 759 IF(Rot_y_coords(i,2) < ShiftTo) UpdatedDirection(ShiftIdx) = 1 760 761 Rot_y_coords(i,1) = MAX(Rot_y_coords(i,1), ShiftTo) 762 Rot_y_coords(i,2) = MAX(Rot_y_coords(i,2), ShiftTo) 763 ELSE 764 !If this node has already been moved the other way, leave it alone 765 IF((UpdatedDirection(ShiftIdx) > 0) .AND. .NOT. DontMove(ShiftToIdx)) CYCLE 766 767 ShiftTo = Rot_y_coords(i,1) - epsShift 768 IF(Rot_y_coords(i,1) > ShiftTo) UpdatedDirection(ShiftIdx) = -1 769 770 Rot_y_coords(i-1,1) = MIN(Rot_y_coords(i-1,1), ShiftTo) 771 Rot_y_coords(i-1,2) = MIN(Rot_y_coords(i-1,2), ShiftTo) 772 END IF 773 774 IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, updating col ',ShiftIdx,& 775 ' rot_y_coords: ',Rot_y_coords(ShiftIdx,:) 776 777 UpdatedColumn(ShiftIdx) = .TRUE. 778 779 !Shift all the nodes in this column 780 DO j=1,Mesh % NumberOfNodes 781 IF(FNColumns(j) /= FrontColumnList(ShiftIdx)) CYCLE 782 783 NodeHolder(1) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1) 784 NodeHolder(2) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2) 785 NodeHolder(3) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3) 786 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 787 788 Displace = 0.0_dp 789 Displace(2) = ShiftTo - NodeHolder(2) 790 791 !Check if node already projectable 792 IF(ShiftSecond) THEN 793 IF(Displace(2) < 0 ) CYCLE 794 ELSE 795 IF(Displace(2) > 0) CYCLE 796 END IF 797 798 Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace) 799 800 IF(Debug) PRINT *,ParEnv % MyPE, 'Debug, shifting node ',j,' col ',ShiftIdx,'xyz: ',& 801 Mesh % Nodes % x(j)+Advance((Perm(j)-1)*DOFs + 1),& 802 Mesh % Nodes % y(j)+Advance((Perm(j)-1)*DOFs + 2),& 803 Mesh % Nodes % z(j)+Advance((Perm(j)-1)*DOFs + 3),& 804 ' by ',Displace,' to ensure projectability. 1' 805 806 807 !Adjust the variable values to shift nodes in line. 808 Advance((Perm(j)-1)*DOFs + 1) = Advance((Perm(j)-1)*DOFs + 1) + Displace(1) 809 Advance((Perm(j)-1)*DOFs + 2) = Advance((Perm(j)-1)*DOFs + 2) + Displace(2) 810 811 END DO 812 END IF 813 END DO 814 815 IF(ANY(UpdatedColumn)) MovedOne = .TRUE. 816 817 IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, MovedOne: ',MovedOne 818 IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, UpdatedColumn: ',UpdatedColumn 819 820 END DO 821 822 823 !----------------------------------------------- 824 ! Check for pinnacles or rifts which can't be made 825 ! projectable. Set the columns in a line and mark them 826 ! for removal by Remesh.F90 827 !----------------------------------------------- 828 !TODO: At least 3 separate issues here: 829 ! 830 ! *This one should be fixed now, at the end we check for groups disappearing* 831 ! 1 : If there's a tangled group, then another, superset tangled 832 ! group, this causes "programming error, tangled group has zero nodes" 833 ! potential solution here is to just remove this error message, because 834 ! its not really a problem *I DON'T THINK*. However, if so, need to 835 ! check for it, and shift TangledGroups down one, so Remesh behaves 836 ! 837 ! *This one should now be fixed, because we do all the unprojectable shifting first:* 838 ! 2 : Here we iteratively: check tangled, then check unprojectable 839 ! If correcting unprojectability causes further tangling, this 840 ! isn't caught. Potential solutions: 841 ! Improve parallel unprojectability checker (dirty fix, won't catch every poss case) 842 ! Better: recheck previously tangled regions 843 ! 844 ! 3 : Long straight sides which also happen to tangle with the end of their headlands 845 ! are not well handled. All the nodes along these sides are shifted out the way 846 ! in the new mesh 847 848 849 NoTangledGroups = 0 850 DO i=1,FrontLineCount-2 851 IF(Tangled(i)) CYCLE 852 j = i+2 853 854 !If the column two columns away is less than 2*epsShift away, and there 855 !is a change of direction, problems... 856 IF((Rot_y_coords(j,1) - Rot_y_coords(i,2)) < 2*epsShift) THEN 857 858 IF(((Rot_z_coords(i,1) < Rot_z_coords(i+1,1)) .NEQV. & 859 (Rot_z_coords(i+1,1) < Rot_z_coords(j,1))) .OR. & 860 ((Rot_z_coords(i,2) < Rot_z_coords(i+1,2)) .NEQV. & 861 (Rot_z_coords(i+1,2) < Rot_z_coords(j,2)))) THEN 862 863 !Either a pinnacle or a slit (i.e protrusion or rift) 864 Protrusion = SUM(Rot_z_coords(i+1,:)) > SUM(Rot_z_coords(i,:)) 865 IF(Debug) PRINT *,'Debug, protrusion: ',Protrusion 866 867 NoTangledGroups = NoTangledGroups + 1 868 PivotIdx = i+1 869 870 DO k=2,PivotIdx 871 p1(1) = Rot_y_coords(k,2) 872 p1(2) = Rot_z_coords(k,2) 873 874 p2(1) = Rot_y_coords(k-1,2) 875 p2(2) = Rot_z_coords(k-1,2) 876 877 DO m=FrontLineCount-1,PivotIdx,-1 878 IF(k==m) CYCLE !first two will always intersect by definition, not what we want 879 q1(1) = Rot_y_coords(m,1) 880 q1(2) = Rot_z_coords(m,1) 881 882 q2(1) = Rot_y_coords(m+1,1) 883 q2(2) = Rot_z_coords(m+1,1) 884 885 CALL LineSegmentsIntersect ( p1, p2, q1, q2, intersect, intersect_flag ) 886 887 IF(intersect_flag) EXIT 888 END DO 889 IF(intersect_flag) EXIT 890 END DO 891 892 IF(intersect_flag) THEN 893 894 !Found an intersection point (intersect) 895 PRINT *,'Debug, found tangle intersection ',intersect,' leaving last tangled nodes: ',k,m 896 897 Tangled(k:m) = .TRUE. 898 TangledPivotIdx(k:m) = PivotIdx 899 TangledShiftTo(k:m) = intersect(1) 900 901 IF(Protrusion) THEN 902 TangledGroup(k:m) = NoTangledGroups 903 ELSE 904 TangledGroup(k:m) = -NoTangledGroups 905 END IF 906 907 ELSE 908 PRINT *,'Debug, found no intersection, so nodes are not QUITE tangled: ',i,j 909 910 Tangled(i:j) = .TRUE. 911 TangledPivotIdx(i:j) = PivotIdx 912 TangledShiftTo(i:j) = (SUM(rot_y_coords(i,:)) + SUM(rot_y_coords(j,:))) / 4.0_dp 913 914 IF(Protrusion) THEN 915 TangledGroup(i:j) = NoTangledGroups 916 ELSE 917 TangledGroup(i:j) = -NoTangledGroups 918 END IF 919 920 END IF 921 END IF 922 END IF 923 END DO 924 925 !Check for a tangled group 'swallowing' another 926 county = 0 927 DO i=1,NoTangledGroups 928 IF(COUNT(TangledGroup == i) > 0) CYCLE 929 county = county + 1 930 !Shift group numbers down one 931 DO j=1,SIZE(TangledGroup) 932 IF(TangledGroup(j) > i) TangledGroup(j) = TangledGroup(j) - 1 933 END DO 934 END DO 935 NoTangledGroups = NoTangledGroups - county 936 937 !Strategy: 938 ! Shift all nodes to near (offset) the y-coordinate 939 ! of the tangle pivot (i+1, above) 940 DO i=1,NoTangledGroups 941 n = COUNT(TangledGroup == i) 942 IF(n==0) THEN 943 n = COUNT(TangledGroup == -i) 944 Protrusion = .FALSE. 945 ELSE 946 Protrusion = .TRUE. 947 END IF 948 IF(n==0) CALL Fatal(SolverName, "Programming error: tangled group has 0 nodes?") 949 950 !Get the pivot node index, ShiftToY, and tangled node range 951 FirstTangleIdx = 0 952 LastTangleIdx = 0 953 DO j=1,FrontLineCount 954 IF(TangledGroup(j) == i .OR. TangledGroup(j) == -i) THEN 955 IF(FirstTangleIdx == 0) FirstTangleIdx = j 956 LastTangleIdx = j 957 PivotIdx = TangledPivotIdx(j) 958 ShiftToY = TangledShiftTo(j) 959 !EXIT 960 END IF 961 END DO 962 963 IF(LastTangleIdx - FirstTangleIdx /= n-1) CALL Fatal(SolverName, & 964 "Programming error: wrong number of nodes in TangledGroup") 965 IF(Debug) PRINT *,'Debug, tangled pivot index, ShiftToY: ', PivotIdx, ShiftToY 966 967 LeftY = ShiftToY - (epsTangle * ((n-1) / 2.0_dp)) 968 RightY = ShiftToY + (epsTangle * ((n-1) / 2.0_dp)) 969 970 !Potentially 'squeezed' on either side by neighbour columns 971 SqueezeLeft = .FALSE. 972 SqueezeRight = .FALSE. 973 974 IF(LeftY < Rot_y_coords(FirstTangleIdx-1,2) + epsTangle) THEN 975 SqueezeLeft = .TRUE. 976 IF( ( (Rot_y_coords(LastTangleIdx+1,1) - epsTangle) - (epsTangle * (n-1)) ) < & 977 (Rot_y_coords(FirstTangleIdx-1,2) + epsTangle)) THEN 978 SqueezeRight = .TRUE. 979 END IF 980 END IF 981 IF(RightY > (Rot_y_coords(LastTangleIdx+1,1) - epsTangle)) THEN 982 SqueezeRight = .TRUE. 983 IF( ( (Rot_y_coords(LastTangleIdx+1,1) - epsTangle) - (epsTangle * (n-1)) ) < & 984 (Rot_y_coords(FirstTangleIdx-1,2) + epsTangle)) THEN 985 SqueezeLeft = .TRUE. 986 END IF 987 END IF 988 989 IF(Debug) PRINT *,'Debug, LeftY: ',LeftY,' RightY: ',RightY,' SqueezeL: ',& 990 SqueezeLeft,' SqueezeR: ',SqueezeRight,' prev: ',Rot_y_coords(FirstTangleIdx-1,2),& 991 ' next: ',Rot_y_coords(LastTangleIdx+1,1) 992 993 !If squeezed, adjust the new y coord of the tangled nodes 994 IF(SqueezeLeft .AND. SqueezeRight) THEN 995 thisEps = (Rot_y_coords(LastTangleIdx+1,1) - Rot_y_coords(FirstTangleIdx-1,2)) / (n+1) 996 LeftY = Rot_y_coords(FirstTangleIdx-1,2) + thisEps 997 RightY = Rot_y_coords(LastTangleIdx+1,1) - thisEps 998 ShiftToY = (RightY + LeftY) / 2.0_dp !midpoint 999 ELSE IF(SqueezeLeft) THEN 1000 Shift = (Rot_y_coords(FirstTangleIdx-1,2) + epsTangle) - LeftY 1001 LeftY = LeftY + Shift 1002 RightY = RightY + Shift 1003 ShiftToY = ShiftToY + Shift 1004 ELSE IF(SqueezeRight) THEN 1005 Shift = (Rot_y_coords(LastTangleIdx+1,1) - epsTangle) - RightY 1006 LeftY = LeftY + Shift 1007 RightY = RightY + Shift 1008 ShiftToY = ShiftToY + Shift 1009 END IF 1010 1011 !Where tangling occurs, we shift the tangled columns to be 1012 !1m apart in a series. Then Remesh gets rid of them 1013 DO j=FirstTangleIdx,LastTangleIdx 1014 IF(.NOT. (TangledGroup(j) == i .OR. TangledGroup(j) == -i)) & 1015 CALL Fatal(SolverName, "Programming error: node in specified idx range not tangled?") 1016 1017 thisY = LeftY + ((REAL(j - FirstTangleIdx)/(n-1)) * (RightY - LeftY)) 1018 IF(Debug) PRINT *,'Debug, thisY: ',thisY, j 1019 1020 DO k=1,Mesh % NumberOfNodes 1021 IF(FNColumns(k) /= FrontColumnList(j)) CYCLE 1022 1023 NodeHolder(1) = Mesh % Nodes % x(k) + Advance((Perm(k)-1)*DOFs + 1) 1024 NodeHolder(2) = Mesh % Nodes % y(k) + Advance((Perm(k)-1)*DOFs + 2) 1025 NodeHolder(3) = Mesh % Nodes % z(k) + Advance((Perm(k)-1)*DOFs + 3) 1026 IF(Debug) PRINT *, ParEnv % MyPE, ' Debug, pre shift tangled node ',k,': ',NodeHolder 1027 1028 NodeHolder = MATMUL(RotationMatrix, NodeHolder) 1029 1030 Displace = 0.0_dp 1031 Displace(2) = thisY - NodeHolder(2) 1032 1033 Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace) 1034 1035 IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, shifting node ',k, ' col ',j,& 1036 ' by ',Displace,' to detangle.' 1037 1038 !Adjust the variable values to shift nodes in line. 1039 Advance((Perm(k)-1)*DOFs + 1) = Advance((Perm(k)-1)*DOFs + 1) + Displace(1) 1040 Advance((Perm(k)-1)*DOFs + 2) = Advance((Perm(k)-1)*DOFs + 2) + Displace(2) 1041 !Set this variable so that Remesh knows 1042 TangledVar % Values(TangledVar % Perm(k)) = 1.0_dp * ABS(TangledGroup(j)) 1043 END DO 1044 END DO 1045 END DO 1046 1047 1048 !--------------------------------------- 1049 !Done, just deallocations 1050 1051 FirstTime = .FALSE. 1052 1053 DEALLOCATE(FrontPerm, & 1054 TopPerm, & 1055 FrontNodeNums, & 1056 Rot_y_coords, & 1057 UpdatedColumn, & 1058 UpdatedDirection, & 1059 Tangled, & 1060 TangledGroup, & 1061 TangledPivotIdx, & 1062 TangledShiftTo, & 1063 FrontColumnList, & 1064 FrontLocalNodeNumbers) 1065 1066 END SUBROUTINE FrontAdvance3D 1067