Skip to content

Commit 29c82e6

Browse files
authored
Merge pull request #664 from rjleveque/make_dtopography_refactor
refactor dtopotools.create_dtopography to avoid memory issues
2 parents e4eb1c1 + 9bdf03c commit 29c82e6

File tree

1 file changed

+70
-29
lines changed

1 file changed

+70
-29
lines changed

src/python/geoclaw/dtopotools.py

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -760,17 +760,26 @@ def Mw(self):
760760
r"""Calculate the moment magnitude for a fault composed of subfaults."""
761761
return Mw(self.Mo())
762762

763-
def create_dtopography(self, x, y, times=[0., 1.], verbose=False):
763+
def create_dtopography(self, x, y, times=[0., 1.], slip_tol=0.001,
764+
verbose=False):
764765
r"""Compute change in topography and construct a dtopography object.
765766
766767
Use subfaults' `okada` routine and add all
767768
deformations together.
768769
769770
Raises a ValueError exception if the *rupture_type* is an unknown type.
770771
772+
Subfaults are ignored if abs(subfault.slip) < slip_tol
773+
774+
If verbose == True then the subfault number is printed as each is
775+
processed to show progress. If verbose is an integer, then it is
776+
printed for the k'th subfault only if mod(k,verbose) == 0.
777+
771778
returns a :class`DTopography` object.
772779
"""
773780

781+
nignore = 0 # to keep track of how many have abs(slip) < slip_tol
782+
774783
dtopo = DTopography()
775784
dtopo.x = x
776785
dtopo.y = y
@@ -783,21 +792,31 @@ def create_dtopography(self, x, y, times=[0., 1.], verbose=False):
783792
print("Making Okada dz for each of %s subfaults" \
784793
% len(self.subfaults))
785794

786-
for k,subfault in enumerate(self.subfaults):
787-
if verbose:
788-
sys.stdout.write("%s.." % k)
789-
sys.stdout.flush()
790-
subfault.okada(x,y) # sets subfault.dtopo with times=[0]
791-
# and subfault.dtopo.dZ.shape[0] == 1
792-
if verbose:
793-
sys.stdout.write("\nDone\n")
795+
dz = numpy.zeros(X.shape) # to accumulate dZ for static rupture
794796

795797
if self.rupture_type == 'static':
798+
799+
for k,subfault in enumerate(self.subfaults):
800+
if verbose:
801+
if (type(verbose) is int) and (numpy.mod(k,verbose) != 0):
802+
pass
803+
else:
804+
sys.stdout.write("%s.." % k)
805+
sys.stdout.flush()
806+
807+
if abs(subfault.slip) < slip_tol:
808+
nignore += 1
809+
else:
810+
dtopo_sub = subfault.okada(x,y,set_dtopo=False)
811+
# returns dtopo with times=[0] and dtopo.dZ.shape[0] == 1
812+
813+
dz += dtopo_sub.dZ[0,:,:]
814+
815+
if verbose:
816+
sys.stdout.write("\nDone\n")
817+
796818
if len(times) > 2:
797819
raise ValueError("For static deformation, need len(times) <= 2")
798-
dz = numpy.zeros(X.shape)
799-
for subfault in self.subfaults:
800-
dz += subfault.dtopo.dZ[0,:,:]
801820

802821
if len(times) == 1:
803822
# only final deformation stored:
@@ -811,33 +830,47 @@ def create_dtopography(self, x, y, times=[0., 1.], verbose=False):
811830

812831
elif self.rupture_type in ['dynamic','kinematic']:
813832

814-
t_prev = -1.e99
815-
dzt = numpy.zeros(X.shape)
816-
dZ = None
817-
for t in times:
818-
for k,subfault in enumerate(self.subfaults):
833+
# array subfault_frac[k,jt] will store fraction of subfault k
834+
# deformation to add to dZ[jt,:,:] at times[jt]:
835+
subfault_frac = numpy.zeros((len(self.subfaults),len(times)))
819836

