11"""Plate analysis."""
22
33from contextlib import suppress
4+ from functools import lru_cache
45
56import matplotlib .pyplot as plt
67from matplotlib import colors
78import numpy as np
8- from scipy .signal import argrelextrema
9+ from scipy .signal import argrelmin , argrelmax
910
1011from . import conf , error , field , phyvars
1112from ._helpers import saveplot , list_of_vars
@@ -68,56 +69,49 @@ def detect_plates_vzcheck(step, vz_thres_ratio=0):
6869 return limits , dvphi , vphi_surf
6970
7071
71- def detect_plates (step ):
72+ @lru_cache ()
73+ def detect_plates (snap ):
7274 """Detect plates using derivative of horizontal velocity."""
73- vphi = step .fields ['v2' ].values [0 , :, :, 0 ]
74- ph_coord = step .geom .p_centers
75-
76- indsurf = _isurf (step )
77-
78- # dvphi/dphi at cell-center
79- dvph2 = np .diff (vphi [:, indsurf ]) / (ph_coord [1 ] - ph_coord [0 ])
75+ dvphi = _surf_diag (snap , 'dv2' ).values
8076
8177 # finding trenches
82- pom2 = np .copy (dvph2 )
83- maskbigdvel = np .amin (dvph2 ) * 0.2
84- pom2 [pom2 > maskbigdvel ] = maskbigdvel
85- trench_span = 15 if step .sdat .par ['boundaries' ]['air_layer' ] else 10
86- argless_dv = argrelextrema (
87- pom2 , np .less , order = trench_span , mode = 'wrap' )[0 ]
88- trench = ph_coord [argless_dv ]
78+ dvphi_saturated = np .copy (dvphi )
79+ max_dvphi = np .amin (dvphi ) * 0.2
80+ dvphi_saturated [dvphi > max_dvphi ] = max_dvphi
81+ trench_span = 15 if snap .sdat .par ['boundaries' ]['air_layer' ] else 10
82+ itrenches = argrelmin (dvphi_saturated , order = trench_span , mode = 'wrap' )[0 ]
8983
9084 # finding ridges
91- pom2 = np .copy (dvph2 )
92- masksmalldvel = np .amax (dvph2 ) * 0.2
93- pom2 [ pom2 < masksmalldvel ] = masksmalldvel
85+ dvphi_saturated = np .copy (dvphi )
86+ min_dvphi = np .amax (dvphi ) * 0.2
87+ dvphi_saturated [ dvphi < min_dvphi ] = min_dvphi
9488 ridge_span = 20
95- arggreat_dv = argrelextrema (
96- pom2 , np .greater , order = ridge_span , mode = 'wrap' )[0 ]
97- ridge = ph_coord [arggreat_dv ]
89+ iridges = argrelmax (dvphi_saturated , order = ridge_span , mode = 'wrap' )[0 ]
9890
99- # elimination of ridges that are too close to trench
91+ # elimination of ridges that are too close to a trench
92+ phi = snap .geom .p_centers
93+ phi_trenches = phi [itrenches ]
10094 argdel = []
101- if trench . any () and ridge . any () :
102- for i , ridge_i in enumerate (ridge ):
103- mdistance = np .amin (abs (trench - ridge_i ))
95+ if itrenches . size and iridges . size :
96+ for i , iridge in enumerate (iridges ):
97+ mdistance = np .amin (np . abs (phi_trenches - phi [ iridge ] ))
10498 if mdistance < 0.016 :
10599 argdel .append (i )
106100 if argdel :
107- ridge = np .delete (ridge , np . array ( argdel ) )
101+ iridges = np .delete (iridges , argdel )
108102
109- return trench , ridge , argless_dv
103+ return itrenches , iridges
110104
111105
112- def plot_plate_limits (axis , ridges , trenches ):
106+ def _plot_plate_limits (axis , trenches , ridges ):
113107 """Plot lines designating ridges and trenches."""
114108 for trench in trenches :
115109 axis .axvline (x = trench , color = 'red' , ls = 'dashed' , alpha = 0.4 )
116110 for ridge in ridges :
117111 axis .axvline (x = ridge , color = 'green' , ls = 'dashed' , alpha = 0.4 )
118112
119113
120- def plot_plate_limits_field (axis , rcmb , ridges , trenches ):
114+ def _plot_plate_limits_field (axis , rcmb , trenches , ridges ):
121115 """Plot arrows designating ridges and trenches in 2D field plots."""
122116 for trench in trenches :
123117 xxd = (rcmb + 1.02 ) * np .cos (trench ) # arrow begin
@@ -196,7 +190,7 @@ def _continents_location(snap, at_surface=True):
196190 return csurf >= 2
197191
198192
199- def plot_at_surface (snap , names , trenches , ridges ):
193+ def plot_at_surface (snap , names ):
200194 """Plot surface diagnostics."""
201195 for vfig in list_of_vars (names ):
202196 fig , axes = plt .subplots (nrows = len (vfig ), sharex = True ,
@@ -220,9 +214,9 @@ def plot_at_surface(snap, names, trenches, ridges):
220214 where = continents , alpha = 0.2 ,
221215 facecolor = '#8B6914' )
222216 axis .set_ylim ([ymin , ymax ])
223- # need to have trenches and ridges detection without side-
224- # effects, call it here. Memoized.
225- plot_plate_limits (axis , ridges , trenches )
217+ phi = snap . geom . p_centers
218+ itrenches , iridges = detect_plates ( snap )
219+ _plot_plate_limits (axis , phi [ itrenches ], phi [ iridges ] )
226220 if len (vplt ) == 1 :
227221 axis .set_ylabel (label )
228222 else :
@@ -232,8 +226,9 @@ def plot_at_surface(snap, names, trenches, ridges):
232226 saveplot (fig , fname , snap .isnap )
233227
234228
235- def _write_trench_diagnostics (step , vrms_surf , itrenches , fid ):
229+ def _write_trench_diagnostics (step , vrms_surf , fid ):
236230 """Print out some trench diagnostics."""
231+ itrenches , _ = detect_plates (step )
237232 time = step .time * vrms_surf * \
238233 conf .scaling .ttransit / conf .scaling .yearins / 1.e6
239234 isurf = _isurf (step )
@@ -284,28 +279,31 @@ def _write_trench_diagnostics(step, vrms_surf, itrenches, fid):
284279 agetrenches [isubd ]))
285280
286281
287- def plot_scalar_field (step , fieldname , ridges , trenches ):
282+ def plot_scalar_field (snap , fieldname ):
288283 """Plot scalar field with plate information."""
289- fig , axis , _ , _ = field .plot_scalar (step , fieldname )
284+ fig , axis , _ , _ = field .plot_scalar (snap , fieldname )
290285
291286 if conf .plates .continents :
292287 c_field = np .ma .masked_where (
293- ~ _continents_location (step , at_surface = False ),
294- step .fields ['c' ].values [0 , :, :, 0 ])
288+ ~ _continents_location (snap , at_surface = False ),
289+ snap .fields ['c' ].values [0 , :, :, 0 ])
295290 cbar = conf .field .colorbar
296291 conf .field .colorbar = False
297292 cmap = colors .ListedColormap (["k" , "g" , "m" ])
298- field .plot_scalar (step , 'c' , c_field , axis , cmap = cmap ,
293+ field .plot_scalar (snap , 'c' , c_field , axis , cmap = cmap ,
299294 norm = colors .BoundaryNorm ([2 , 3 , 4 , 5 ], cmap .N ))
300295 conf .field .colorbar = cbar
301296
302297 # plotting velocity vectors
303- field .plot_vec (axis , step , 'sx' if conf .plates .stress else 'v' )
298+ field .plot_vec (axis , snap , 'sx' if conf .plates .stress else 'v' )
304299
305300 # Put arrow where ridges and trenches are
306- plot_plate_limits_field (axis , step .geom .rcmb , ridges , trenches )
301+ phi = snap .geom .p_centers
302+ itrenches , iridges = detect_plates (snap )
303+ _plot_plate_limits_field (axis , snap .geom .rcmb ,
304+ phi [itrenches ], phi [iridges ])
307305
308- saveplot (fig , f'plates_{ fieldname } ' , step .isnap ,
306+ saveplot (fig , f'plates_{ fieldname } ' , snap .isnap ,
309307 close = conf .plates .zoom is None )
310308
311309 # Zoom
@@ -320,11 +318,11 @@ def plot_scalar_field(step, fieldname, ridges, trenches):
320318 ladd , radd , uadd , dadd = 0.8 , 0.8 , 0.1 , 0.05
321319 else : # >315 or <=45
322320 ladd , radd , uadd , dadd = 0.1 , 0.05 , 0.8 , 0.8
323- xzoom = (step .geom .rcmb + 1 ) * np .cos (np .radians (conf .plates .zoom ))
324- yzoom = (step .geom .rcmb + 1 ) * np .sin (np .radians (conf .plates .zoom ))
321+ xzoom = (snap .geom .rcmb + 1 ) * np .cos (np .radians (conf .plates .zoom ))
322+ yzoom = (snap .geom .rcmb + 1 ) * np .sin (np .radians (conf .plates .zoom ))
325323 axis .set_xlim (xzoom - ladd , xzoom + radd )
326324 axis .set_ylim (yzoom - dadd , yzoom + uadd )
327- saveplot (fig , f'plates_zoom_{ fieldname } ' , step .isnap )
325+ saveplot (fig , f'plates_zoom_{ fieldname } ' , snap .isnap )
328326
329327
330328def cmd ():
@@ -348,11 +346,9 @@ def cmd():
348346
349347 for step in sdat .walk .filter (fields = ['T' ]):
350348 # could check other fields too
351- trenches , ridges , itrenches = detect_plates (step )
352-
353- _write_trench_diagnostics (step , vrms_surf , itrenches , fid )
354- plot_at_surface (step , conf .plates .plot , trenches , ridges )
355- plot_scalar_field (step , conf .plates .field , ridges , trenches )
349+ _write_trench_diagnostics (step , vrms_surf , fid )
350+ plot_at_surface (step , conf .plates .plot )
351+ plot_scalar_field (step , conf .plates .field )
356352 else :
357353 nb_plates = []
358354 time = []
0 commit comments