28 real(dp),
allocatable,
public :: qextl1(:), qextl2(:), qintl(:)
46 method%subcell => subcell
47 method%name => method%subcell%type
48 method%delegates = .false.
54 deallocate (this%name)
62 real(DP),
intent(in) :: tmax
70 select type (subcell => this%subcell)
76 x_origin = subcell%xOrigin
77 y_origin = subcell%yOrigin
78 z_origin = subcell%zOrigin
79 sinrot = subcell%sinrot
80 cosrot = subcell%cosrot
81 call particle%transform(x_origin, y_origin)
82 call this%track_subcell(subcell, particle, tmax)
83 call particle%transform(x_origin, y_origin, invert=.true.)
101 real(DP),
intent(in) :: tmax
103 real(DP) :: dt, dtexit, texit
104 real(DP) :: t, x, y, z
105 real(DP) :: t0, x0, y0, z0
106 integer(I4B) :: i, exit_face, exit_soln
113 call find_exits(particle, subcell, exit_solutions, x0, y0, z0)
114 exit_x = exit_solutions(1)
115 exit_y = exit_solutions(2)
116 exit_z = exit_solutions(3)
120 if (exit_soln == 0)
then
124 exit_face = exit_solutions(exit_soln)%iboundary
125 dtexit = exit_solutions(exit_soln)%dt
127 texit = particle%ttrack + dtexit
149 call this%tracktimes%advance()
150 if (this%tracktimes%any())
then
151 do i = this%tracktimes%selection(1), this%tracktimes%selection(2)
152 t = this%tracktimes%times(i)
153 if (t < particle%ttrack) cycle
154 if (t > texit .or. t > tmax)
exit
156 x =
new_x(exit_x%v, exit_x%dvdx, subcell%vx1, subcell%vx2, &
157 dt, x0, subcell%dx, exit_x%status == 1)
158 y =
new_x(exit_y%v, exit_y%dvdx, subcell%vy1, subcell%vy2, &
159 dt, y0, subcell%dy, exit_y%status == 1)
160 z =
new_x(exit_z%v, exit_z%dvdx, subcell%vz1, subcell%vz2, &
161 dt, z0, subcell%dz, exit_z%status == 1)
162 particle%x = x * subcell%dx
163 particle%y = y * subcell%dy
164 particle%z = z * subcell%dz
167 call this%usertime(particle)
173 if (texit .gt. tmax)
then
176 x =
new_x(exit_x%v, exit_x%dvdx, subcell%vx1, subcell%vx2, &
177 dt, x0, subcell%dx, exit_x%status == 1)
178 y =
new_x(exit_y%v, exit_y%dvdx, subcell%vy1, subcell%vy2, &
179 dt, y0, subcell%dy, exit_y%status == 1)
180 z =
new_x(exit_z%v, exit_z%dvdx, subcell%vz1, subcell%vz2, &
181 dt, z0, subcell%dz, exit_z%status == 1)
184 particle%advancing = .false.
185 particle%x = x * subcell%dx
186 particle%y = y * subcell%dy
187 particle%z = z * subcell%dz
190 call this%timestep(particle)
199 if ((exit_face .eq. 1) .or. (exit_face .eq. 2))
then
201 y =
new_x(exit_y%v, exit_y%dvdx, subcell%vy1, subcell%vy2, &
202 dt, y0, subcell%dy, exit_y%status == 1)
203 z =
new_x(exit_z%v, exit_z%dvdx, subcell%vz1, subcell%vz2, &
204 dt, z0, subcell%dz, exit_z%status == 1)
205 if (exit_face .eq. 2) x =
done
206 else if ((exit_face .eq. 3) .or. (exit_face .eq. 4))
then
207 x =
new_x(exit_x%v, exit_x%dvdx, subcell%vx1, subcell%vx2, dt, &
208 x0, subcell%dx, exit_x%status == 1)
210 z =
new_x(exit_z%v, exit_z%dvdx, subcell%vz1, subcell%vz2, dt, &
211 z0, subcell%dz, exit_z%status == 1)
212 if (exit_face .eq. 4) y =
done
213 else if ((exit_face .eq. 5) .or. (exit_face .eq. 6))
then
214 x =
new_x(exit_x%v, exit_x%dvdx, subcell%vx1, subcell%vx2, &
215 dt, x0, subcell%dx, exit_x%status == 1)
216 y =
new_x(exit_y%v, exit_y%dvdx, subcell%vy1, subcell%vy2, &
217 dt, y0, subcell%dy, exit_y%status == 1)
219 if (exit_face .eq. 6) z =
done
221 print *,
"programmer error, invalid exit face", exit_face
224 particle%x = x * subcell%dx
225 particle%y = y * subcell%dy
226 particle%z = z * subcell%dz
229 call this%subcellexit(particle)
236 integer(I4B) :: exit_soln
243 if (exit_solutions(1)%status < 2)
then
245 dtmin = exit_solutions(1)%dt
247 if (exit_solutions(2)%status < 2 .and. &
248 exit_solutions(2)%dt < dtmin)
then
250 dtmin = exit_solutions(2)%dt
252 if (exit_solutions(3)%status < 2 .and. &
253 exit_solutions(3)%dt < dtmin)
then
260 subroutine find_exits(particle, domain, exit_solutions, x0, y0, z0)
264 real(DP),
intent(out) :: x0, y0, z0
269 x0 = particle%x / domain%dx
270 y0 = particle%y / domain%dy
271 z0 = particle%z / domain%dz
275 find_exit(domain%vx1, domain%vx2, domain%dx, x0), &
276 find_exit(domain%vy1, domain%vy2, domain%dy, y0), &
277 find_exit(domain%vz1, domain%vz2, domain%dz, z0) &
281 if (exit_solutions(1)%v <
dzero)
then
282 exit_solutions(1)%iboundary = 1
283 else if (exit_solutions(1)%v >
dzero)
then
284 exit_solutions(1)%iboundary = 2
286 if (exit_solutions(2)%v <
dzero)
then
287 exit_solutions(2)%iboundary = 3
288 else if (exit_solutions(2)%v >
dzero)
then
289 exit_solutions(2)%iboundary = 4
291 if (exit_solutions(3)%v <
dzero)
then
292 exit_solutions(3)%iboundary = 5
293 else if (exit_solutions(3)%v >
dzero)
then
294 exit_solutions(3)%iboundary = 6
302 real(dp),
intent(in) :: v1
303 real(dp),
intent(in) :: v2
304 real(dp),
intent(in) :: dx
305 real(dp),
intent(in) :: xl
310 solution%v, solution%dvdx, solution%dt)
330 integer(I4B) :: status
346 logical(LGP) :: nooutflow
352 if (v2a .lt.
dzero) v2a = -v2a
354 if (v1a .lt.
dzero) v1a = -v1a
357 if (dva .lt.
dzero) dva = -dva
362 if ((v2a .lt. tol) .and. (v1a .lt. tol))
then
373 if (v2a .gt. vv) vv = v2a
375 if (vvv .lt. 1.0d-4)
then
380 if (v1 .gt. zro) dt = (dx - x) / v1
381 if (v1 .lt. zrom) dt = -x / v1
390 v = (
done - xl) * v1 + xl * v2
395 if (v1 .lt.
dzero) nooutflow = .false.
396 if (v2 .gt.
dzero) nooutflow = .false.
406 if ((v1 .le.
dzero) .and. (v2 .ge.
dzero))
then
407 if (abs(v) .le.
dzero)
then
409 if (v2 .le.
dzero) v = -v
419 if (vr .le.
dzero)
then
427 if (v1v2 .gt.
dzero)
then
428 if (v .gt.
dzero) vr = vr2
429 if (v .lt.
dzero) vr = vr1
434 if (dabs(vr) .lt. 1.0d-10)
then
454 pure function new_x(v, dvdx, v1, v2, dt, x, dx, velocity_profile)
result(newx)
456 real(dp),
intent(in) :: v
457 real(dp),
intent(in) :: dvdx
458 real(dp),
intent(in) :: v1
459 real(dp),
intent(in) :: v2
460 real(dp),
intent(in) :: dt
461 real(dp),
intent(in) :: x
462 real(dp),
intent(in) :: dx
463 logical(LGP),
intent(in),
optional :: velocity_profile
466 logical(LGP) :: lprofile
469 if (
present(velocity_profile))
then
470 lprofile = velocity_profile
478 newx = newx + (v1 * dt / dx)
479 else if (v .ne.
dzero)
then
480 newx = newx + (v * (exp(dvdx * dt) -
done) / dvdx / dx)
This module contains simulation constants.
real(dp), parameter dzero
real constant zero
real(dp), parameter done
real constant 1
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
@ ok_exit_constant
exit found, constant velocity
@ ok_exit
exit found using velocity interpolation
@ no_exit_stationary
no exit, zero velocity
@ no_exit_no_outflow
no exit, no outflow
This module defines variable data types.
Particle tracking strategies.
@, public level_subfeature
subroutine find_exits(particle, domain, exit_solutions, x0, y0, z0)
Compute candidate exit solutions.
pure real(dp) function new_x(v, dvdx, v1, v2, dt, x, dx, velocity_profile)
Update a cell-local coordinate based on a time increment.
integer(i4b) function, public calculate_dt(v1, v2, dx, xL, v, dvdx, dt)
Calculate particle travel time to exit and exit status.
type(linearexitsolutiontype) function find_exit(v1, v2, dx, xL)
Find an exit solution for one dimension.
integer(i4b) function pick_exit(exit_solutions)
Pick the exit solution with the shortest travel time.
subroutine track_subcell(this, subcell, particle, tmax)
Track a particle across a rectangular subcell using Pollock's method.
subroutine, public create_method_subcell_pollock(method)
Create a new Pollock's subcell method.
subroutine apply_msp(this, particle, tmax)
Apply Pollock's method to a rectangular subcell.
@, public featexit
particle exited a grid feature
@, public timestep
time step ended
@ term_timeout
terminated at stop time or end of simulation
@ term_no_exits_sub
terminated in a subcell with no exit face
subroutine, public create_subcell_rect(subcell)
Create a new rectangular subcell.
Base type for grid cells of a concrete type. Contains a cell-definition which is information shared b...
Base type for exit solutions.
Linear velocity interpolation exit solution.
A generic heterogeneous doubly-linked list.
Abstract base type for subcell tracking methods.
Rectangular subcell tracking method.
Particle tracked by the PRT model.