Skip to content

Commit

Permalink
add nonlinear diffusion
Browse files Browse the repository at this point in the history
  • Loading branch information
tristan-salles committed Oct 20, 2017
1 parent 75d179a commit d015983
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 10 deletions.
9 changes: 7 additions & 2 deletions pyBadlands/flow/flowNetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def __init__(self, input):
self._rank = self._comm.Get_rank()
self._size = self._comm.Get_size()

def compute_hillslope_diffusion(self, elev, neighbours, edges, distances, globalIDs, type):
def compute_hillslope_diffusion(self, elev, neighbours, edges, distances, globalIDs, type, Sc):
"""
Perform hillslope evolution based on diffusion processes.
Expand All @@ -140,7 +140,12 @@ def compute_hillslope_diffusion(self, elev, neighbours, edges, distances, global
"""

if type == 0:
diff_flux = sfd.diffusion(elev, self.borders2, neighbours, edges, distances, globalIDs)
if Sc > 0.:
tSc = numpy.zeros(1)
tSc[0] = Sc
diff_flux = sfd.diffusionnl(tSc, elev, self.borders2, neighbours, edges, distances, globalIDs)
else:
diff_flux = sfd.diffusion(elev, self.borders2, neighbours, edges, distances, globalIDs)
else:
diff_flux = sfd.diffusionero(elev, self.borders2, neighbours, edges, distances, globalIDs)

Expand Down
15 changes: 10 additions & 5 deletions pyBadlands/forcing/xmlParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ def __init__(self, inputfile = None, makeUniqueOutputDir=True):
self.Hillslope = False
self.CDa = 0.
self.CDm = 0.
self.Sc = 0.
self.CDr = 0.
self.makeUniqueOutputDir = makeUniqueOutputDir

Expand Down Expand Up @@ -1007,11 +1008,14 @@ def _get_XmL_Data(self):
self.CDm = float(element.text)
else:
self.CDm = 0.
# self.CDm = self.CDa
# if self.CDm > self.CDa:
# self.CDa = self.CDm
# else:
# self.CDm = self.CDa
element = None
element = creep.find('cslp')
if element is not None:
self.Sc = float(element.text)
if self.Sc < 0.:
self.Sc = 0.
else:
self.Sc = 0.
element = None
element = creep.find('criver')
if element is not None:
Expand All @@ -1023,6 +1027,7 @@ def _get_XmL_Data(self):
self.CDa = 0.
self.CDm = 0.
self.CDr = 0.
self.Sc = 0.

# Loading erodibility layers
erost = None
Expand Down
45 changes: 44 additions & 1 deletion pyBadlands/hillslope/diffLinear.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
from pyBadlands.libUtils import FLOWalgo
import mpi4py.MPI as MPI

import os
if 'READTHEDOCS' not in os.environ:
import pyBadlands.libUtils.sfd as sfd

class diffLinear:
"""
Class for handling hillslope computation using a linear diffusion equation.
Class for handling hillslope computation using a linear/non-linear diffusion equation.
"""

def __init__(self):
Expand All @@ -30,6 +34,7 @@ def __init__(self):
self.CFL = None
self.CFLms = None
self.ids = None
self.Sc = 0.
self.updatedt = 0

def dt_stability(self, edgelen):
Expand Down Expand Up @@ -69,6 +74,44 @@ def dt_stability(self, edgelen):
self.CFL = CFL[0]
self.updatedt = 1

def dt_stabilityCs(self, elev, neighbours, distances, globalIDs, borders):
"""
This function computes the maximal timestep to ensure computation stability
of the non-linear hillslope processes. This CFL-like condition is computed
using non-linear diffusion coefficients and distances between TIN nodes.
Parameters
----------
edgelen
Numpy arrays containing the edges of the TIN surface for the considered partition.
elevation
Numpy arrays containing the edges of the TIN surface for the considered partition.
"""

# Initialise MPI communications
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

# Get the tin edges lengths
maxCD = max(self.CDaerial,self.CDmarine)

CFL = numpy.zeros(1)
if maxCD > 0.:
Sc = numpy.zeros(1)
Sc[0] = self.Sc
mCD = numpy.zeros(1)
mCD[0] = maxCD
CFL = sfd.diffnlcfl(Sc, mCD, elev, borders, neighbours, distances, globalIDs)
else:
CFL[0] = 1.e6

