Skip to content

Commit 0d5e743

Browse files
authored
fix(prt): fix drape behavior (MODFLOW-ORG#2824)
Fix the PRT PRP package's DRAPE option's behavior. A draped particle's release was previously reported in the original release position, followed by a "dropped" (ireason=6) event due to the particle reaching the water table at tracking time as a result of the default DRY_TRACKING_METHOD setting DROP. This is inconsistent with the intent of the DRAPE option: DRAPE is applied before release to control a particle's release position. Draped particles will now be released in the highest active cell. While this fix produces essentially identical pathlines (ignoring the release event and subsequent dropped event) as the previous logic, it is worth pointing out that PRT's DRAPE semantics diverge from MP7 in an important way: MP7 unconditionally calculates a particle release position's z coordinate with the given local z value, regardless whether the particle was draped. This means a draped particle may start beneath the water table if local z < 1. Whereas, PRT did previously and will continue to start draped particles at the water table in convertible cells. Both PRT and MP7 start draped particles at the geometric top of confined cells.
1 parent 9f92119 commit 0d5e743

4 files changed

Lines changed: 43 additions & 30 deletions

File tree

-560 Bytes
Binary file not shown.

autotest/test_prt_drape.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ def check_output(idx, test):
276276
)
277277

278278
if drape:
279-
assert mf6_pls.shape[0] == 36
279+
assert mf6_pls.shape[0] == 27
280+
assert mf6_pls[mf6_pls.ireason == 6].empty
280281
else:
281282
# expect no movement without drape
282283
assert mf6_pls.shape[0] == 9

doc/ReleaseNotes/develop.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,8 @@ description = "Fix an indexing issue in structured NetCDF export where READASARR
6868
section = "fixes"
6969
subsection = "basic"
7070
description = "Stop with an informative error if a discretization package is missing after loading the model input file's PACKAGES block."
71+
72+
[[items]]
73+
section = "fixes"
74+
subsection = "model"
75+
description = "Fix the PRT PRP package's DRAPE option's behavior. A draped particle's release was previously reported in the original release position, followed by a DROPPED (ireason=6) event due to the particle reaching the water table at tracking time as a result of the default DRY\\_TRACKING\\_METHOD setting DROP. This is inconsistent with the intent of the DRAPE option: DRAPE is applied before release to control a particle's release position. Draped particles will now be released in the highest active cell, at the water table if the cell is convertible or at the geometric top if the cell is confined, and no DROPPED event will be reported."

src/Model/ParticleTracking/prt-prp.f90

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ subroutine initialize_particle(this, particle, ip, trelease)
605605
integer(I4B), intent(in) :: ip !< particle index
606606
real(DP), intent(in) :: trelease !< release time
607607
! local
608+
logical(LGP) :: draped
608609
integer(I4B) :: irow, icol, ilay, icpl
609610
integer(I4B) :: ic, icu, ic_old
610611
real(DP) :: x, y, z
@@ -617,7 +618,6 @@ subroutine initialize_particle(this, particle, ip, trelease)
617618
&Make sure a GWFGRID entry is configured in the PRT FMI package.')"
618619

619620
ic = this%rptnode(ip)
620-
icu = this%dis%get_nodeuser(ic)
621621

622622
call create_particle(particle)
623623

@@ -631,25 +631,18 @@ subroutine initialize_particle(this, particle, ip, trelease)
631631
particle%istopweaksink = this%istopweaksink
632632
particle%istopzone = this%istopzone
633633
particle%idrymeth = this%idrymeth
634-
particle%icu = icu
635-
636-
select type (dis => this%dis)
637-
type is (DisType)
638-
call get_ijk(icu, dis%nrow, dis%ncol, dis%nlay, irow, icol, ilay)
639-
type is (DisvType)
640-
call get_jk(icu, dis%ncpl, dis%nlay, icpl, ilay)
641-
end select
642-
particle%ilay = ilay
643-
particle%izone = this%rptzone(ic)
644634
particle%istatus = 0 ! status 0 until tracking starts
635+
645636
! If the cell is inactive, either drape the particle
646637
! to the top-most active cell beneath it if drape is
647638
! enabled, or else terminate permanently unreleased.
639+
draped = .false.
648640
if (this%ibound(ic) == 0) then
649641
ic_old = ic
650642
if (this%drape) then
651643
call this%dis%highest_active(ic, this%ibound)
652-
if (ic == ic_old .or. this%ibound(ic) == 0) then
644+
draped = ic /= ic_old
645+
if (.not. draped .and. this%ibound(ic) == 0) then
653646
! negative unreleased status signals to the
654647
! tracking method that we haven't yet saved
655648
! a termination record, it needs to do so.
@@ -660,24 +653,35 @@ subroutine initialize_particle(this, particle, ip, trelease)
660653
end if
661654
end if
662655

663-
! load coordinates
664-
x = this%rptx(ip)
665-
y = this%rpty(ip)
666-
if (this%localz) then
667-
! make sure FMI has cell type array. we need
668-
! it to distinguish convertible and confined
669-
! cells if release z coordinates are local
670-
if (this%fmi%igwfceltyp /= 1) then
671-
write (errmsg, fmticterr) trim(this%text)
672-
call store_error(errmsg, terminate=.TRUE.)
673-
end if
656+
icu = this%dis%get_nodeuser(ic)
657+
particle%icu = icu
658+
select type (dis => this%dis)
659+
type is (DisType)
660+
call get_ijk(icu, dis%nrow, dis%ncol, dis%nlay, irow, icol, ilay)
661+
type is (DisvType)
662+
call get_jk(icu, dis%ncpl, dis%nlay, icpl, ilay)
663+
end select
664+
particle%ilay = ilay
665+
particle%izone = this%rptzone(ic)
666+
667+
! if the particle was draped, override the release z coord and
668+
! set it to the saturated top of the cell. this puts a draped
669+
! a draped particle at the water table for a convertible cell
670+
! or at the geometric cell top for a confined cell. if it was
671+
! not draped and localz is enabled, calculate a model z coord
672+
! using the geometric cell top if the cell is confined or the
673+
! water table as the effective top if the cell is convertible.
674+
if (draped) then
675+
z = this%fmi%dis%bot(ic) + &
676+
this%fmi%gwfsat(ic) * &
677+
(this%fmi%dis%top(ic) - this%fmi%dis%bot(ic))
678+
else if (this%localz) then
679+
! TODO: is this sufficient instead of the below??
680+
! z = this%fmi%dis%bot(ic) + &
681+
! this%rptz(ip) * &
682+
! this%fmi%gwfsat(ic) * &
683+
! (this%fmi%dis%top(ic) - this%fmi%dis%bot(ic))
674684

675-
! calculate model z coord from local z coord.
676-
! if cell is confined (icelltype == 0) use the
677-
! actual cell height (geometric top - bottom).
678-
! otherwise use head as cell top, clamping to
679-
! the cell bottom if head is below the bottom
680-
! and to geometric cell top if head is above top
681685
top = this%fmi%dis%top(ic)
682686
bot = this%fmi%dis%bot(ic)
683687
if (this%fmi%gwfceltyp(icu) /= 0) then
@@ -690,6 +694,9 @@ subroutine initialize_particle(this, particle, ip, trelease)
690694
z = this%rptz(ip)
691695
end if
692696

697+
x = this%rptx(ip)
698+
y = this%rpty(ip)
699+
693700
if (this%ichkmeth > 0) &
694701
call this%validate_release_point(ic, x, y, z)
695702

0 commit comments

Comments
 (0)