@@ -178,29 +178,29 @@ def setup_and_check(self):
178178 self .plotTypes = self .config .getexpression ('timeSeriesConservation' , 'plotTypes' )
179179
180180 self .masterVariableList = {'absolute_energy_error' : ['absoluteEnergyError' ],
181- 'total_energy_flux' : ['netEnergyFlux' ],
182- 'absolute_salt_error' : ['absoluteSaltError' ],
183- 'ice_salt_flux' : ['netSaltFlux' ],
184- 'total_mass_flux' : ['netMassFlux' ],
185- 'total_mass_change' : ['netMassChange' ],
186- 'land_ice_mass_change' : ['landIceMassChange' ],
187- 'land_ice_ssh_change' : ['landIceSshChange' ],
188- 'land_ice_mass_flux' : ['landIceMassFlux' ],
189- 'land_ice_mass_flux_components' : ['accumulatedIcebergFlux' ,
181+ 'total_energy_flux' : ['netEnergyFlux' ],
182+ 'absolute_salt_error' : ['absoluteSaltError' ],
183+ 'ice_salt_flux' : ['netSaltFlux' ],
184+ 'total_mass_flux' : ['netMassFlux' ],
185+ 'total_mass_change' : ['netMassChange' ],
186+ 'land_ice_mass_change' : ['landIceMassChange' ],
187+ 'land_ice_ssh_change' : ['landIceSshChange' ],
188+ 'land_ice_mass_flux' : ['landIceMassFlux' ],
189+ 'land_ice_mass_flux_components' : ['accumulatedIcebergFlux' ,
190190 'accumulatedLandIceFlux' ,
191191 'accumulatedRemovedRiverRunoffFlux' ,
192192 'accumulatedRemovedIceRunoffFlux' ]}
193193
194194 # for each derived variable, which source variables are needed
195- self .derivedVariableList = {'netMassChange' : ['netMassFlux ' ],
195+ self .derivedVariableList = {'netMassChange' : ['massChange ' ],
196196 'landIceMassFlux' : ['accumulatedIcebergFlux' ,
197- 'accumulatedLandIceFlux' ,
198- 'accumulatedRemovedRiverRunoffFlux' ,
199- 'accumulatedRemovedIceRunoffFlux' ],
197+ 'accumulatedLandIceFlux' ,
198+ 'accumulatedRemovedRiverRunoffFlux' ,
199+ 'accumulatedRemovedIceRunoffFlux' ],
200200 'landIceSshChange' : ['accumulatedIcebergFlux' ,
201- 'accumulatedLandIceFlux' ,
202- 'accumulatedRemovedRiverRunoffFlux' ,
203- 'accumulatedRemovedIceRunoffFlux' ],
201+ 'accumulatedLandIceFlux' ,
202+ 'accumulatedRemovedRiverRunoffFlux' ,
203+ 'accumulatedRemovedIceRunoffFlux' ],
204204 'landIceMassChange' : ['accumulatedIcebergFlux' ,
205205 'accumulatedLandIceFlux' ,
206206 'accumulatedRemovedRiverRunoffFlux' ,
@@ -303,6 +303,7 @@ def _make_plot(self, plot_type):
303303 titles ['absolute_salt_error' ] = 'Salt conservation error'
304304 titles ['total_mass_flux' ] = 'Total mass flux'
305305 titles ['total_mass_change' ] = 'Total mass anomaly'
306+ titles ['land_ice_mass_flux' ] = 'Mass flux due to land ice'
306307 titles ['land_ice_mass_change' ] = 'Mass anomaly due to land ice fluxes'
307308 titles ['land_ice_ssh_change' ] = 'SSH anomaly due to land ice fluxes'
308309 titles ['land_ice_mass_flux_components' ] = 'Mass fluxes from land ice'
@@ -314,6 +315,7 @@ def _make_plot(self, plot_type):
314315 y_labels ['absolute_salt_error' ] = 'Salt (Gt)'
315316 y_labels ['total_mass_flux' ] = 'Mass flux (Gt/yr)'
316317 y_labels ['total_mass_change' ] = 'Mass (Gt)'
318+ y_labels ['land_ice_mass_flux' ] = 'Mass flux (Gt/yr)'
317319 y_labels ['land_ice_mass_change' ] = 'Mass (Gt)'
318320 y_labels ['land_ice_ssh_change' ] = 'SSH anomaly (mm)'
319321 y_labels ['land_ice_mass_flux_components' ] = 'Mass flux (Gt/yr)'
@@ -326,6 +328,7 @@ def _make_plot(self, plot_type):
326328 captions ['absolute_salt_error' ] = 'Absolute salt conservation error'
327329 captions ['total_mass_flux' ] = 'Total mass flux'
328330 captions ['total_mass_change' ] = 'Total mass anomaly'
331+ captions ['land_ice_mass_flux' ] = 'Mass flux due to land ice'
329332 captions ['land_ice_mass_change' ] = 'Mass anomaly due to land ice fluxes'
330333 captions ['land_ice_ssh_change' ] = 'SSH anomaly due to land ice fluxes. Assumes a constant ocean area.'
331334 captions ['land_ice_mass_flux_components' ] = 'Mass flux components from land ice'
@@ -374,16 +377,7 @@ def _make_plot(self, plot_type):
374377 lineColors = []
375378 lineStyles = []
376379 for index , varname in enumerate (self .masterVariableList [plot_type ]):
377- if varname in self .derivedVariableList :
378- variable = self ._derive_variable (ds , varname )
379- else :
380- variable = ds [varname ]
381- if 'Removed' in varname :
382- variable = - variable
383- if 'mass_flux' or 'salt_flux' in plot_type :
384- variable = variable * 1e-12 * constants .sec_per_year # convert to Gt/yr
385- if 'salt_error' in plot_type :
386- variable = variable * 1e-12 # convert to Gt
380+ variable = self ._get_variable (ds , varname )
387381 fields .append (variable )
388382 legend_text = ''
389383 if self .referenceRunName != 'None' :
@@ -396,16 +390,7 @@ def _make_plot(self, plot_type):
396390 lineColors .append (config .get ('timeSeries' , 'mainColor' ))
397391 lineStyles .append (lineStylesBase [index ])
398392 if self .referenceRunName != 'None' :
399- if varname in self .derivedVariableList :
400- variable = self ._derive_variable (ds_ref_slice , varname )
401- else :
402- variable = ds_ref_slice [varname ]
403- if 'Removed' in varname :
404- variable = - variable
405- if 'mass_flux' or 'salt_flux' in plot_type :
406- variable = variable * 1e-12 * constants .sec_per_year # convert to Gt/yr
407- if 'salt_error' in plot_type :
408- variable = variable * 1e-12 # convert to Gt
393+ variable = self ._get_variable (ds , varname )
409394 fields .append (variable )
410395 legend_text = self .referenceRunName
411396 if len (self .masterVariableList [plot_type ]) > 1 :
@@ -428,7 +413,7 @@ def _make_plot(self, plot_type):
428413 firstYearXTicks = None
429414
430415 if config .has_option ('timeSeries' , 'yearStrideXTicks' ):
431- EearStrideXTicks = config .getint ('timeSeries' ,
416+ yearStrideXTicks = config .getint ('timeSeries' ,
432417 'yearStrideXTicks' )
433418 else :
434419 yearStrideXTicks = None
@@ -446,15 +431,6 @@ def _make_plot(self, plot_type):
446431 # save the plot to the output file
447432 plt .savefig (outFileName )
448433
449- # here's an example of how you would create an XML file for this plot
450- # with the appropriate entries. Some notes:
451- # * Gallery groups typically represent all the analysis from a task,
452- # or sometimes from multiple tasks
453- # * A gallery might be for just for one set of observations, one
454- # season, etc., depending on what makes sense
455- # * Within each gallery, there is one plot for each value in
456- # 'plotParameters', with a corresponding caption and short thumbnail
457- # description
458434 caption = captions [plot_type ]
459435 write_image_xml (
460436 config = self .config ,
@@ -468,59 +444,83 @@ def _make_plot(self, plot_type):
468444 imageDescription = caption ,
469445 imageCaption = caption )
470446
471- def _derive_variable (self , ds , varname ):
472-
473- if varname == 'netMassChange' :
474- # Convert from kg/s to Gt/s
475- mass_flux = ds ['netMassFlux' ] * 1e-12
476- # Assume that the frequency of output is monthly
477- dt = constants .sec_per_month
478- # Convert from Gt/yr to Gt
479- derived_variable = mass_flux .cumsum (axis = 0 ) * dt
480- elif varname == 'landIceMassChange' :
481- land_ice_mass_flux = self ._derive_variable (ds , 'landIceMassFlux' )
482- # Convert from kg/s to Gt/s
483- land_ice_mass_flux = land_ice_mass_flux * 1e-12
484- # Assume that the frequency of output is monthly
485- dt = constants .sec_per_month
486- # Convert from Gt/yr to Gt
487- derived_variable = land_ice_mass_flux .cumsum (axis = 0 ) * dt
488-
489- elif varname == 'landIceMassFlux' :
490- # Here, keep units as kg/s because the conversion to Gt/yr will happen later
491- derived_variable = ds ['accumulatedIcebergFlux' ] + \
492- ds ['accumulatedLandIceFlux' ] + \
493- - ds ['accumulatedRemovedRiverRunoffFlux' ] + \
494- - ds ['accumulatedRemovedIceRunoffFlux' ]
495-
496- elif varname == 'landIceSshChange' :
497- ts_files = sorted (self .historyStreams .readpath (
498- 'timeSeriesStatsMonthlyOutput' ,
499- startDate = f'{ self .startYear :04d} -01-01_00:00:00' ,
500- endDate = f'{ self .endYear :04d} -01-01_00:00:00' ,
501- calendar = self .calendar ))
502- # Note that here we assume that the area of the ocean is constant in time
503- # to save computational expense because most configurations do not allow
504- # the area of the ocean to change
505- ts_file = ts_files [0 ]
506- if not os .path .exists (ts_file ):
507- raise ValueError (f'Could not find timeMonthlyStats file { ts_file } ' )
508- var = 'timeMonthly_avg_areaCellGlobal'
509- ds_ts = open_mpas_dataset (fileName = ts_file ,
510- calendar = self .calendar ,
511- variableList = [var ])
512- A = ds_ts [var ].mean ()
513- land_ice_mass_change = self ._derive_variable (ds , 'landIceMassChange' )
514- # Convert from to Gt to kg
515- land_ice_mass_change = land_ice_mass_change * 1e12
516- rho = self .namelist .getfloat ('config_density0' )
517- # Convert from to kg to mm
518- derived_variable = land_ice_mass_change * 1.0e3 / (rho * A )
519-
447+ def _get_variable (self , ds , varname , mks = False ):
448+ if varname not in self .derivedVariableList :
449+ variable = ds [varname ]
520450 else :
521- raise ValueError (f'Attempted to derive non-supported variable { varname } ' )
451+ # Here we keep the units mks
452+ if varname == 'netMassChange' :
453+ variable = self ._get_variable (ds , 'massChange' , mks = True )
454+ # mass_flux = self._get_variable(ds, 'netMassFlux')
455+ # # Assume that the frequency of output is monthly
456+ # dt = constants.sec_per_month
457+ # # Convert from kg/s to kg
458+ # derived_variable = mass_flux.cumsum(axis=0) * dt
459+ elif varname == 'landIceMassChange' :
460+ land_ice_mass_flux = self ._get_variable (ds , 'landIceMassFlux' , mks = True )
461+ # Assume that the frequency of output is monthly
462+ dt = constants .sec_per_month
463+ # Convert from kg/s to kg/month
464+ land_ice_mass_flux = land_ice_mass_flux * dt
465+ # Convert from kg/month to kg
466+ variable = np .cumsum (land_ice_mass_flux )
467+
468+ elif varname == 'landIceMassFlux' :
469+ variable = self ._get_variable (ds , 'accumulatedIcebergFlux' , mks = True ) + \
470+ self ._get_variable (ds , 'accumulatedLandIceFlux' , mks = True ) + \
471+ self ._get_variable (ds , 'accumulatedRemovedRiverRunoffFlux' , mks = True ) + \
472+ self ._get_variable (ds , 'accumulatedRemovedIceRunoffFlux' , mks = True )
473+
474+ elif varname == 'landIceSshChange' :
475+ ts_files = sorted (self .historyStreams .readpath (
476+ 'timeSeriesStatsMonthlyOutput' ,
477+ startDate = f'{ self .startYear :04d} -01-01_00:00:00' ,
478+ endDate = f'{ self .endYear :04d} -01-01_00:00:00' ,
479+ calendar = self .calendar ))
480+ # Note that here we assume that the area of the ocean is constant in time
481+ # to save computational expense because most configurations do not allow
482+ # the area of the ocean to change
483+ ts_file = ts_files [0 ]
484+ if not os .path .exists (ts_file ):
485+ raise ValueError (f'Could not find timeMonthlyStats file { ts_file } ' )
486+ var = 'timeMonthly_avg_areaCellGlobal'
487+ ds_ts = open_mpas_dataset (fileName = ts_file ,
488+ calendar = self .calendar ,
489+ variableList = [var ])
490+ A = ds_ts [var ].mean ()
491+ land_ice_mass_change = self ._get_variable (ds , 'landIceMassChange' , mks = True )
492+ rho = self .namelist .getfloat ('config_density0' )
493+ # Convert from to kg to m
494+ variable = land_ice_mass_change / (rho * A )
522495
523- return derived_variable
496+ else :
497+ raise ValueError (f'Attempted to derive non-supported variable { varname } ' )
498+
499+ removed_vars = ['accumulatedRemovedRiverRunoffFlux' ,
500+ 'accumulatedRemovedIceRunoffFlux' ]
501+ if varname in removed_vars :
502+ variable = - variable
503+
504+ if not mks :
505+ # Here we do all the unit conversion from mks into whatever we want
506+ mass_vars = ['initialMass' , 'finalMass' , 'absoluteMassError' ,
507+ 'relativeMassError' , 'massChange' , 'landIceMassChange' ]
508+ salt_vars = ['initialSalt' , 'finalSalt' , 'absoluteSaltError' ,
509+ 'relativeSaltError' ]
510+ mass_flux_vars = ['netMassFlux' , 'landIceMassFlux' ]
511+ salt_flux_vars = ['netSaltFlux' ]
512+ ssh_vars = ['landIceSshChange' , 'sshChange' ]
513+ if (varname in mass_vars ) or (varname in salt_vars ):
514+ # Convert from kg to Gt
515+ variable = variable * 1e-12
516+ if (varname in mass_flux_vars ) or (varname in salt_flux_vars ):
517+ # Convert from kg/s to Gt/yr
518+ variable = variable * 1e-12 * constants .sec_per_year
519+ if varname in ssh_vars :
520+ # Convert from m to mm
521+ variable = variable * 1e3
522+
523+ return variable
524524
525525 def _compute_time_series_with_ncrcat (self , variable_list ):
526526
@@ -531,10 +531,6 @@ def _compute_time_series_with_ncrcat(self, variable_list):
531531 ------
532532 OSError
533533 If ``ncrcat`` is not in the system path.
534-
535- Author
536- ------
537- Xylar Asay-Davis
538534 """
539535
540536 if find_executable ('ncrcat' ) is None :
0 commit comments