# Global mimimum value for diffusion stability
comm.Allreduce(MPI.IN_PLACE,CFL,op=MPI.MIN)
self.CFL = CFL[0]
self.updatedt = 0

def dt_stability_ms(self, edgelen):
"""
This function computes the maximal timestep to ensure computation stability
Expand Down
96 changes: 96 additions & 0 deletions pyBadlands/libUtils/sfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,102 @@ void diffusion(double pyZ[], int pyBord[], int pyNgbs[][MAX_NEIGHBOURS], double
}
}

void diffnlcfl(double pySc[], double pyKd[], double pyZ[], int pyBord[], int pyNgbs[][MAX_NEIGHBOURS],
double pyDist[][MAX_NEIGHBOURS], int pyGIDs[], double pyCFL[], int pylocalNb, int pyglobalNb)
{
pyCFL[0] = 1.e6;

int k;
double Sc2 = pySc[0] * pySc[0];
double kd = 20. * pyKd[0];

for (k = 0; k < pylocalNb; k++) {
int gid = pyGIDs[k];
int p;
if (pyBord[gid]>0) {
for (p = 0; p < MAX_NEIGHBOURS; p++) {
int ngbid = pyNgbs[gid][p];
if (ngbid < 0) {
break;
}
if (pyBord[ngbid]>0 && pyDist[gid][p] > 0.){
double dh = pyZ[ngbid] - pyZ[gid];
if (dh < 0.){
dh = -dh;
}
double num = pyDist[gid][p] * pyDist[gid][p] - (dh / Sc2);
if (num > 0.){
if (pyCFL[0] > num / kd){
pyCFL[0] = num / kd;
}
}
}
if (pyBord[ngbid]<1){
if (pyZ[ngbid] < pyZ[gid] && pyDist[gid][p] > 0.){
double dh = pyZ[ngbid] - pyZ[gid];
if (dh < 0.){
dh = -dh;
}
double num = pyDist[gid][p] * pyDist[gid][p] - (dh / Sc2);
if (num > 0.){
if (pyCFL[0] > num / kd){
pyCFL[0] = num / kd;
}
}
}
}
}
}
}
}


void diffusionnl(double pySc[], double pyZ[], int pyBord[], int pyNgbs[][MAX_NEIGHBOURS], double pyEdge[][MAX_NEIGHBOURS],
double pyDist[][MAX_NEIGHBOURS], int pyGIDs[], double pyDiff[], int pylocalNb, int pyglobalNb)
{
int i;

for (i = 0; i < pyglobalNb; i++) {
pyDiff[i] = 0.;
}

int k;
double Sc2 = pySc[0] * pySc[0];

for (k = 0; k < pylocalNb; k++) {
int gid = pyGIDs[k];
int p;
if (pyBord[gid]>0) {
for (p = 0; p < MAX_NEIGHBOURS; p++) {
int ngbid = pyNgbs[gid][p];
if (ngbid < 0) {
break;
}
if (pyBord[ngbid]>0 && pyDist[gid][p] > 0.){
double dh = (pyZ[ngbid] - pyZ[gid]) / pyDist[gid][p];
double denom = 1. - ( dh*dh / Sc2 );
if (denom < 0.1){
denom = 0.1;
}
if (denom>0.){
pyDiff[gid] += pyEdge[gid][p] * dh / denom;
}
}
if (pyBord[ngbid]<1){
if (pyZ[ngbid] < pyZ[gid] && pyDist[gid][p] > 0.){
double dh = (pyZ[ngbid] - pyZ[gid]) / pyDist[gid][p];
double denom = 1. - ( dh*dh / Sc2 );
if (denom < 0.1){
denom = 0.1;
}
pyDiff[gid] += pyEdge[gid][p] * dh / denom;
}
}
}
}
}
}

void diffusionero(double pyZ[], int pyBord[], int pyNgbs[][MAX_NEIGHBOURS], double pyEdge[][MAX_NEIGHBOURS],
double pyDist[][MAX_NEIGHBOURS], int pyGIDs[], double pyEro[], int pylocalNb, int pyglobalNb)
{
Expand Down
36 changes: 36 additions & 0 deletions pyBadlands/libUtils/sfd.pyf
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,42 @@ interface
double precision intent(out) :: pyDiff(pyglobalNb)
end subroutine diffusion

subroutine diffnlcfl(pySc, pyKd, pyZ, pyBord, pyNgbs, pyDist, pyGIDs, pyCFL, pylocalNb, pyglobalNb)
intent(c) diffnlcfl ! directions is a C function
intent(c) ! all foo arguments are
! considered as C based

integer intent(in), depend(pyGIDs) :: pylocalNb=len(pyGIDs)
integer intent(in), depend(pyNgbs) :: pyglobalNb=len(pyNgbs)
integer intent(in) :: pyGIDs(pylocalNb)
integer intent(in) :: pyBord(pyglobalNb)
integer intent(in) :: pyNgbs(pyglobalNb, 20)
double precision intent(in) :: pySc(1)
double precision intent(in) :: pyKd(1)
double precision intent(in) :: pyZ(pyglobalNb)
double precision intent(in) :: pyDist(pyglobalNb, 20)

double precision intent(out) :: pyCFL(1)
end subroutine diffnlcfl

subroutine diffusionnl(pySc, pyZ, pyBord, pyNgbs, pyEdge, pyDist, pyGIDs, pyDiff, pylocalNb, pyglobalNb)
intent(c) diffusionnl ! directions is a C function
intent(c) ! all foo arguments are
! considered as C based

integer intent(in), depend(pyGIDs) :: pylocalNb=len(pyGIDs)
integer intent(in), depend(pyNgbs) :: pyglobalNb=len(pyNgbs)
integer intent(in) :: pyGIDs(pylocalNb)
integer intent(in) :: pyBord(pyglobalNb)
integer intent(in) :: pyNgbs(pyglobalNb, 20)
double precision intent(in) :: pySc(1)
double precision intent(in) :: pyZ(pyglobalNb)
double precision intent(in) :: pyEdge(pyglobalNb, 20)
double precision intent(in) :: pyDist(pyglobalNb, 20)

double precision intent(out) :: pyDiff(pyglobalNb)
end subroutine diffusionnl

subroutine diffusionero(pyZ, pyBord, pyNgbs, pyEdge, pyDist, pyGIDs, pyEro, pylocalNb, pyglobalNb)
intent(c) diffusionero ! directions is a C function
intent(c) ! all foo arguments are
Expand Down
1 change: 1 addition & 0 deletions pyBadlands/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def build_mesh(self, filename, verbose):
self.hillslope.CDaerial = self.input.CDa
self.hillslope.CDmarine = self.input.CDm
self.hillslope.CDriver = self.input.CDr
self.hillslope.Sc = self.input.Sc
self.hillslope.updatedt = 0

# Define flow parameters
Expand Down
12 changes: 10 additions & 2 deletions pyBadlands/simulation/buildFlux.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
This file is the main entry point to compute flow network and associated sedimentary fluxes.
"""

