Skip to content

Commit 210ad4f

Browse files
authored
refactor(prt): structure exit solution decision (#2489)
PRT instantiates a tree of tracking methods, each of which may delegate to submethods or solve particle motion itself. Leaves in the tree do the work, nodes delegate depending on various conditions. The work consists of - trying to obtain an exit solution from the method domain in each dimension independently - choosing which of the candidate exit solutions, if any, is the correct (e.g., first) one - solving particle coordinates for user-specified times up to exit time - solving (the remaining) particle coordinates at exit time and generally maintaining the particle's state while this happens. This happens in the track_subcell routine in the relevant subcell methods. The four steps happen roughly in the order described, but the procedure is not structured otherwise (e.g. by subroutines, etc). So the concept of an exit solution is implicit and is so far mainly relevant for setting boundary indices (e.g. face numbers). Up to now there has been a single criterion for selecting among candidate exit solutions: take the one that occurs first. However, #2478 is an example of a situation in which this gives unwanted results. So we may have arbitrary criteria for selecting the "best" exit solution. But this is awkward to implement right now, as the logic is interwoven across the track_subcell routine. Separate the evaluation of candidate exit solutions and the selection of one into procedures. This makes filtering of candidate solutions cleaner. - find_exits: generates candidates - pick_exit: picks the best solution Also introduce a base DomainType and module, used in the signature of find_exits. Also, miscellaneous other tidying, and clarify argument intent in some routines in TernarySolveUtils.f90.
1 parent d9fa90f commit 210ad4f

File tree

12 files changed

+568
-397
lines changed

12 files changed

+568
-397
lines changed

make/makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,11 @@ $(OBJDIR)/Dis.o \
310310
$(OBJDIR)/Dis2d.o \
311311
$(OBJDIR)/BudgetObject.o \
312312
$(OBJDIR)/BoundaryPackage.o \
313-
$(OBJDIR)/CellDefn.o \
314313
$(OBJDIR)/ParticleEvent.o \
315314
$(OBJDIR)/sort.o \
315+
$(OBJDIR)/Domain.o \
316+
$(OBJDIR)/CellDefn.o \
316317
$(OBJDIR)/FlowModelInterface.o \
317-
$(OBJDIR)/Cell.o \
318318
$(OBJDIR)/WeakSinkEvent.o \
319319
$(OBJDIR)/UserTimeEvent.o \
320320
$(OBJDIR)/TimeStepEvent.o \
@@ -325,6 +325,8 @@ $(OBJDIR)/ReleaseEvent.o \
325325
$(OBJDIR)/prt-fmi.o \
326326
$(OBJDIR)/ParticleEvents.o \
327327
$(OBJDIR)/FeatExitEvent.o \
328+
$(OBJDIR)/ExitSolution.o \
329+
$(OBJDIR)/Cell.o \
328330
$(OBJDIR)/Method.o \
329331
$(OBJDIR)/CellExitEvent.o \
330332
$(OBJDIR)/SubcellExitEvent.o \

msvs/mf6core.vfproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@
422422
<File RelativePath="..\src\Solution\LinearMethods\ImsLinearSolver.f90"/>
423423
<File RelativePath="..\src\Solution\LinearMethods\ImsReordering.f90"/></Filter>
424424
<Filter Name="ParticleTracker">
425+
<File RelativePath="..\src\Solution\ParticleTracker\Domain\Domain.f90"/>
425426
<File RelativePath="..\src\Solution\ParticleTracker\Domain\Cell.f90"/>
426427
<File RelativePath="..\src\Solution\ParticleTracker\Domain\CellDefn.f90"/>
427428
<File RelativePath="..\src\Solution\ParticleTracker\Domain\CellPoly.f90"/>
@@ -431,6 +432,7 @@
431432
<File RelativePath="..\src\Solution\ParticleTracker\Domain\Subcell.f90"/>
432433
<File RelativePath="..\src\Solution\ParticleTracker\Domain\SubcellRect.f90"/>
433434
<File RelativePath="..\src\Solution\ParticleTracker\Domain\SubcellTri.f90"/>
435+
<File RelativePath="..\src\Solution\ParticleTracker\Method\ExitSolution.f90"/>
434436
<File RelativePath="..\src\Solution\ParticleTracker\Method\Method.f90"/>
435437
<File RelativePath="..\src\Solution\ParticleTracker\Method\MethodCell.f90"/>
436438
<File RelativePath="..\src\Solution\ParticleTracker\Method\MethodCellPassToBot.f90"/>
Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,16 @@
11
module CellModule
22

33
use CellDefnModule, only: CellDefnType
4+
use DomainModule, only: DomainType
45
use KindModule, only: I4B
56
implicit none
67
private
78
public :: CellType
89

910
!> @brief Base type for grid cells of a concrete type. Contains
1011
!! a cell-definition which is information shared by cell types.
11-
type, abstract :: CellType
12-
character(len=40), pointer :: type ! tracking domain type
12+
type, abstract, extends(DomainType) :: CellType
1313
type(CellDefnType), pointer :: defn => null() ! cell defn
14-
contains
15-
procedure(destroy), deferred :: destroy !< destroy the cell
1614
end type CellType
1715

18-
abstract interface
19-
subroutine destroy(this)
20-
import CellType
21-
class(CellType), intent(inout) :: this
22-
end subroutine
23-
end interface
24-
2516
end module CellModule
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module DomainModule
2+
3+
implicit none
4+
private
5+
public :: DomainType
6+
7+
!> @brief A tracking domain.
8+
type, abstract :: DomainType
9+
character(len=40), pointer :: type !< character string that names the tracking domain type
10+
contains
11+
procedure(destroy), deferred :: destroy !< destructor
12+
end type DomainType
13+
14+
abstract interface
15+
subroutine destroy(this)
16+
import DomainType
17+
class(DomainType), intent(inout) :: this
18+
end subroutine
19+
end interface
20+
21+
end module DomainModule

src/Solution/ParticleTracker/Domain/Subcell.f90

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
11
module SubcellModule
22

33
use CellDefnModule, only: CellDefnType
4+
use DomainModule, only: DomainType
45
implicit none
56
private
67
public :: SubcellType
78

89
!> @brief A subcell of a cell.
9-
type, abstract :: SubcellType
10-
private
11-
character(len=40), pointer, public :: type !< character string that names the tracking domain type
10+
type, abstract, extends(DomainType) :: SubcellType
1211
integer, public :: isubcell !< index of subcell in the cell
1312
integer, public :: icell !< index of cell in the source grid
1413
contains
15-
procedure(destroy), deferred :: destroy !< destructor
1614
procedure(init), deferred :: init !< initializer
1715
end type SubcellType
1816

1917
abstract interface
20-
subroutine destroy(this)
21-
import SubcellType
22-
class(SubcellType), intent(inout) :: this
23-
end subroutine
24-
2518
subroutine init(this)
2619
import SubcellType
2720
class(SubcellType), intent(inout) :: this
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module ExitSolutionModule
2+
3+
use KindModule, only: I4B, DP, LGP
4+
use ConstantsModule, only: DZERO
5+
6+
implicit none
7+
8+
!> @brief Exit status codes
9+
enum, bind(C)
10+
enumerator :: OK_EXIT = 0 !< exit found using velocity interpolation
11+
! below only used for linear interp
12+
enumerator :: OK_EXIT_CONSTANT = 1 !< exit found, constant velocity
13+
enumerator :: NO_EXIT_STATIONARY = 2 !< no exit, zero velocity
14+
enumerator :: NO_EXIT_NO_OUTFLOW = 3 !< no exit, no outflow
15+
end enum
16+
17+
!> @brief Base type for exit solutions
18+
type :: ExitSolutionType
19+
integer(I4B) :: status = -1 !< domain exit status code
20+
integer(I4B) :: iboundary = 0 !< boundary number
21+
real(DP) :: dt = 1.0d+20 !< time to exit
22+
end type ExitSolutionType
23+
24+
!> @brief Linear velocity interpolation exit solution
25+
type, extends(ExitSolutionType) :: LinearExitSolutionType
26+
real(DP) :: v = DZERO !< particle velocity
27+
real(DP) :: dvdx = DZERO !< velocity gradient
28+
end type LinearExitSolutionType
29+
30+
end module ExitSolutionModule

src/Solution/ParticleTracker/Method/Method.f90

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ module MethodModule
2020
use CellDefnModule, only: CellDefnType
2121
use TimeSelectModule, only: TimeSelectType
2222
use MathUtilModule, only: is_close
23+
use DomainModule, only: DomainType
24+
use ExitSolutionModule, only: ExitSolutionType
25+
use ListModule, only: ListType
2326
implicit none
2427

2528
public :: LEVEL_MODEL, LEVEL_FEATURE, LEVEL_SUBFEATURE
@@ -68,10 +71,12 @@ module MethodModule
6871
procedure(apply), deferred :: apply !< apply the method to the particle
6972
procedure(assess), deferred :: assess !< assess conditions before tracking
7073
procedure(deallocate), deferred :: deallocate !< deallocate the method object
74+
procedure :: get_level !< get the tracking method level
7175
! Overridden in subtypes that delegate
7276
procedure :: pass !< pass the particle to the next subdomain
7377
procedure :: load !< load the subdomain tracking method
74-
procedure :: get_level !< get the tracking method level
78+
procedure :: find_exits !< find domain exit solutions
79+
procedure :: pick_exit
7580
! Implemented here
7681
procedure :: init
7782
procedure :: track
@@ -111,6 +116,7 @@ end subroutine deallocate
111116

112117
contains
113118

119+
!> @brief Initialize the method with pointers to model data.
114120
subroutine init(this, fmi, cell, subcell, events, tracktimes, &
115121
izone, flowja, porosity, retfactor)
116122
class(MethodType), intent(inout) :: this
@@ -178,7 +184,15 @@ subroutine try_pass(this, particle, nextlevel, advancing)
178184
end if
179185
end subroutine try_pass
180186

181-
!> @brief Load the subdomain tracking method (submethod).
187+
!> @brief Get tracking method level.
188+
function get_level(this) result(level)
189+
class(MethodType), intent(in) :: this
190+
integer(I4B) :: level
191+
level = -1 ! suppress compiler warning
192+
call pstop(1, "get_level must be overridden")
193+
end function get_level
194+
195+
!> @brief Load subdomain tracking method (submethod).
182196
subroutine load(this, particle, next_level, submethod)
183197
class(MethodType), intent(inout) :: this
184198
type(ParticleType), pointer, intent(inout) :: particle
@@ -187,22 +201,35 @@ subroutine load(this, particle, next_level, submethod)
187201
call pstop(1, "load must be overridden")
188202
end subroutine load
189203

190-
!> @brief Get the tracking method's level.
191-
function get_level(this) result(level)
192-
class(MethodType), intent(in) :: this
193-
integer(I4B) :: level
194-
level = -1 ! suppress compiler warning
195-
call pstop(1, "get_level must be overridden")
196-
end function get_level
197-
198-
!> @brief Pass the particle to the next subdomain.
204+
!> @brief Pass particle to the next subdomain or to a domain boundary.
199205
subroutine pass(this, particle)
200206
class(MethodType), intent(inout) :: this
201207
type(ParticleType), pointer, intent(inout) :: particle
202208
call pstop(1, "pass must be overridden")
203209
end subroutine pass
204210

205-
!> @brief Particle is released.
211+
!> @brief Compute candidate exit solutions.
212+
subroutine find_exits(this, particle, domain)
213+
class(MethodType), intent(inout) :: this
214+
type(ParticleType), pointer, intent(inout) :: particle
215+
class(DomainType), intent(in) :: domain
216+
if (.not. this%delegates) &
217+
call pstop(1, "find_exits called on non-delegating method")
218+
call pstop(1, "find_exits must be overridden in delegating methods")
219+
end subroutine find_exits
220+
221+
!> @brief Choose an exit solution among candidates.
222+
function pick_exit(this, particle) result(exit_soln)
223+
class(MethodType), intent(inout) :: this
224+
type(ParticleType), pointer, intent(inout) :: particle
225+
integer(I4B) :: exit_soln
226+
exit_soln = 0 ! suppress compiler warning
227+
if (.not. this%delegates) &
228+
call pstop(1, "pick_exit called on non-delegating method")
229+
call pstop(1, "pick_exit must be overridden in delegating methods")
230+
end function pick_exit
231+
232+
!> @brief A particle is released.
206233
subroutine release(this, particle)
207234
class(MethodType), intent(inout) :: this
208235
type(ParticleType), pointer, intent(inout) :: particle
@@ -212,7 +239,7 @@ subroutine release(this, particle)
212239
deallocate (event)
213240
end subroutine release
214241

215-
!> @brief Particle terminates.
242+
!> @brief A particle terminates.
216243
subroutine terminate(this, particle, status)
217244
class(MethodType), intent(inout) :: this
218245
type(ParticleType), pointer, intent(inout) :: particle
@@ -225,7 +252,7 @@ subroutine terminate(this, particle, status)
225252
deallocate (event)
226253
end subroutine terminate
227254

228-
!> @brief Time step ends.
255+
!> @brief A time step ends.
229256
subroutine timestep(this, particle)
230257
class(MethodType), intent(inout) :: this
231258
type(ParticleType), pointer, intent(inout) :: particle
@@ -235,7 +262,7 @@ subroutine timestep(this, particle)
235262
deallocate (event)
236263
end subroutine timestep
237264

238-
!> @brief Particle leaves a weak sink.
265+
!> @brief A particle leaves a weak sink.
239266
subroutine weaksink(this, particle)
240267
class(MethodType), intent(inout) :: this
241268
type(ParticleType), pointer, intent(inout) :: particle
@@ -245,7 +272,7 @@ subroutine weaksink(this, particle)
245272
deallocate (event)
246273
end subroutine weaksink
247274

248-
!> @brief User-defined tracking time occurs.
275+
!> @brief A user-defined tracking time occurs.
249276
subroutine usertime(this, particle)
250277
class(MethodType), intent(inout) :: this
251278
type(ParticleType), pointer, intent(inout) :: particle

src/Solution/ParticleTracker/Method/MethodSubcell.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module MethodSubcellModule
1010
private
1111
public :: MethodSubcellType
1212

13+
!> @brief Abstract base type for subcell tracking methods
1314
type, abstract, extends(MethodCellType) :: MethodSubcellType
1415
contains
1516
procedure, public :: assess
@@ -19,6 +20,7 @@ module MethodSubcellModule
1920

2021
contains
2122

23+
!> @brief Assess conditions before tracking
2224
subroutine assess(this, particle, cell_defn, tmax)
2325
! dummy
2426
class(MethodSubcellType), intent(inout) :: this

0 commit comments

Comments
 (0)