2020# read the config
2121pygem_prms = config_manager .read_config ()
2222from oggm import cfg , tasks , workflow
23- from oggm .core . flowline import FluxBasedModel
23+ from oggm .core import flowline
2424
2525import pygem .pygem_modelsetup as modelsetup
2626from pygem import class_climate
2727from pygem .massbalance import PyGEMMassBalance_wrapper
28-
29- # from pygem.glacierdynamics import MassRedistributionCurveModel
3028from pygem .oggm_compat import (
3129 single_flowline_glacier_directory ,
3230 single_flowline_glacier_directory_with_calving ,
3331 update_cfg ,
3432)
33+ from pygem .shop import debris
3534from pygem .utils ._funcs import interp1d_fill_gaps , str2bool
3635
3736
@@ -149,6 +148,79 @@ def run_spinup(gd, **kwargs):
149148 return out
150149
151150
151+ # run inversion at year 2000
152+ def run_inversion (gd , ** kwargs ):
153+ if gd .is_tidewater :
154+ cfg .PARAMS ['use_kcalving_for_inversion' ] = True
155+ tasks .find_inversion_calving_from_any_mb (
156+ gd ,
157+ mb_model = PyGEMMassBalance_wrapper (
158+ gd ,
159+ fl_str = 'inversion_flowlines' ,
160+ option_areaconstant = True ,
161+ ),
162+ glen_a = gd .get_diagnostics ().get ('inversion_glen_a' , None ),
163+ fs = gd .get_diagnostics ().get ('inversion_fs' , None ),
164+ )
165+ else :
166+ cfg .PARAMS ['use_kcalving_for_inversion' ] = False
167+ tasks .prepare_for_inversion (gd )
168+ tasks .mass_conservation_inversion (
169+ gd ,
170+ glen_a = gd .get_diagnostics ().get ('inversion_glen_a' , None ),
171+ fs = gd .get_diagnostics ().get ('inversion_fs' , None ),
172+ )
173+ # create the dynamic flowlines
174+ workflow .execute_entity_task (tasks .init_present_time_glacier , [gd ])
175+
176+ # add debris to model_flowlines
177+ workflow .execute_entity_task (debris .debris_binned , [gd ], fl_str = 'model_flowlines' )
178+
179+ return _run_oggm_dynamics (gd , ** kwargs )
180+
181+
182+ def _run_oggm_dynamics (gd , ** kwargs ):
183+ """run the dynamical evolution model with a given set of model parameters"""
184+ y0 = 2000
185+ y1 = gd .dates_table .year .max ()
186+ fls = gd .read_pickle ('model_flowlines' )
187+ # mass balance model with evolving area
188+ mbmod = PyGEMMassBalance_wrapper (
189+ gd ,
190+ fl_str = 'model_flowlines' ,
191+ )
192+
193+ # glacier dynamics model
194+ if gd .is_tidewater and pygem_prms ['setup' ]['include_frontalablation' ]:
195+ ev_model = flowline .FluxBasedModel (
196+ fls ,
197+ y0 = y0 ,
198+ mb_model = mbmod ,
199+ glen_a = gd .get_diagnostics ()['inversion_glen_a' ],
200+ fs = gd .get_diagnostics ()['inversion_fs' ],
201+ is_tidewater = gd .is_tidewater ,
202+ water_level = gd .get_diagnostics ().get ('calving_water_level' , None ),
203+ do_kcalving = pygem_prms ['setup' ]['include_frontalablation' ],
204+ )
205+ else :
206+ ev_model = flowline .SemiImplicitModel (
207+ fls ,
208+ y0 = y0 ,
209+ mb_model = mbmod ,
210+ glen_a = gd .get_diagnostics ()['inversion_glen_a' ],
211+ fs = gd .get_diagnostics ()['inversion_fs' ],
212+ )
213+ try :
214+ # run glacier dynamics model forward
215+ ev_model .run_until_and_store (
216+ y1 + 1 , fl_diag_path = gd .get_filepath ('fl_diagnostics' , filesuffix = '_dynamic_spinup_pygem_mb' )
217+ )
218+ return [ev_model ]
219+ # safely catch any errors with dynamical run
220+ except Exception :
221+ return [None ]
222+
223+
152224def run (glacno_list , mb_model_params , optimize = False , periods2try = [20 ], outdir = None , debug = False , ncores = 1 , ** kwargs ):
153225 # remove any None kwargs
154226 kwargs = {k : v for k , v in kwargs .items () if v is not None }
@@ -196,7 +268,7 @@ def run(glacno_list, mb_model_params, optimize=False, periods2try=[20], outdir=N
196268 gd .is_tidewater = True
197269 if kwargs ['allow_calving' ]:
198270 kwargs ['evolution_model' ] = partial (
199- FluxBasedModel , water_level = gd .get_diagnostics ().get ('calving_water_level' , None )
271+ flowline . FluxBasedModel , water_level = gd .get_diagnostics ().get ('calving_water_level' , None )
200272 ) # use FluxBasedModel to allow for calving
201273 cfg .PARAMS ['use_kcalving_for_inversion' ] = True
202274 cfg .PARAMS ['use_kcalving_for_run' ] = True
@@ -296,7 +368,7 @@ def run(glacno_list, mb_model_params, optimize=False, periods2try=[20], outdir=N
296368 ############################
297369
298370 # update cfg.PARAMS
299- update_cfg ({'continue_on_error' : True }, 'PARAMS' )
371+ update_cfg ({'continue_on_error' : False }, 'PARAMS' )
300372 update_cfg ({'store_model_geometry' : True }, 'PARAMS' )
301373
302374 # optimize against binned dhdt data
@@ -317,12 +389,18 @@ def run(glacno_list, mb_model_params, optimize=False, periods2try=[20], outdir=N
317389
318390 # objective function to evaluate
319391 def _objective (** kwargs ):
320- fls = run_spinup (gd , ** kwargs )
392+ if gd .rgi_date + 1 - kwargs ['spinup_period' ] >= 2000 :
393+ fls = run_inversion (gd , ** kwargs )
394+ else :
395+ fls = run_spinup (gd , ** kwargs )
396+
321397 if fls [0 ] is None :
322398 return kwargs ['spinup_period' ], float ('inf' ), None
323399
324400 # get true spinup period (note, if initial fails, oggm tries period/2)
325401 spinup_period_ = gd .rgi_date + 1 - fls [0 ].y0
402+ if spinup_period_ in results .keys ():
403+ return None
326404
327405 # create lookup dict (timestamp → index)
328406 dtable = modelsetup .datesmodelrun (startyear = fls [0 ].y0 , endyear = kwargs ['ye' ])
@@ -339,7 +417,7 @@ def _objective(**kwargs):
339417 dhdt_hat = dh_hat / gd .elev_change_1d ['nyrs' ]
340418
341419 # plot binned surface area
342- ax .plot (dist , bin_area , label = f'{ spinup_period } years: { round (1e-6 * np .sum (bin_area ), 1 )} km$^2$' )
420+ ax .plot (dist , bin_area , label = f'{ spinup_period_ } years: { round (1e-6 * np .sum (bin_area ), 1 )} km$^2$' )
343421
344422 # penalize positive values below specified elevation threshold
345423 loss = loss_with_penalty (
@@ -350,6 +428,8 @@ def _objective(**kwargs):
350428
351429 # evaluate candidate spinup periods
352430 for p in periods2try :
431+ if p in results .keys ():
432+ continue
353433 kwargs ['spinup_period' ] = p
354434 p_ , mismatch , model = _objective (** kwargs )
355435 results [p_ ] = (mismatch , model )
@@ -550,10 +630,10 @@ def main():
550630 '-periods2try' ,
551631 type = int ,
552632 nargs = '+' ,
553- default = [20 , 30 , 40 , 50 , 60 ],
633+ default = [0 , 10 , 20 , 30 , 40 , 50 , 60 ],
554634 help = (
555635 'Optional list of spinup periods (years) to test if -optimize is used. '
556- 'Ignored otherwise. Example: -periods2try 20 30 40 50 60'
636+ 'Ignored otherwise. Example: -periods2try 0 10 20 30 40 50 60'
557637 ),
558638 )
559639 parser .add_argument (
0 commit comments