Skip to content

Commit

Permalink
Fixed bug in slip output inconsistency (#17) (#38)
Browse files Browse the repository at this point in the history
* Moved slip updates to main ODE solver routine (#38) 

* Fixed bugs in time output, redone benchmark results
  • Loading branch information
martijnende authored Oct 2, 2019
1 parent a47a191 commit ef4b845
Show file tree
Hide file tree
Showing 20 changed files with 65,726 additions and 67,612 deletions.
55,193 changes: 27,083 additions & 28,110 deletions examples/notebooks/.ipynb_checkpoints/double_asperity-checkpoint.ipynb

Large diffs are not rendered by default.

11,421 changes: 5,740 additions & 5,681 deletions examples/notebooks/.ipynb_checkpoints/single_asperity-checkpoint.ipynb

Large diffs are not rendered by default.

55,193 changes: 27,083 additions & 28,110 deletions examples/notebooks/double_asperity.ipynb

Large diffs are not rendered by default.

11,421 changes: 5,740 additions & 5,681 deletions examples/notebooks/single_asperity.ipynb

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions src/derivs_all.f90
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ subroutine derivs(time,yt,dydt,pb)
double precision, intent(out) :: dydt(pb%neqs*pb%mesh%nn)

double precision, dimension(pb%mesh%nn) :: theta, theta2, sigma, tau, v, P
double precision, dimension(pb%mesh%nn) :: main_var, dmain_var
double precision, dimension(pb%mesh%nn) :: main_var, dmain_var, slip, dslip
double precision, dimension(pb%mesh%nn) :: dsigma_dt, dtau_dt, dth_dt, dth2_dt
double precision, dimension(pb%mesh%nn) :: dmu_dv, dmu_dtheta
double precision, dimension(pb%mesh%nn) :: tau_y, dP_dt, dtau_dP
Expand All @@ -54,7 +54,7 @@ subroutine derivs(time,yt,dydt,pb)
dummy2 = 1d0
tau_y = 0d0

call unpack(yt, theta, main_var, sigma, theta2, pb)
call unpack(yt, theta, main_var, sigma, theta2, slip, pb)

! SEISMIC: when thermal pressurisation is requested, update P and T,
! then calculate effective stress sigma_e = sigma - P
Expand Down Expand Up @@ -111,6 +111,9 @@ subroutine derivs(time,yt,dydt,pb)
! periodic loading
dtau_per = pb%Omper * pb%Aper * cos(pb%Omper*time)

! Rate of change of slip is simply the velocity
dslip = v

! SEISMIC: calculate radiation damping. For rate-and-state, dmu_dv and
! dmu_dtheta contain the partial derivatives of friction to V and theta,
! respectively. For the CNS model, these variables contain the partials of
Expand Down Expand Up @@ -151,7 +154,7 @@ subroutine derivs(time,yt,dydt,pb)
/ ( sigma*dmu_dv + pb%zimpedance )
endif

call pack(dydt, dth_dt, dmain_var, dsigma_dt, dth2_dt, pb)
call pack(dydt, dth_dt, dmain_var, dsigma_dt, dth2_dt, dslip, pb)

end subroutine derivs

Expand Down
3 changes: 2 additions & 1 deletion src/initialize.f90
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ subroutine init_all(pb)
call init_mesh(pb%mesh)

! number of equations
pb%neqs = 2 + pb%features%localisation
! Initial number of neqs is defined in problem_class.f90
pb%neqs = pb%neqs + pb%features%localisation
if (pb%features%stress_coupling == 1 .and. pb%mesh%dim == 2) then
pb%neqs = pb%neqs + 1
endif
Expand Down
5 changes: 3 additions & 2 deletions src/ode_rk45_2.f90
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ subroutine rkf45_d2(f, y, t, dtmax, rtol, atol, pb)
! UPDATE dt after successful step
dt = pb%dt_did
y_new = pb%rk45_2%y_new
e = pb%rk45_2%e
! e = pb%rk45_2%e
e = 0d0

do
! Increment loop counter
Expand All @@ -90,7 +91,7 @@ subroutine rkf45_d2(f, y, t, dtmax, rtol, atol, pb)
call rk45_step(f, y, t, dt, y_new, e, pb)
endif
! Calculate error
e_ratio = maxval(e / (rtol * abs(y_new) + atol)) + 1e-12
e_ratio = maxval(e / (rtol * abs(y_new) + atol + 1e-12)) + 1e-12
! Check for NaNs
if (isnan(e_ratio)) then
! Decimate step size and try again
Expand Down
5 changes: 4 additions & 1 deletion src/output.f90
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ end subroutine screen_write
subroutine time_write(pb)

use problem_class
use my_mpi, only: is_mpi_master
type (problem_type), intent(inout) :: pb

write(121,*) pb%time, pb%tmax
if (is_mpi_master()) write(121,*) pb%time, pb%dt_did

end subroutine time_write

Expand Down Expand Up @@ -279,6 +280,7 @@ subroutine ot_write(pb)
if (is_MPI_parallel()) then
! if "ic" station is in this processor
if (pb%ot%ic>0) then

open(pb%ot%unit,access='APPEND',status='old',iostat=ios)
if (ios>0) stop 'Fatal error: ot_write: Error opening a fort.18 file'
!JPA add test for the first time we try to open this file but it does not exist yet
Expand Down Expand Up @@ -307,6 +309,7 @@ subroutine ot_write(pb)
!JPA warning: ivmax outputs not implemented in parallel yet

else

if (.not.BIN_OUTPUT) then

if (OCTAVE_OUTPUT) then
Expand Down
2 changes: 1 addition & 1 deletion src/problem_class.f90
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ module problem_class
integer :: i_sigma_cpl=0, finite=0
! Friction properties
double precision, dimension(:), allocatable :: a, b, dc, v1, v2, mu_star, v_star, theta_star, coh, v_pl
integer :: itheta_law=1, i_rns_law=1, neqs=2
integer :: itheta_law=1, i_rns_law=1, neqs=3
! Elastic properties
double precision :: beta=0d0, smu=0d0, lam=0d0, D=0d0, H=0d0, zimpedance=0d0
! Periodic loading
Expand Down
11 changes: 9 additions & 2 deletions src/pyqdyn.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,13 +516,17 @@ def run(self, test=False, unit=False):


# Read QDYN output data
def read_output(self, mirror=False, read_ot=True, filename_ot="fort.18", read_ox=True, filename_ox="fort.19"):
def read_output(self, mirror=False, read_ot=True, filename_ot="fort.18",
read_ox=True, filename_ox="fort.19", filename_time="fort.121"):

# If a suffix is specified (optional), change file names
suffix = self.set_dict["SUFFIX"]
if suffix != "":
filename_ot = "%s_%s" % (filename_ot, suffix)
filename_ox = "%s_%s" % (filename_ox, suffix)
filename_time = "%s_%s" % (filename_time, suffix)

time_data = read_csv(filename_time, header=None, names=("t", "dt"), delim_whitespace=True)

# Default number of header lines
nheaders = 6
Expand All @@ -539,7 +543,10 @@ def read_output(self, mirror=False, read_ot=True, filename_ot="fort.18", read_ox

# If time series data is requested
if read_ot:
data = read_csv(filename_ot, header=nheaders, names=cols, delim_whitespace=True)
# Read time series data
data = read_csv(filename_ot, header=None, skiprows=6, names=cols, delim_whitespace=True)
# Replace (less precise) time values
data["t"] = time_data["t"]
self.ot = data # Store data in self.ot

# Check if time series output was requested for other fault elements
Expand Down
35 changes: 24 additions & 11 deletions src/solver.f90
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module solver
!
subroutine solve(pb)

use output, only : screen_init, screen_write, ox_write, ot_write
use output, only : screen_init, screen_write, ox_write, ot_write, time_write
use my_mpi, only : is_MPI_parallel, is_mpi_master, finalize_mpi

type(problem_type), intent(inout) :: pb
Expand Down Expand Up @@ -56,11 +56,13 @@ subroutine solve(pb)
endif
! if (is_mpi_master()) call ox_write(pb)
if (mod(pb%it, pb%ot%ntout) == 0 .and. pb%it /= pb%itstop) then
call time_write(pb)
call ot_write(pb)
endif
enddo

! Write data for last step
call time_write(pb)
call screen_write(pb)
call ox_write(pb)
call ot_write(pb)
Expand All @@ -83,13 +85,14 @@ subroutine do_bsstep(pb)
use ode_bs
use ode_rk45, only: rkf45_d
use ode_rk45_2, only: rkf45_d2
use output, only : screen_write, ox_write, ot_write
use output, only : screen_write, ox_write, ot_write, time_write
use constants, only : SOLVER_TYPE
use diffusion_solver, only : update_PT_final

type(problem_type), intent(inout) :: pb

double precision, dimension(pb%neqs*pb%mesh%nn) :: yt, dydt, yt_scale
double precision, dimension(pb%neqs*pb%mesh%nn) :: yt_prev
double precision, dimension(pb%mesh%nn) :: main_var
double precision :: t_out
integer :: ik, neqs
Expand All @@ -103,7 +106,8 @@ subroutine do_bsstep(pb)
main_var = pb%v
endif

call pack(yt, pb%theta, main_var, pb%sigma, pb%theta2, pb)
call pack(yt, pb%theta, main_var, pb%sigma, pb%theta2, pb%slip, pb)
yt_prev = yt

! SEISMIC: user-defined switch to use either (1) the Bulirsch-Stoer method, or
! the (2) Runge-Kutta-Fehlberg method
Expand Down Expand Up @@ -135,34 +139,43 @@ subroutine do_bsstep(pb)
pb%rk45%iflag = -2 ! Reset to one-step mode each call
pb%t_prev = pb%time

100 continue

! Call Runge-Kutta solver routine
call rkf45_d( derivs_rk45, neqs, yt, pb%time, pb%tmax, &
pb%acc, 0d0, pb%rk45%iflag, pb%rk45%work, pb%rk45%iwork)

! Set time step
pb%dt_did = pb%time - pb%t_prev

! Basic error checking. See description of rkf45_d in ode_rk45.f90 for details
select case (pb%rk45%iflag)
case (3)
write (6,*) "RK45 error [3]: relative error tolerance too small"
stop
case (4)
! write (6,*) "RK45 warning [4]: integration took more than 3000 derivative evaluations"
write (6,*) "RK45 warning [4]: integration took more than 3000 derivative evaluations"
yt = yt_prev
goto 100
case (5)
write (6,*) "RK45 error [5]: solution vanished, relative error test is not possible"
stop
case (6)
write (6,*) "RK45 error [6]: requested accuracy could not be achieved"
stop
case (8)
call time_write(pb)
call ot_write(pb)
call screen_write(pb)
call ox_write(pb)
write (6,*) "RK45 error [8]: invalid input parameters"
stop
end select

! Set time step
pb%dt_did = pb%time - pb%t_prev

if (pb%dt_did < 1e-12) then
write(6,*) pb%dt_did
endif

elseif (SOLVER_TYPE == 3) then
! Set-up Runge-Kutta solver
pb%t_prev = pb%time
Expand All @@ -178,7 +191,7 @@ subroutine do_bsstep(pb)

iktotal=ik+iktotal

call unpack(yt, pb%theta, main_var, pb%sigma, pb%theta2, pb)
call unpack(yt, pb%theta, main_var, pb%sigma, pb%theta2, pb%slip, pb)
if (pb%features%tp == 1) call update_PT_final(pb%dt_did, pb)

! SEISMIC: retrieve the solution for tau in the case of the CNS model, else
Expand Down Expand Up @@ -223,7 +236,7 @@ subroutine update_field(pb)
! Update slip
! SEISMIC NOTE: slip needs to be calculated after velocity!
! NOTE 2: include slip in solver routine to get higher order accuracy
pb%slip = pb%slip + pb%v*pb%dt_did
! pb%slip = pb%slip + pb%v*pb%dt_did

! update potency and potency rate

Expand Down Expand Up @@ -276,7 +289,7 @@ subroutine check_stop(pb)

! STOP if time > tmax
case (0)
if (is_mpi_master()) call time_write(pb)
! if (is_mpi_master()) call time_write(pb)
if (pb%time >= pb%tmax) pb%itstop = pb%it

! STOP soon after end of slip localization
Expand Down Expand Up @@ -331,7 +344,7 @@ subroutine init_rk45(pb)
main_var = pb%v
endif

call pack(yt, pb%theta, main_var, pb%sigma, pb%theta2, pb)
call pack(yt, pb%theta, main_var, pb%sigma, pb%theta2, pb%slip, pb)

call rkf45_d( derivs_rk45, pb%neqs*pb%mesh%nn, yt, pb%time, pb%time, &
pb%acc, 0d0, pb%rk45%iflag, pb%rk45%work, pb%rk45%iwork)
Expand Down
17 changes: 11 additions & 6 deletions src/utils.f90
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,25 @@ module utils
! dv/dt or dtau/dt = dydt(2::pb%neqs)
! + feature specific variables
!===============================================================================
subroutine pack(yt, theta, main_var, sigma, theta2, pb)
subroutine pack(yt, theta, main_var, sigma, theta2, slip, pb)

type(problem_type), intent(inout) :: pb
double precision, dimension(pb%neqs*pb%mesh%nn), intent(out) :: yt
double precision, dimension(pb%mesh%nn), intent(in) :: theta, main_var, sigma
double precision, dimension(pb%mesh%nn), intent(in) :: theta2
double precision, dimension(pb%mesh%nn), intent(in) :: theta2, slip
integer :: nmax, ind_stress_coupling, ind_localisation, ind_tp

! pb%neqs is defined in problem_class.f90
nmax = pb%neqs*pb%mesh%nn
! Define the indices of yt and dydt based on which
! features are requested (defined in input file)
ind_stress_coupling = 2 + pb%features%stress_coupling
ind_stress_coupling = 3 + pb%features%stress_coupling
ind_localisation = ind_stress_coupling + pb%features%localisation
ind_tp = ind_localisation + pb%features%tp

yt(1:nmax:pb%neqs) = theta
yt(2:nmax:pb%neqs) = main_var
yt(3:nmax:pb%neqs) = slip

if (pb%features%stress_coupling == 1) then
yt(ind_stress_coupling:nmax:pb%neqs) = sigma
Expand All @@ -53,20 +55,23 @@ end subroutine pack
!===============================================================================
! Helper routine to unpack variables from solver
!===============================================================================
subroutine unpack(yt, theta, main_var, sigma, theta2, pb)
subroutine unpack(yt, theta, main_var, sigma, theta2, slip, pb)

type(problem_type), intent(inout) :: pb
double precision, dimension(pb%neqs*pb%mesh%nn), intent(in) :: yt
double precision, dimension(pb%mesh%nn) :: theta, main_var, sigma, theta2
double precision, dimension(pb%mesh%nn) :: theta, main_var, sigma
double precision, dimension(pb%mesh%nn) :: theta2, slip
integer :: nmax, ind_stress_coupling, ind_localisation, ind_tp

! pb%neqs is defined in problem_class.f90
nmax = pb%neqs*pb%mesh%nn
ind_stress_coupling = 2 + pb%features%stress_coupling
ind_stress_coupling = 3 + pb%features%stress_coupling
ind_localisation = ind_stress_coupling + pb%features%localisation
ind_tp = ind_localisation + pb%features%tp

theta = yt(1:nmax:pb%neqs)
main_var = yt(2:nmax:pb%neqs)
slip = yt(3:nmax:pb%neqs)

if (pb%features%stress_coupling == 1) then
sigma = yt(ind_stress_coupling:nmax:pb%neqs)
Expand Down
2 changes: 1 addition & 1 deletion test/singleasperity.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class TestSingleAsperity(AuxiliaryFunctions):
# frozen benchmark results, and it is checked against each time the results
# are imported. When a new benchmark is generated, this hash should be
# updated.
frozen_hash = "e599cf2970fa080320f577ea4b31cd683c82b679"
frozen_hash = "161afa5fe587d428936d45cfe326bd600524cd2b"
frozen_loaded = False

def __init__(self, p):
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion test/stickslip.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class TestStickSlip(AuxiliaryFunctions):
# frozen benchmark results, and it is checked against each time the results
# are imported. When a new benchmark is generated, this hash should be
# updated.
frozen_hash = "e599cf2970fa080320f577ea4b31cd683c82b679"
frozen_hash = "161afa5fe587d428936d45cfe326bd600524cd2b"
frozen_loaded = False

def __init__(self, p):
Expand Down
Binary file not shown.
Loading

0 comments on commit ef4b845

Please sign in to comment.