1- from compass .landice .mesh import build_cell_width , build_mali_mesh
1+ import os
2+
3+ import numpy as np
4+ import xarray as xr
5+ from mpas_tools .scrip .from_mpas import scrip_from_mpas
6+
7+ from compass .landice .mesh import (
8+ build_cell_width ,
9+ build_mali_mesh ,
10+ clean_up_after_interp ,
11+ interp_gridded2mali ,
12+ )
213from compass .model import make_graph_file
314from compass .step import Step
415
@@ -28,18 +39,19 @@ def __init__(self, test_case):
2839 super ().__init__ (test_case = test_case , name = 'mesh' , cpus_per_task = 128 ,
2940 min_cpus_per_task = 1 )
3041
42+ self .mesh_filename = 'Kangerlussuaq.nc'
3143 self .add_output_file (filename = 'graph.info' )
32- self .add_output_file (filename = 'Kangerlussuaq.nc' )
33- self .add_input_file (
34- filename = 'greenland_1km_2024_01_29.epsg3413.icesheetonly.nc' ,
35- target = 'greenland_1km_2024_01_29.epsg3413.icesheetonly.nc' ,
36- database = '' )
44+ self .add_output_file (filename = self .mesh_filename )
3745 self .add_input_file (filename = 'Kangerlussuaq.geojson' ,
3846 package = 'compass.landice.tests.kangerlussuaq' ,
3947 target = 'Kangerlussuaq.geojson' ,
4048 database = None )
41- self .add_input_file (filename = 'greenland_8km_2024_01_29.epsg3413.nc' ,
42- target = 'greenland_8km_2024_01_29.epsg3413.nc' ,
49+ self .add_input_file (
50+ filename = 'greenland_1km_2024_01_29.epsg3413.icesheetonly.nc' ,
51+ target = 'greenland_1km_2024_01_29.epsg3413.icesheetonly.nc' ,
52+ database = '' )
53+ self .add_input_file (filename = 'greenland_2km_2024_01_29.epsg3413.nc' ,
54+ target = 'greenland_2km_2024_01_29.epsg3413.nc' ,
4355 database = '' )
4456
4557 # no setup() method is needed
@@ -49,22 +61,85 @@ def run(self):
4961 Run this step of the test case
5062 """
5163 logger = self .logger
52- mesh_name = 'Kangerlussuaq.nc'
64+ config = self .config
65+ self .mesh_filename = 'Kangerlussuaq.nc'
5366 section_name = 'mesh'
5467
68+ section_gis = config ['greenland' ]
69+
70+ parallel_executable = config .get ('parallel' , 'parallel_executable' )
71+ nProcs = section_gis .get ('nProcs' )
72+ src_proj = section_gis .get ("src_proj" )
73+ data_path = section_gis .get ('data_path' )
74+ measures_filename = section_gis .get ("measures_filename" )
75+ bedmachine_filename = section_gis .get ("bedmachine_filename" )
76+
77+ measures_dataset = os .path .join (data_path , measures_filename )
78+ bedmachine_dataset = os .path .join (data_path , bedmachine_filename )
79+
80+ section_name = 'mesh'
81+
82+ source_gridded_dataset_1km = 'greenland_1km_2024_01_29.epsg3413.icesheetonly.nc' # noqa: E501
83+ source_gridded_dataset_2km = 'greenland_2km_2024_01_29.epsg3413.nc'
84+
5585 logger .info ('calling build_cell_width' )
5686 cell_width , x1 , y1 , geom_points , geom_edges , floodMask = \
5787 build_cell_width (
5888 self , section_name = section_name ,
59- gridded_dataset = 'greenland_8km_2024_01_29.epsg3413.nc' )
89+ gridded_dataset = source_gridded_dataset_2km )
6090
6191 build_mali_mesh (
6292 self , cell_width , x1 , y1 , geom_points , geom_edges ,
63- mesh_name = mesh_name , section_name = section_name ,
64- gridded_dataset = 'greenland_1km_2024_01_29.epsg3413.icesheetonly.nc' , # noqa
65- projection = 'gis-gimp' , geojson_file = 'Kangerlussuaq.geojson' ,
93+ mesh_name = self . mesh_filename , section_name = section_name ,
94+ gridded_dataset = source_gridded_dataset_1km , # noqa
95+ projection = src_proj , geojson_file = 'Kangerlussuaq.geojson' ,
6696 cores = self .cpus_per_task )
6797
98+ # Create scrip file for the newly generated mesh
99+ logger .info ('creating scrip file for destination mesh' )
100+ dst_scrip_file = f"{ self .mesh_filename .split ('.' )[:- 1 ][0 ]} _scrip.nc"
101+ scrip_from_mpas (self .mesh_filename , dst_scrip_file )
102+
103+ # Now perform bespoke interpolation of geometry and velocity data
104+ # from their respective sources
105+ logger .info ('interpolating bedMachine' )
106+ interp_gridded2mali (self .mesh_filename , bedmachine_dataset ,
107+ dst_scrip_file , parallel_executable , nProcs ,
108+ self .mesh_filename , src_proj , variables = "all" )
109+
110+ # only interpolate a subset of MEaSUREs variables onto the MALI mesh
111+ logger .info ('interpolating MEaSUREs' )
112+ measures_vars = ['observedSurfaceVelocityX' ,
113+ 'observedSurfaceVelocityY' ,
114+ 'observedSurfaceVelocityUncertainty' ]
115+ interp_gridded2mali (self , measures_dataset , dst_scrip_file ,
116+ parallel_executable , nProcs ,
117+ self .mesh_filename , src_proj ,
118+ variables = measures_vars )
119+
120+ # perform some final cleanup details
121+ clean_up_after_interp (self .mesh_filename )
122+
68123 logger .info ('creating graph.info' )
69- make_graph_file (mesh_filename = mesh_name ,
124+ make_graph_file (mesh_filename = self . mesh_filename ,
70125 graph_filename = 'graph.info' )
126+
127+ # Do some final validation of the mesh
128+ ds = xr .open_dataset (self .mesh_filename )
129+ # Ensure basalHeatFlux is positive
130+ ds ["basalHeatFlux" ] = np .abs (ds .basalHeatFlux )
131+ # Ensure reasonable dHdt values
132+ dHdt = ds ["observedThicknessTendency" ]
133+ # Arbitrary 5% uncertainty; improve this later
134+ dHdtErr = np .abs (dHdt ) * 0.05
135+ # Use threshold of |dHdt| > 1.0 to determine invalid data
136+ mask = np .abs (dHdt ) > 1.0
137+ # Assign very large uncertainty where data is missing
138+ dHdtErr = dHdtErr .where (~ mask , 1.0 )
139+ # Remove ridiculous values
140+ dHdt = dHdt .where (~ mask , 0.0 )
141+ # Put the updated fields back in the dataset
142+ ds ["observedThicknessTendency" ] = dHdt
143+ ds ["observedThicknessTendencyUncertainty" ] = dHdtErr
144+ # Write the data to disk
145+ ds .to_netcdf (self .mesh_filename , 'a' )
0 commit comments