import sys
import time
import numpy as np
import mpi4py.MPI as mpi
Expand Down Expand Up @@ -153,7 +154,14 @@ def sediment_flux(input, recGrid, hillslope, FVmesh, tMesh, flow, force, rain, l
# Compute CFL condition
walltime = time.clock()
if input.Hillslope and hillslope.updatedt == 0:
hillslope.dt_stability(FVmesh.edge_length[inGIDs,:tMesh.maxNgbh])
if hillslope.Sc == 0:
hillslope.dt_stability(FVmesh.edge_length[inGIDs,:tMesh.maxNgbh])
else:
hillslope.dt_stabilityCs(elevation, FVmesh.neighbours, FVmesh.edge_length,
lGIDs, flow.borders2)
if hillslope.CFL < input.minDT:
print 'Decrease your hillslope diffusion coefficients to ensure stability.'
sys.exit(0)
hillslope.dt_stability_ms(FVmesh.edge_length[inGIDs,:tMesh.maxNgbh])
elif hillslope.CFL is None:
hillslope.CFL = tEnd-tNow
Expand Down Expand Up @@ -251,7 +259,7 @@ def sediment_flux(input, recGrid, hillslope, FVmesh, tMesh, flow, force, rain, l
diffcoeff = hillslope.sedflux(force.sealevel, elevation, FVmesh.control_volumes)
diffcoeff[flow.outsideIDs2] = 0.
diff_flux = flow.compute_hillslope_diffusion(elevation, FVmesh.neighbours, FVmesh.vor_edges,
FVmesh.edge_length, lGIDs, dtype)
FVmesh.edge_length, lGIDs, dtype, hillslope.Sc)
diff_flux[flow.outsideIDs2] = 0.
cdiff = diffcoeff*diff_flux*timestep

Expand Down

0 comments on commit d015983

Please sign in to comment.