820-
rf = rise_fraction([t_prev,t],
837+
# compute these values from rupture and rise times, without yet
838+
# computing deformations:
839+
for k,subfault in enumerate(self.subfaults):
840+
subfault_frac[k,:] = rise_fraction(times,
821841
subfault.rupture_time,
822842
subfault.rise_time,
823843
subfault.rise_time_starting,
824844
subfault.rise_shape)
825845

826-
dfrac = rf[1] - rf[0]
827-
if dfrac > 0.:
828-
dzt = dzt + dfrac * subfault.dtopo.dZ[0,:,:]
846+
# now loop over subfaults, applying Okada to get
847+
# deformation dtopo_sub due to single subfault, then loop
848+
# over times to apply this at each time:
829849

830-
dzt = numpy.array(dzt, ndmin=3) # convert to 3d array
831-
if dZ is None:
832-
dZ = dzt.copy()
850+
dZ = numpy.zeros([len(times)] + list(X.shape))
851+
852+
for k,subfault in enumerate(self.subfaults):
853+
if abs(subfault.slip) < slip_tol:
854+
nignore += 1
833855
else:
834-
dZ = numpy.append(dZ, dzt, axis=0)
835-
t_prev = t
856+
dtopo_sub = subfault.okada(x,y,set_dtopo=False)
857+
# returns dtopo with times=[0] and dtopo.dZ.shape[0] == 1
858+
859+
for jt,t in enumerate(times):
860+
dfrac = subfault_frac[k,jt] # fraction to add at t
861+
862+
if dfrac > 0.:
863+
dZ[jt,:,:] += dfrac * dtopo_sub.dZ[0,:,:]
864+
836865
dtopo.dZ = dZ
837866

838867
else:
839868
raise ValueError("Unrecognized rupture_type: %s" % self.rupture_type)
840869

870+
if verbose and nignore > 0:
871+
print('Ignored %i subfaults with abs(slip) < slip_tol = %.3fm' \
872+
% (nignore,slip_tol))
873+
841874
# Store for user
842875
self.dtopo = dtopo
843876

@@ -1682,12 +1715,18 @@ def _llz2utm(self,lon,lat,projection_zone=None):
16821715
return x,y
16831716

16841717

1685-
def okada(self, x, y):
1718+
def okada(self, x, y, set_dtopo=True):
16861719
r"""
16871720
Apply Okada to this subfault and return a DTopography object.
16881721
16891722
:Input:
16901723
- x,y are 1d arrays
1724+
- set_dtopo (bool): If True, also set self.dtopo = dtopo, the
1725+
DTopography object created.
1726+
Defaults to True for backward compatibility, but create_dtopography
1727+
has been refactored so it is no longer necessary to save dtopo
1728+
for each subfault separately, which may use too much memory if
1729+
there are many subfaults with fine resolution dtopo files.
16911730
:Output:
16921731
- DTopography object with dZ array of shape (1,len(x),len(y))
16931732
with single static displacement and times = [0.].
@@ -1774,7 +1813,8 @@ def okada(self, x, y):
17741813
dtopo.Y = Y
17751814
dtopo.dZ = numpy.array(dz, ndmin=3)
17761815
dtopo.times = [0.]
1777-
self.dtopo = dtopo
1816+
if set_dtopo:
1817+
self.dtopo = dtopo
17781818

17791819
elif self.coordinate_specification == 'triangular':
17801820

@@ -1866,7 +1906,8 @@ def okada(self, x, y):
18661906
dtopo.dY = numpy.array(dY, ndmin=3)
18671907
dtopo.dZ = numpy.array(dZ, ndmin=3)
18681908
dtopo.times = [0.]
1869-
self.dtopo = dtopo
1909+
if set_dtopo:
1910+
self.dtopo = dtopo
18701911

18711912
return dtopo
18721913

0 commit comments

Comments
 (0)