src default routines¶
See also Using src for source terms.
For GeoClaw, see src routine in GeoClaw.
Below are the default src library routines for Classic and AMRClaw. By default these do nothing. If you wish to specify source terms, you need to copy one of these files to your application directory and modify it as needed. Remember to change to Makefile to point to the proper version.
If you are using AMRClaw, you will also need to provide a routine src1d, see Using src1d for source terms with AMRClaw.
$CLAW/classic/src/1d/src1.f90:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | subroutine src1(meqn,mbc,mx,xlower,dx,q,maux,aux,t,dt)
! Called to update q by solving source term equation
! $q_t = \psi(q)$ over time dt starting at time t.
!
! This default version does nothing.
implicit none
integer, intent(in) :: mbc,mx,meqn,maux
real(kind=8), intent(in) :: xlower,dx,t,dt
real(kind=8), intent(in) :: aux(maux,1-mbc:mx+mbc)
real(kind=8), intent(inout) :: q(meqn,1-mbc:mx+mbc)
end subroutine src1
|
$CLAW/classic/src/2d/src2.f90:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | subroutine src2(meqn,mbc,mx,my,xlower,ylower,dx,dy,q,maux,aux,t,dt)
! Called to update q by solving source term equation
! $q_t = \psi(q)$ over time dt starting at time t.
!
! This default version does nothing.
implicit none
integer, intent(in) :: mbc,mx,my,meqn,maux
real(kind=8), intent(in) :: xlower,ylower,dx,dy,t,dt
real(kind=8), intent(in) :: aux(maux,1-mbc:mx+mbc,1-mbc:my+mbc)
real(kind=8), intent(inout) :: q(meqn,1-mbc:mx+mbc,1-mbc:my+mbc)
end subroutine src2
|
$CLAW/classic/src/3d/src3.f90:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | subroutine src3(meqn,mbc,mx,my,mz,xlower,ylower,zlower,dx,dy,dz,q,maux,aux,t,dt)
! Called to update q by solving source term equation
! $q_t = \psi(q)$ over time dt starting at time t.
!
! This default version does nothing.
implicit none
integer, intent(in) :: meqn,mbc,mx,my,mz,maux
real(kind=8), intent(in) :: xlower,ylower,zlower,dx,dy,dz,t,dt
double precision, intent(in) :: aux(maux,1-mbc:mx+mbc,1-mbc:my+mbc)
double precision, intent(inout) :: q(meqn,1-mbc:mx+mbc,1-mbc:my+mbc)
end subroutine src3
|
src routine in GeoClaw¶
In GeoClaw, there is a library routine to impose source terms for bottom friction (via a Manning term) and Coriolis terms. The topography source term is built into the Riemann solver in a manner that achieves well balancing (an ocean at rest remains at rest).
$CLAW/geoclaw/src/2d/shallow/src2.f90:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | subroutine src2(meqn,mbc,mx,my,xlower,ylower,dx,dy,q,maux,aux,t,dt)
use geoclaw_module, only: g => grav, coriolis_forcing, coriolis
use geoclaw_module, only: friction_forcing, friction_depth
use geoclaw_module, only: manning_coefficient
use geoclaw_module, only: manning_break, num_manning
use geoclaw_module, only: spherical_distance, coordinate_system
use geoclaw_module, only: RAD2DEG, pi, dry_tolerance
use storm_module, only: wind_forcing, pressure_forcing
use storm_module, only: rho_air, wind_drag, ambient_pressure
use storm_module, only: wind_index, pressure_index
use storm_module, only: storm_direction, storm_location
use friction_module, only: variable_friction, friction_index
implicit none
! Input parameters
integer, intent(in) :: meqn,mbc,mx,my,maux
double precision, intent(in) :: xlower,ylower,dx,dy,t,dt
! Output
double precision, intent(inout) :: q(meqn,1-mbc:mx+mbc,1-mbc:my+mbc)
double precision, intent(inout) :: aux(maux,1-mbc:mx+mbc,1-mbc:my+mbc)
! Locals
integer :: i, j, nman
real(kind=8) :: h, hu, hv, gamma, dgamma, y, fdt, a(2,2), coeff
real(kind=8) :: xm, xc, xp, ym, yc, yp, dx_meters, dy_meters
real(kind=8) :: u, v, hu0, hv0
real(kind=8) :: tau, wind_speed, theta, phi, psi, P_gradient(2), S(2)
real(kind=8) :: Ddt, sloc(2)
! Algorithm parameters
! Parameter controls when to zero out the momentum at a depth in the
! friction source term
real(kind=8), parameter :: depth_tolerance = 1.0d-30
! Physics
! Nominal density of water
real(kind=8), parameter :: rho = 1025.d0
! Friction source term
if (friction_forcing) then
do j=1,my
do i=1,mx
! Extract appropriate momentum
if (q(1,i,j) < depth_tolerance) then
q(2:3,i,j) = 0.d0
else
! Apply friction source term only if in shallower water
if (q(1,i,j) <= friction_depth) then
if (.not.variable_friction) then
do nman = num_manning, 1, -1
if (aux(1,i,j) .lt. manning_break(nman)) then
coeff = manning_coefficient(nman)
endif
enddo
else
coeff = aux(friction_index,i,j)
endif
! Calculate source term
gamma = sqrt(q(2,i,j)**2 + q(3,i,j)**2) * g &
* coeff**2 / (q(1,i,j)**(7.d0/3.d0))
dgamma = 1.d0 + dt * gamma
q(2, i, j) = q(2, i, j) / dgamma
q(3, i, j) = q(3, i, j) / dgamma
endif
endif
enddo
enddo
endif
! End of friction source term
! Coriolis source term
! TODO: May want to remove the internal calls to coriolis as this could
! lead to slow downs.
if (coriolis_forcing) then
do j=1,my
y = ylower + (j - 0.5d0) * dy
fdt = coriolis(y) * dt ! Calculate f dependent on coordinate system
! Calculate matrix components
a(1,1) = 1.d0 - 0.5d0 * fdt**2 + fdt**4 / 24.d0
a(1,2) = fdt - fdt**3 / 6.d0
a(2,1) = -fdt + fdt**3 / 6.d0
a(2,2) = a(1,1)
do i=1,mx
q(2,i,j) = q(2, i, j) * a(1,1) + q(3, i, j) * a(1,2)
q(3,i,j) = q(2, i, j) * a(2,1) + q(3, i, j) * a(2,2)
enddo
enddo
endif
! End of coriolis source term
! wind -----------------------------------------------------------
if (wind_forcing) then
! Need storm location and direction for sector based wind drag
sloc = storm_location(t)
theta = storm_direction(t)
do j=1,my
yc = ylower + (j - 0.5d0) * dy
do i=1,mx
xc = xlower + (i - 0.5d0) * dx
if (q(1,i,j) > dry_tolerance) then
psi = atan2(yc - sloc(2), xc - sloc(1))
if (theta > psi) then
phi = (2.d0 * pi - theta + psi) * RAD2DEG
else
phi = (psi - theta) * RAD2DEG
endif
wind_speed = sqrt(aux(wind_index,i,j)**2 &
+ aux(wind_index+1,i,j)**2)
tau = wind_drag(wind_speed, phi) * rho_air * wind_speed / rho
q(2,i,j) = q(2,i,j) + dt * tau * aux(wind_index,i,j)
q(3,i,j) = q(3,i,j) + dt * tau * aux(wind_index+1,i,j)
endif
enddo
enddo
endif
! ----------------------------------------------------------------
! Atmosphere Pressure --------------------------------------------
if (pressure_forcing) then
do j=1,my
ym = ylower + (j - 1.d0) * dy
yc = ylower + (j - 0.5d0) * dy
yp = ylower + j * dy
do i=1,mx
xm = xlower + (i - 1.d0) * dx
xc = xlower + (i - 0.5d0) * dx
xp = xlower + i * dx
if (coordinate_system == 2) then
! Convert distance in lat-long to meters
dx_meters = spherical_distance(xp,yc,xm,yc)
dy_meters = spherical_distance(xc,yp,xc,ym)
else
dx_meters = dx
dy_meters = dy
endif
! Extract depths
h = q(1,i,j)
! Calculate gradient of Pressure
P_gradient(1) = (aux(pressure_index,i+1,j) &
- aux(pressure_index,i-1,j)) / (2.d0 * dx_meters)
P_gradient(2) = (aux(pressure_index,i,j+1) &
- aux(pressure_index,i,j-1)) / (2.d0 * dy_meters)
! Modify momentum in each layer
if (h > dry_tolerance) then
q(2, i, j) = q(2, i, j) - dt * h * P_gradient(1) / rho
q(3, i, j) = q(3, i, j) - dt * h * P_gradient(2) / rho
end if
enddo
enddo
endif
end subroutine src2
|