44import jigsawpy
55import numpy as np
66import xarray as xr
7+ from mpas_tools .logging import check_call
78from mpas_tools .scrip .from_mpas import scrip_from_mpas
89
910from compass .landice .mesh import (
@@ -81,9 +82,13 @@ def run(self):
8182 data_path = section_gis .get ('data_path' )
8283 measures_filename = section_gis .get ("measures_filename" )
8384 bedmachine_filename = section_gis .get ("bedmachine_filename" )
85+ smb_filename = section_gis .get ("smb_filename" )
86+ bmb_filename = section_gis .get ("bmb_filename" )
8487
8588 measures_dataset = os .path .join (data_path , measures_filename )
8689 bedmachine_dataset = os .path .join (data_path , bedmachine_filename )
90+ smb_dataset = os .path .join (data_path , smb_filename )
91+ bmb_dataset = os .path .join (data_path , bmb_filename )
8792
8893 section_name = 'mesh'
8994
@@ -133,6 +138,127 @@ def run(self):
133138 self .mesh_filename , src_proj ,
134139 variables = measures_vars )
135140
141+ # Insert SMB fields for dh/dt constraint
142+ # Create copy of smb file with mean and stdev smb
143+ # for 2002 – 2012, named to be consistent with MALI
144+ start_yr = 52 # 2002
145+ end_yr = 63 # 2012
146+
147+ file , ext = os .path .splitext (smb_dataset )
148+ smb_altered = file + '.tmp.copy' + ext
149+
150+ ds = xr .open_dataset (smb_dataset )
151+ smb_rec = ds ['smb_rec' ][start_yr :end_yr , :, :].values
152+ smb_mean = np .nanmean (smb_rec , axis = 0 ).astype ('float64' )
153+ smb_stdev = np .nanstd (smb_rec , axis = 0 ).astype ('float64' )
154+ x = ds ['x' ].values
155+ y = ds ['y' ].values
156+ ds ['x' ] = xr .DataArray (x .astype ('int32' ), dims = ("x" ),
157+ attrs = {'units' : 'm' })
158+ ds ['y' ] = xr .DataArray (y .astype ('int32' ), dims = ("y" ),
159+ attrs = {'units' : 'm' })
160+ ds ['x1' ] = ds ['x' ]
161+ ds ['y1' ] = ds ['y' ]
162+ ds ['sfcMassBal' ] = xr .DataArray (smb_mean , dims = ("y" , "x" ))
163+ ds ['sfcMassBalUncertainty' ] = xr .DataArray (smb_stdev , dims = ("y" , "x" ))
164+ ds .to_netcdf (smb_altered )
165+ ds .close ()
166+
167+ args = (["ncatted" , "-a" , "_FillValue,,d,," , smb_altered ])
168+ check_call (args )
169+
170+ # interpolate
171+ smb_scrip = ['smb_rec.1950-2014.BN_RACMO2.'
172+ '3p2-CESM2-Historical.1km.YY.scrip.nc' ]
173+ args = ['create_scrip_file_from_planar_rectangular_grid' ,
174+ '-i' , smb_altered ,
175+ '-s' , smb_scrip ,
176+ '-p' , 'gis-gimp' , '-r' , '2' ]
177+ check_call (args )
178+
179+ args = [parallel_executable , '-n' , nProcs , 'ESMF_RegridWeightGen' ,
180+ '--source' , smb_scrip , '--destination' , dst_scrip_file ,
181+ '--weight' , 'SMB_to_UD_weights.nc' ,
182+ '--method' , 'conserve' , '--netcdf4' ,
183+ '--dst_regional' , '--src_regional' , '--ignore_unmapped' ]
184+ check_call (args )
185+
186+ args = ['ncremap' , '-i' , smb_altered ,
187+ '-o' , 'smb_remapped.nc' ,
188+ '-m' , 'SMB_to_UD_weights.nc' ,
189+ '-v' , 'sfcMassBal,sfcMassBalUncertainty' ]
190+ check_call (args )
191+
192+ # Repeat with BMB fields for dh/dt constraint
193+ # rename variables to be compatible
194+ # with MALI and interpolator
195+
196+ # interpolate
197+ bmb_scrip = 'basalmelt_Karlssonetal2021_updated2022.scrip.nc'
198+ args = ['create_scrip_file_from_planar_rectangular_grid' ,
199+ '-i' , bmb_dataset ,
200+ '-s' , bmb_scrip ,
201+ '-p' , 'gis-gimp' , '-r' , '2' ]
202+ check_call (args )
203+
204+ args = [parallel_executable , '-n' , nProcs , 'ESMF_RegridWeightGen' ,
205+ '--source' , bmb_scrip , '--destination' , dst_scrip_file ,
206+ '--weight' , 'BMB_to_UD_weights.nc' ,
207+ '--method' , 'conserve' , '--netcdf4' ,
208+ '--dst_regional' , '--src_regional' , '--ignore_unmapped' ]
209+ check_call (args )
210+
211+ args = ['ncremap' , '-i' , bmb_dataset ,
212+ '-o' , 'bmb_remapped.nc' ,
213+ '-m' , 'BMB_to_UD_weights.nc' ,
214+ '-v' , 'bmb,bmbErr' ]
215+ check_call (args )
216+
217+ # transfer remapped SMB and BMB to final mesh
218+ ds_bmb = xr .open_dataset ('bmb_remapped.nc' )
219+ ds_smb = xr .open_dataset ('smb_remapped.nc' )
220+ ds = xr .open_dataset (self .mesh_filename )
221+
222+ bmb = ds_bmb ['bmb' ].values
223+ bmbErr = ds_bmb ['bmbErr' ].values
224+ smb = ds_smb ['sfcMassBal' ].values
225+ smbU = ds_smb ['sfcMassBalUncertainty' ].values
226+
227+ # unit conversions to MALI standards
228+ # mm w.e./yr to kg/(m2 s)
229+ smb = smb / 3.15e7
230+ smbU = smbU / 3.15e7
231+ # m/yr to kg/(m2 s)
232+ bmb = (bmb * 910 ) / 3.15e7
233+ bmbErr = (bmbErr * 910 ) / 3.15e7
234+
235+ bmb = bmb .reshape (1 , len (bmb ))
236+ bmbErr = bmbErr .reshape (1 , len (bmbErr ))
237+ smb = smb .reshape (1 , len (smb ))
238+ smbU = smbU .reshape (1 , len (smbU ))
239+
240+ ds ['floatingBasalMassBal' ] = \
241+ xr .DataArray (bmb ,
242+ dims = ("Time" , "nCells" ),
243+ attrs = {'units' : 'kg m^-2 s^-1' })
244+ ds ['floatingBasalMassBalUncertainty' ] = \
245+ xr .DataArray (bmbErr , dims = ("Time" , "nCells" ),
246+ attrs = {'units' : 'kg m^-2 s^-1' })
247+ ds ['sfcMassBal' ] = xr .DataArray (smb , dims = ("Time" , "nCells" ),
248+ attrs = {'units' : 'kg m^-2 s^-1' })
249+ ds ['sfcMassBalUncertainty' ] = \
250+ xr .DataArray (smbU ,
251+ dims = ("Time" , "nCells" ),
252+ attrs = {'units' : 'kg m^-2 s^-1' })
253+
254+ ds .to_netcdf (self .mesh_filename , 'a' )
255+ ds .close ()
256+ ds_smb .close ()
257+ ds_bmb .close ()
258+
259+ args = (["ncatted" , "-a" , "_FillValue,,d,," , self .mesh_filename ])
260+ check_call (args )
261+
136262 # perform some final cleanup details
137263 clean_up_after_interp (self .mesh_filename )
138264
@@ -152,19 +278,28 @@ def run(self):
152278 ds = xr .open_dataset (self .mesh_filename )
153279 # Ensure basalHeatFlux is positive
154280 ds ["basalHeatFlux" ] = np .abs (ds .basalHeatFlux )
155- # Ensure reasonable dHdt values
281+
282+ # Ensure reasonable dHdt and dHdtErr values
156283 dHdt = ds ["observedThicknessTendency" ]
157- # Arbitrary 5% uncertainty; improve this later
158- dHdtErr = np .abs (dHdt ) * 0.05
284+ # Calculate dHdt err using Csatho et al 2014 estimates
285+ # Error is approximated based on surface velocity
286+ baselineUncertainty = 0.01 # m/yr
287+ ux = ds ['observedSurfaceVelocityX' ].values
288+ uy = ds ['observedSurfaceVelocityY' ].values
289+ spd = np .sqrt (ux ** 2 + uy ** 2 )
290+ mask = spd > (50.0 / 3.15E7 ) # cutoff at 50 m/yr
291+ dHdtErr = baselineUncertainty * np .ones (dHdt .values .shape ) / 3.15E7
292+ dHdtErr [mask ] = 2.0 / 3.15E7 # From Csatho 2014
159293 # Use threshold of |dHdt| > 1.0 to determine invalid data
160294 mask = np .abs (dHdt ) > 1.0
161- # Assign very large uncertainty where data is missing
162- dHdtErr = dHdtErr .where (~ mask , 1.0 )
163295 # Remove ridiculous values
164296 dHdt = dHdt .where (~ mask , 0.0 )
297+
165298 # Put the updated fields back in the dataset
166299 ds ["observedThicknessTendency" ] = dHdt
167- ds ["observedThicknessTendencyUncertainty" ] = dHdtErr
300+ dhdterr = xr .DataArray (dHdtErr .astype ('float64' ),
301+ dims = ("Time" , "nCells" ))
302+ ds ["observedThicknessTendencyUncertainty" ] = dhdterr
168303 # Write the data to disk
169304 ds .to_netcdf (self .mesh_filename , 'a' )
170305
0 commit comments