def run(self): """ Run this step of the test case """ config = self.config logger = self.logger section = config['gotm'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=False, nonperiodic_y=False) write_netcdf(dsMesh, 'grid.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, graphInfoFileName='graph.info', logger=logger) write_netcdf(dsMesh, 'mesh.nc') replacements = dict() replacements['config_periodic_planar_vert_levels'] = \ config.get('gotm', 'vert_levels') replacements['config_periodic_planar_bottom_depth'] = \ config.get('gotm', 'bottom_depth') self.update_namelist_at_runtime(options=replacements) run_model(self)
def run(self): """ Run this step of the test case """ logger = self.logger section = self.config['enthalpy_benchmark'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') levels = section.get('levels') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=True, nonperiodic_y=True) write_netcdf(dsMesh, 'grid.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, logger=logger) write_netcdf(dsMesh, 'mpas_grid.nc') args = ['create_landice_grid_from_generic_MPAS_grid.py', '-i', 'mpas_grid.nc', '-o', 'landice_grid.nc', '-l', levels, '--thermal'] check_call(args, logger) make_graph_file(mesh_filename='landice_grid.nc', graph_filename='graph.info') _setup_initial_conditions(section, 'landice_grid.nc')
def run(self): """ Run this step of the test case """ logger = self.logger section = self.config['eismint2'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=False, nonperiodic_y=False) dsMesh = convert(dsMesh, logger=logger) write_netcdf(dsMesh, 'mpas_grid.nc') dsMesh.close() radius = section.get('radius') args = [ 'define_cullMask.py', '-f', 'mpas_grid.nc', '-m', 'radius', '-d', radius ] check_call(args, logger) dsMesh = xarray.open_dataset('mpas_grid.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, logger=logger) write_netcdf(dsMesh, 'mpas_grid2.nc') levels = section.get('levels') args = [ 'create_landice_grid_from_generic_MPAS_grid.py', '-i', 'mpas_grid2.nc', '-o', 'landice_grid.nc', '-l', levels, '--thermal', '--beta' ] check_call(args, logger) make_graph_file(mesh_filename='landice_grid.nc', graph_filename='graph.info')
def test_conversion(): dsMesh = xarray.open_dataset( 'mesh_tools/mesh_conversion_tools/test/mesh.QU.1920km.151026.nc') dsMesh = convert(dsIn=dsMesh) write_netcdf(dsMesh, 'mesh.nc') dsMask = xarray.open_dataset( 'mesh_tools/mesh_conversion_tools/test/land_mask_final.nc') dsCulled = cull(dsIn=dsMesh, dsMask=dsMask) write_netcdf(dsCulled, 'culled_mesh.nc') fcMask = read_feature_collection( 'mesh_tools/mesh_conversion_tools/test/Arctic_Ocean.geojson') dsMask = mask(dsMesh=dsMesh, fcMask=fcMask) write_netcdf(dsMask, 'antarctic_mask.nc')
def main(args): earth_radius = 6371.0e3 out_dir = os.path.abspath(args.output) out_base = os.path.basename(args.output) out_basepath = out_dir + "/" + out_base out_filename = out_dir + "/" + out_base + "_mpas.nc" p = bool(args.plots) print(p) if not os.path.exists(out_dir): os.makedirs(out_dir) else: print("Base dir already exists: ", out_dir) if (args.opt == "unif" or args.opt == "localref"): #Density based grid if (args.opt == "unif"): cellWidth, lon, lat = jutil.cellWidthVsLatLon(args.r) elif (args.opt == "localref"): cellWidth, lon, lat = jutil.localrefVsLatLon(args.r, p=p) mesh_file = jutil.jigsaw_gen_sph_grid(cellWidth, lon, lat, basename=out_basepath) elif (args.opt == "icos"): #Icosahedral grid mesh_file = jutil.jigsaw_gen_icos_grid(basename=out_basepath, level=4) else: print("Unknown option") exit(1) #Convert jigsaw mesh to netcdf jigsaw_to_netcdf(msh_filename=mesh_file, output_name=out_basepath + '_triangles.nc', on_sphere=True, sphere_radius=1.0) #convert to mpas grid specific format write_netcdf( convert(xarray.open_dataset(out_basepath + '_triangles.nc'), dir=out_dir, graphInfoFileName=out_basepath + "_graph.info"), out_filename)
def run(self): """ Run this step of the test case """ config = self.config section = config['soma'] options = dict( config_eos_linear_alpha=section.get('eos_linear_alpha'), config_soma_density_difference=section.get('density_difference'), config_soma_surface_temperature=section.get('surface_temperature'), config_soma_surface_salinity=section.get('surface_salinity'), config_soma_salinity_gradient=section.get('salinity_gradient'), config_soma_thermocline_depth=section.get('thermocline_depth'), config_soma_density_difference_linear=section.get( 'density_difference_linear'), config_soma_phi=section.get('phi'), config_soma_shelf_depth=section.get('shelf_depth'), config_soma_bottom_depth=section.get('bottom_depth')) for out_name in ['namelist_mark_land.ocean', 'namelist.ocean']: self.update_namelist_at_runtime(options=options, out_name=out_name) ds_mesh = convert(xarray.open_dataset('base_mesh.nc'), graphInfoFileName='base_graph.info', logger=self.logger) write_netcdf(ds_mesh, 'mesh.nc') run_model(self, namelist='namelist_mark_land.ocean', streams='streams_mark_land.ocean', graph_file='base_graph.info') ds_mesh = cull(xarray.open_dataset('masked_initial_state.nc'), graphInfoFileName='graph.info', logger=self.logger) write_netcdf(ds_mesh, 'culled_mesh.nc') run_model(self, namelist='namelist.ocean', streams='streams.ocean', graph_file='graph.info')
def run(self): """ Run this step of the test case """ mesh_type = self.mesh_type logger = self.logger config = self.config section = config['dome'] if mesh_type == '2000m': nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=True, nonperiodic_y=True) write_netcdf(dsMesh, 'grid.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, logger=logger) write_netcdf(dsMesh, 'mpas_grid.nc') levels = section.get('levels') args = [ 'create_landice_grid_from_generic_MPAS_grid.py', '-i', 'mpas_grid.nc', '-o', 'landice_grid.nc', '-l', levels ] check_call(args, logger) make_graph_file(mesh_filename='landice_grid.nc', graph_filename='graph.info') _setup_dome_initial_conditions(config, logger, filename='landice_grid.nc')
def run(self): """ Run this step of the test case """ config = self.config logger = self.logger section = config['ziso'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=False, nonperiodic_y=True) write_netcdf(dsMesh, 'base_mesh.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', logger=logger) write_netcdf(dsMesh, 'culled_mesh.nc') ds = _write_initial_state(config, dsMesh, self.with_frazil) _write_forcing(config, ds.yCell, ds.zMid)
def run(self): """ Run this step of the test case """ config = self.config logger = self.logger replacements = dict() replacements['config_periodic_planar_vert_levels'] = \ config.getfloat('vertical_grid', 'vert_levels') replacements['config_periodic_planar_bottom_depth'] = \ config.getfloat('vertical_grid', 'bottom_depth') self.update_namelist_at_runtime(options=replacements) section = config['vertical_grid'] vert_levels = section.getint('vert_levels') bottom_depth = section.getfloat('bottom_depth') section = config['internal_wave'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') use_distances = section.getboolean('use_distances') amplitude_width_dist = section.getfloat('amplitude_width_dist') amplitude_width_frac = section.getfloat('amplitude_width_frac') bottom_temperature = section.getfloat('bottom_temperature') surface_temperature = section.getfloat('surface_temperature') temperature_difference = section.getfloat('temperature_difference') salinity = section.getfloat('salinity') logger.info(' * Make planar hex mesh') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=False, nonperiodic_y=True) logger.info(' * Completed Make planar hex mesh') write_netcdf(dsMesh, 'base_mesh.nc') logger.info(' * Cull mesh') dsMesh = cull(dsMesh, logger=logger) logger.info(' * Convert mesh') dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', logger=logger) logger.info(' * Completed Convert mesh') write_netcdf(dsMesh, 'culled_mesh.nc') ds = dsMesh.copy() yCell = ds.yCell ds['bottomDepth'] = bottom_depth * xarray.ones_like(yCell) ds['ssh'] = xarray.zeros_like(yCell) init_vertical_coord(config, ds) yMin = yCell.min().values yMax = yCell.max().values yMid = 0.5 * (yMin + yMax) if use_distances: perturbation_width = amplitude_width_dist else: perturbation_width = (yMax - yMin) * amplitude_width_frac # Set stratified temperature temp_vert = (bottom_temperature + (surface_temperature - bottom_temperature) * ((ds.refZMid + bottom_depth) / bottom_depth)) depth_frac = xarray.zeros_like(temp_vert) refBottomDepth = ds['refBottomDepth'] for k in range(1, vert_levels): depth_frac[k] = refBottomDepth[k - 1] / refBottomDepth[vert_levels - 1] # If cell is in the southern half, outside the sin width, subtract # temperature difference frac = xarray.where( numpy.abs(yCell - yMid) < perturbation_width, numpy.cos(0.5 * numpy.pi * (yCell - yMid) / perturbation_width) * numpy.sin(numpy.pi * depth_frac), 0.) temperature = temp_vert - temperature_difference * frac temperature = temperature.transpose('nCells', 'nVertLevels') temperature = temperature.expand_dims(dim='Time', axis=0) normalVelocity = xarray.zeros_like(ds.xEdge) normalVelocity, _ = xarray.broadcast(normalVelocity, ds.refBottomDepth) normalVelocity = normalVelocity.transpose('nEdges', 'nVertLevels') normalVelocity = normalVelocity.expand_dims(dim='Time', axis=0) ds['temperature'] = temperature ds['salinity'] = salinity * xarray.ones_like(temperature) ds['normalVelocity'] = normalVelocity write_netcdf(ds, 'ocean.nc')
def waves_mesh(cfg): pwd = os.getcwd() src_path = pwd dst_path = pwd opts = jigsawpy.jigsaw_jig_t() hfun = jigsawpy.jigsaw_msh_t() mesh = jigsawpy.jigsaw_msh_t() init = jigsawpy.jigsaw_msh_t() #------------------------------------ setup files for JIGSAW opts.geom_file = \ str(Path(dst_path)/"geom.msh") # GEOM file opts.jcfg_file = \ str(Path(dst_path)/"jcfg.jig") # JCFG file opts.hfun_file = \ str(Path(dst_path)/"hfun.msh") # HFUN file opts.mesh_file = \ str(Path(dst_path)/"mesh.msh") # MESH file opts.init_file = \ str(Path(dst_path)/"init.msh") # INIT file #------------------------------------ define JIGSAW geometry if cfg['coastlines']: print('Defining coastline geometry') create_coastline_geometry(cfg['shpfiles'], opts.geom_file, cfg['sphere_radius']) else: geom = jigsawpy.jigsaw_msh_t() geom.mshID = 'ELLIPSOID-MESH' geom.radii = cfg['sphere_radius'] * np.ones(3, float) jigsawpy.savemsh(opts.geom_file, geom) #------------------------------------ define mesh size function print('Defining mesh size function') lon_min = -180.0 lon_max = 180.0 dlon = cfg['hfun_grid_spacing'] nlon = int((lon_max - lon_min) / dlon) + 1 lat_min = -90.0 lat_max = 90.0 nlat = int((lat_max - lat_min) / dlon) + 1 dlat = cfg['hfun_grid_spacing'] xlon = np.linspace(lon_min, lon_max, nlon) ylat = np.linspace(lat_min, lat_max, nlat) print(' hfun grid dimensions: {}, {}'.format(xlon.size, ylat.size)) define_hfunction.depth_threshold_refined = cfg['depth_threshold_refined'] define_hfunction.distance_threshold_refined = cfg[ 'distance_threshold_refined'] define_hfunction.depth_threshold_global = cfg['depth_threshold_global'] define_hfunction.distance_threshold_global = cfg[ 'distance_threshold_global'] define_hfunction.refined_res = cfg['refined_res'] define_hfunction.maxres = cfg['maxres'] hfunction = define_hfunction.cell_widthVsLatLon(xlon, ylat, cfg['shpfiles'], cfg['sphere_radius'], cfg['ocean_mesh']) hfunction = hfunction / km hfun.mshID = "ellipsoid-grid" hfun.radii = np.full(3, cfg['sphere_radius'], dtype=jigsawpy.jigsaw_msh_t.REALS_t) hfun.xgrid = np.radians(xlon) hfun.ygrid = np.radians(ylat) hfun.value = hfunction.astype(jigsawpy.jigsaw_msh_t.REALS_t) #------------------------------------ specify JIGSAW initial conditions print('Specifying initial fixed coordinate locations') create_initial_points(cfg['ocean_mesh'], xlon, ylat, hfunction, cfg['sphere_radius'], opts.init_file) jigsawpy.loadmsh(opts.init_file, init) jigsawpy.savevtk(str(Path(dst_path) / "init.vtk"), init) #------------------------------------ set HFUN grad.-limiter print('Limiting mesh size function gradients') hfun.slope = np.full( # |dH/dx| limits hfun.value.shape, cfg['hfun_slope_lim'], dtype=hfun.REALS_t) jigsawpy.savemsh(opts.hfun_file, hfun) jigsawpy.cmd.marche(opts, hfun) #------------------------------------ make mesh using JIGSAW opts.hfun_scal = "absolute" opts.hfun_hmax = float("inf") # null HFUN limits opts.hfun_hmin = float(+0.00) opts.mesh_dims = +2 # 2-dim. simplexes opts.mesh_eps1 = +.67 # relax edge error opts.mesh_rad2 = +1.2 opts.optm_qlim = +9.5E-01 # tighter opt. tol opts.optm_iter = +32 opts.optm_qtol = +1.0E-05 opts.verbosity = 2 #jigsawpy.cmd.tetris(opts, 3, mesh) jigsawpy.cmd.jigsaw(opts, mesh) if cfg['coastlines']: segment.segment(mesh) #------------------------------------ save mesh for Paraview print("Writing ex_h.vtk file.") jigsawpy.savevtk(str(Path(dst_path) / "_hfun.vtk"), hfun) jigsawpy.savevtk(str(Path(dst_path) / "waves_mesh.vtk"), mesh) jigsawpy.savemsh(str(Path(dst_path) / "waves_mesh.msh"), mesh) #------------------------------------ convert mesh to MPAS format jigsaw_to_netcdf(msh_filename='waves_mesh.msh', output_name='waves_mesh_triangles.nc', on_sphere=True, sphere_radius=cfg['sphere_radius']) write_netcdf( convert(xarray.open_dataset('waves_mesh_triangles.nc'), dir='./', logger=None), 'waves_mesh.nc') #------------------------------------ cull mesh to ocean bounary if os.path.exists('./cull_waves_mesh'): f = open('cull_waves_mesh.nml', 'w') f.write('&inputs\n') f.write(" waves_mesh_file = 'waves_mesh.nc'\n") f.write(" ocean_mesh_file = '" + cfg['ocean_mesh'] + "'\n") f.write("/\n") f.write('&output\n') f.write(" waves_mesh_culled_vtk = 'waves_mesh_culled.vtk'\n") f.write(" waves_mesh_culled_gmsh = 'waves_mesh_culled.msh'\n") f.write("/\n") f.close() subprocess.call('./cull_waves_mesh', shell=True) #------------------------------------ output ocean mesh polygons subprocess.call('paraview_vtk_field_extractor.py -f ' + cfg['ocean_mesh'] + ' --ignore_time -v areaCell -o ' + cfg['ocean_mesh'] + '.vtk', shell=True) return
def run(self): """ Run this step of the test case """ config = self.config logger = self.logger section = config['ice_shelf_2d'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=False, nonperiodic_y=True) write_netcdf(dsMesh, 'base_mesh.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', logger=logger) write_netcdf(dsMesh, 'culled_mesh.nc') bottom_depth = config.getfloat('vertical_grid', 'bottom_depth') section = config['ice_shelf_2d'] temperature = section.getfloat('temperature') surface_salinity = section.getfloat('surface_salinity') bottom_salinity = section.getfloat('bottom_salinity') # points 1 and 2 are where angles on ice shelf are located. # point 3 is at the surface. # d variables are total water-column thickness below ice shelf y1 = section.getfloat('y1') y2 = section.getfloat('y2') y3 = y2 + section.getfloat('edge_width') d1 = section.getfloat('cavity_thickness') d2 = d1 + section.getfloat('slope_height') d3 = bottom_depth ds = dsMesh.copy() ds['bottomDepth'] = bottom_depth * xarray.ones_like(ds.xCell) yCell = ds.yCell column_thickness = xarray.where( yCell < y1, d1, d1 + (d2 - d1) * (yCell - y1) / (y2 - y1)) column_thickness = xarray.where( yCell < y2, column_thickness, d2 + (d3 - d2) * (yCell - y2) / (y3 - y2)) column_thickness = xarray.where(yCell < y3, column_thickness, d3) ds['ssh'] = -bottom_depth + column_thickness # set up the vertical coordinate init_vertical_coord(config, ds) modify_mask = xarray.where(yCell < y3, 1, 0).expand_dims( dim='Time', axis=0) landIceFraction = modify_mask.astype(float) landIceMask = modify_mask.copy() ref_density = constants['SHR_CONST_RHOSW'] landIcePressure, landIceDraft = compute_land_ice_pressure_and_draft( ssh=ds.ssh, modify_mask=modify_mask, ref_density=ref_density) salinity = surface_salinity + ((bottom_salinity - surface_salinity) * (ds.zMid / (-bottom_depth))) salinity, _ = xarray.broadcast(salinity, ds.layerThickness) salinity = salinity.transpose('Time', 'nCells', 'nVertLevels') normalVelocity = xarray.zeros_like(ds.xEdge) normalVelocity, _ = xarray.broadcast(normalVelocity, ds.refBottomDepth) normalVelocity = normalVelocity.transpose('nEdges', 'nVertLevels') normalVelocity = normalVelocity.expand_dims(dim='Time', axis=0) ds['temperature'] = temperature * xarray.ones_like(ds.layerThickness) ds['salinity'] = salinity ds['normalVelocity'] = normalVelocity ds['fCell'] = xarray.zeros_like(ds.xCell) ds['fEdge'] = xarray.zeros_like(ds.xEdge) ds['fVertex'] = xarray.zeros_like(ds.xVertex) ds['modifyLandIcePressureMask'] = modify_mask ds['landIceFraction'] = landIceFraction ds['landIceMask'] = landIceMask ds['landIcePressure'] = landIcePressure ds['landIceDraft'] = landIceDraft write_netcdf(ds, 'initial_state.nc')
def saveesm(path, geom, mesh, preserve_floodplain=False, floodplain_elevation=20.0, do_inject_elevation=False, with_cavities=False, lat_threshold=43.00, with_critical_passages=True): """ SAVEESM: export a jigsaw mesh obj. to MPAS-style output. 1. Writes "mesh_triangles.nc" and "base_mesh.nc" files. 2. (Optionally) injects elevation + floodplain data. 3. Calls MPAS-Tools + Geometric-Data to cull mesh into ocean/land partitions. 4. Writes "culled_mesh.nc" (ocean) and "invert_mesh.nc" (land) MPAS-spec. output files. Data is written to "../path/out/" and/or "../path/tmp/". """ # Authors: Darren Engwirda ttic = time.time() print("") print("Running MPAS mesh-tools...") inject_edge_tags(mesh) # adapted from BUILD_MESH.py if (geom.mshID.lower() == "ellipsoid-mesh"): print("Forming mesh_triangles.nc") jigsaw_mesh_to_netcdf(mesh=mesh, on_sphere=True, sphere_radius=np.mean(geom.radii) * 1e3, output_name=os.path.join(path, "tmp", "mesh_triangles.nc")) if (geom.mshID.lower() == "euclidean-mesh"): print("Forming mesh_triangles.nc") jigsaw_mesh_to_netcdf(mesh=mesh, on_sphere=False, output_name=os.path.join(path, "tmp", "mesh_triangles.nc")) print("Forming base_mesh.nc") write_netcdf(convert( xarray.open_dataset(os.path.join(path, "tmp", "mesh_triangles.nc"))), fileName=os.path.join(path, "out", "base_mesh.nc")) """ if do_inject_elevation: print("Injecting cell elevations") inject_elevation( cell_elev=mesh.value, mesh_file=os.path.join( path, "out", "base_mesh.nc")) """ if preserve_floodplain: print("Injecting floodplain flag") inject_preserve_floodplain(mesh_file=os.path.join( path, "out", "base_mesh.nc"), floodplain_elevation=floodplain_elevation) args = [ "paraview_vtk_field_extractor.py", "--ignore_time", "-l", "-d", "maxEdges=0", "-v", "allOnCells", "-f", os.path.join(path, "out", "base_mesh.nc"), "-o", os.path.join(path, "out", "base_mesh_vtk") ] print("") print("running:", " ".join(args)) subprocess.check_call(args, env=os.environ.copy()) # adapted from CULL_MESH.py # required for compatibility with MPAS netcdfFormat = "NETCDF3_64BIT" gf = GeometricFeatures(cacheLocation="{}".format( os.path.join(HERE, "..", "data", "geometric_data"))) # start with the land coverage from Natural Earth fcLandCoverage = gf.read(componentName="natural_earth", objectType="region", featureNames=["Land Coverage"]) # remove the region south of 60S so we can replace # it based on ice-sheet topography fcSouthMask = gf.read(componentName="ocean", objectType="region", featureNames=["Global Ocean 90S to 60S"]) fcLandCoverage = \ fcLandCoverage.difference(fcSouthMask) # add land coverage from either the full ice sheet # or just the grounded part if with_cavities: fcAntarcticLand = gf.read( componentName="bedmap2", objectType="region", featureNames=["AntarcticGroundedIceCoverage"]) else: fcAntarcticLand = gf.read(componentName="bedmap2", objectType="region", featureNames=["AntarcticIceCoverage"]) fcLandCoverage.merge(fcAntarcticLand) # save the feature collection to a geojson file fcLandCoverage.to_geojson( os.path.join(path, "tmp", "land_coverage.geojson")) # Create the land mask based on the land coverage, # i.e. coastline data. dsBaseMesh = xarray.open_dataset(os.path.join(path, "out", "base_mesh.nc")) dsLandMask = mask(dsBaseMesh, fcMask=fcLandCoverage) dsLandMask = add_land_locked_cells_to_mask( dsLandMask, dsBaseMesh, latitude_threshold=lat_threshold, nSweeps=20) if with_critical_passages: # merge transects for critical passages into # critical_passages.geojson fcCritPassages = gf.read(componentName="ocean", objectType="transect", tags=["Critical_Passage"]) # create masks from the transects dsCritPassMask = \ mask(dsBaseMesh, fcMask=fcCritPassages) # Alter critical passages to be at least two # cells wide, to avoid sea ice blockage. dsCritPassMask = widen_transect_edge_masks( dsCritPassMask, dsBaseMesh, latitude_threshold=lat_threshold) dsLandMask = subtract_critical_passages(dsLandMask, dsCritPassMask) # merge transects for critical land blockages # into critical_land_blockages.geojson fcCritBlockages = gf.read(componentName="ocean", objectType="transect", tags=["Critical_Land_Blockage"]) # create masks from the transects for critical # land blockages dsCritBlockMask = \ mask(dsBaseMesh, fcMask=fcCritBlockages) dsLandMask = add_critical_land_blockages(dsLandMask, dsCritBlockMask) # create seed points for a flood fill of the ocean # use all points in the ocean directory, on the # assumption that they are, in fact *in* the ocean fcSeed = gf.read(componentName="ocean", objectType="point", tags=["seed_point"]) # update the land mask to ensure all ocean cells really # are "reachable" from the rest of the global ocean dsLandMask = mask_reachable_ocean(dsMesh=dsBaseMesh, dsMask=dsLandMask, fcSeed=fcSeed) # cull the (ocean) mesh based on the land mask, and a # cull the (land) mesh using the inverse mask if preserve_floodplain: # with "preserve_floodplains", the (ocean) mesh will # contain overlap with the (land) mesh, otherwise the # two are "perfectly" disjoint dsCulledMesh = cull(dsBaseMesh, dsMask=dsLandMask, dsPreserve=dsBaseMesh, graphInfoFileName=os.path.join( path, "out", "culled_graph.info")) dsInvertMesh = cull(dsBaseMesh, dsInverse=dsLandMask, graphInfoFileName=os.path.join( path, "out", "invert_graph.info")) else: dsCulledMesh = cull(dsBaseMesh, dsMask=dsLandMask, graphInfoFileName=os.path.join( path, "out", "culled_graph.info")) dsInvertMesh = cull(dsBaseMesh, dsInverse=dsLandMask, graphInfoFileName=os.path.join( path, "out", "invert_graph.info")) write_netcdf(dsCulledMesh, os.path.join(path, "out", "culled_mesh.nc"), netcdfFormat) write_netcdf(dsInvertMesh, os.path.join(path, "out", "invert_mesh.nc"), netcdfFormat) args = [ "paraview_vtk_field_extractor.py", "--ignore_time", "-d", "maxEdges=", "-v", "allOnCells", "-f", os.path.join(path, "out", "culled_mesh.nc"), "-o", os.path.join(path, "out", "culled_mesh_vtk") ] print("") print("running", " ".join(args)) subprocess.check_call(args, env=os.environ.copy()) args = [ "paraview_vtk_field_extractor.py", "--ignore_time", "-d", "maxEdges=", "-v", "allOnCells", "-f", os.path.join(path, "out", "invert_mesh.nc"), "-o", os.path.join(path, "out", "invert_mesh_vtk") ] print("running", " ".join(args)) subprocess.check_call(args, env=os.environ.copy()) ttoc = time.time() print("CPUSEC =", (ttoc - ttic)) return
def run(self): """ Run this step of the test case """ logger = self.logger config = self.config section = config['humboldt'] logger.info('calling build_cell_wdith') cell_width, x1, y1, geom_points, geom_edges = self.build_cell_width() logger.info('calling build_planar_mesh') build_planar_mesh(cell_width, x1, y1, geom_points, geom_edges, logger=logger) dsMesh = xarray.open_dataset('base_mesh.nc') logger.info('culling mesh') dsMesh = cull(dsMesh, logger=logger) logger.info('converting to MPAS mesh') dsMesh = convert(dsMesh, logger=logger) logger.info('writing grid_converted.nc') write_netcdf(dsMesh, 'grid_converted.nc') # If no number of levels specified in config file, use 10 levels = section.get('levels') logger.info('calling create_landice_grid_from_generic_MPAS_grid.py') args = [ 'create_landice_grid_from_generic_MPAS_grid.py', '-i', 'grid_converted.nc', '-o', 'gis_1km_preCull.nc', '-l', levels, '-v', 'glimmer' ] check_call(args, logger=logger) # This step uses a subset of the whole Greenland dataset trimmed to # the region around Humboldt Glacier, to speed up interpolation. # This could also be replaced with the full Greenland Ice Sheet # dataset. logger.info('calling interpolate_to_mpasli_grid.py') args = [ 'interpolate_to_mpasli_grid.py', '-s', 'humboldt_1km_2020_04_20.epsg3413.icesheetonly.nc', '-d', 'gis_1km_preCull.nc', '-m', 'b', '-t' ] check_call(args, logger=logger) # This step is only necessary if you wish to cull a certain # distance from the ice margin, within the bounds defined by # the GeoJSON file. cullDistance = section.get('cullDistance') if float(cullDistance) > 0.: logger.info('calling define_cullMask.py') args = [ 'define_cullMask.py', '-f', 'gis_1km_preCull.nc', '-m' 'distance', '-d', cullDistance ] check_call(args, logger=logger) else: logger.info('cullDistance <= 0 in config file. ' 'Will not cull by distance to margin. \n') # This step is only necessary because the GeoJSON region # is defined by lat-lon. logger.info('calling set_lat_lon_fields_in_planar_grid.py') args = [ 'set_lat_lon_fields_in_planar_grid.py', '-f', 'gis_1km_preCull.nc', '-p', 'gis-gimp' ] check_call(args, logger=logger) logger.info('calling MpasMaskCreator.x') args = [ 'MpasMaskCreator.x', 'gis_1km_preCull.nc', 'humboldt_mask.nc', '-f', 'Humboldt.geojson' ] check_call(args, logger=logger) logger.info('culling to geojson file') dsMesh = xarray.open_dataset('gis_1km_preCull.nc') humboldtMask = xarray.open_dataset('humboldt_mask.nc') dsMesh = cull(dsMesh, dsInverse=humboldtMask, logger=logger) write_netcdf(dsMesh, 'humboldt_culled.nc') logger.info('Marking horns for culling') args = ['mark_horns_for_culling.py', '-f', 'humboldt_culled.nc'] check_call(args, logger=logger) logger.info('culling and converting') dsMesh = xarray.open_dataset('humboldt_culled.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, logger=logger) write_netcdf(dsMesh, 'humboldt_dehorned.nc') logger.info('calling create_landice_grid_from_generic_MPAS_grid.py') args = [ 'create_landice_grid_from_generic_MPAS_grid.py', '-i', 'humboldt_dehorned.nc', '-o', 'Humboldt_1to10km.nc', '-l', levels, '-v', 'glimmer', '--beta', '--thermal', '--obs', '--diri' ] check_call(args, logger=logger) logger.info('calling interpolate_to_mpasli_grid.py') args = [ 'interpolate_to_mpasli_grid.py', '-s', 'humboldt_1km_2020_04_20.epsg3413.icesheetonly.nc', '-d', 'Humboldt_1to10km.nc', '-m', 'b', '-t' ] check_call(args, logger=logger) logger.info('Marking domain boundaries dirichlet') args = [ 'mark_domain_boundaries_dirichlet.py', '-f', 'Humboldt_1to10km.nc' ] check_call(args, logger=logger) logger.info('calling set_lat_lon_fields_in_planar_grid.py') args = [ 'set_lat_lon_fields_in_planar_grid.py', '-f', 'Humboldt_1to10km.nc', '-p', 'gis-gimp' ] check_call(args, logger=logger) logger.info('creating graph.info') make_graph_file(mesh_filename='Humboldt_1to10km.nc', graph_filename='graph.info')
def run(self): """ Run this step of the test case """ config = self.config logger = self.logger section = config['baroclinic_channel'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=False, nonperiodic_y=True) write_netcdf(dsMesh, 'base_mesh.nc') dsMesh = cull(dsMesh, logger=logger) dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', logger=logger) write_netcdf(dsMesh, 'culled_mesh.nc') section = config['baroclinic_channel'] use_distances = section.getboolean('use_distances') gradient_width_dist = section.getfloat('gradient_width_dist') gradient_width_frac = section.getfloat('gradient_width_frac') bottom_temperature = section.getfloat('bottom_temperature') surface_temperature = section.getfloat('surface_temperature') temperature_difference = section.getfloat('temperature_difference') salinity = section.getfloat('salinity') coriolis_parameter = section.getfloat('coriolis_parameter') ds = dsMesh.copy() xCell = ds.xCell yCell = ds.yCell bottom_depth = config.getfloat('vertical_grid', 'bottom_depth') ds['bottomDepth'] = bottom_depth * xarray.ones_like(xCell) ds['ssh'] = xarray.zeros_like(xCell) init_vertical_coord(config, ds) xMin = xCell.min().values xMax = xCell.max().values yMin = yCell.min().values yMax = yCell.max().values yMid = 0.5 * (yMin + yMax) xPerturbMin = xMin + 4.0 * (xMax - xMin) / 6.0 xPerturbMax = xMin + 5.0 * (xMax - xMin) / 6.0 if use_distances: perturbationWidth = gradient_width_dist else: perturbationWidth = (yMax - yMin) * gradient_width_frac yOffset = perturbationWidth * numpy.sin(6.0 * numpy.pi * (xCell - xMin) / (xMax - xMin)) temp_vert = (bottom_temperature + (surface_temperature - bottom_temperature) * ((ds.refZMid + bottom_depth) / bottom_depth)) frac = xarray.where(yCell < yMid - yOffset, 1., 0.) mask = numpy.logical_and(yCell >= yMid - yOffset, yCell < yMid - yOffset + perturbationWidth) frac = xarray.where( mask, 1. - (yCell - (yMid - yOffset)) / perturbationWidth, frac) temperature = temp_vert - temperature_difference * frac temperature = temperature.transpose('nCells', 'nVertLevels') # Determine yOffset for 3rd crest in sin wave yOffset = 0.5 * perturbationWidth * numpy.sin( numpy.pi * (xCell - xPerturbMin) / (xPerturbMax - xPerturbMin)) mask = numpy.logical_and( numpy.logical_and( yCell >= yMid - yOffset - 0.5 * perturbationWidth, yCell <= yMid - yOffset + 0.5 * perturbationWidth), numpy.logical_and(xCell >= xPerturbMin, xCell <= xPerturbMax)) temperature = (temperature + mask * 0.3 * (1. - ((yCell - (yMid - yOffset)) / (0.5 * perturbationWidth)))) temperature = temperature.expand_dims(dim='Time', axis=0) normalVelocity = xarray.zeros_like(ds.xEdge) normalVelocity, _ = xarray.broadcast(normalVelocity, ds.refBottomDepth) normalVelocity = normalVelocity.transpose('nEdges', 'nVertLevels') normalVelocity = normalVelocity.expand_dims(dim='Time', axis=0) ds['temperature'] = temperature ds['salinity'] = salinity * xarray.ones_like(temperature) ds['normalVelocity'] = normalVelocity ds['fCell'] = coriolis_parameter * xarray.ones_like(xCell) ds['fEdge'] = coriolis_parameter * xarray.ones_like(ds.xEdge) ds['fVertex'] = coriolis_parameter * xarray.ones_like(ds.xVertex) write_netcdf(ds, 'ocean.nc')
def run(self): """ Run this step of the test case """ config = self.config logger = self.logger section = config['isomip_plus'] nx = section.getint('nx') ny = section.getint('ny') dc = section.getfloat('dc') filter_sigma = section.getfloat('topo_smoothing') * self.resolution min_ice_thickness = section.getfloat('min_ice_thickness') min_land_ice_fraction = section.getfloat('min_land_ice_fraction') draft_scaling = section.getfloat('draft_scaling') process_input_geometry('input_geometry.nc', 'input_geometry_processed.nc', filterSigma=filter_sigma, minIceThickness=min_ice_thickness, scale=draft_scaling) dsMesh = make_planar_hex_mesh(nx=nx + 2, ny=ny + 2, dc=dc, nonperiodic_x=False, nonperiodic_y=False) translate(mesh=dsMesh, yOffset=-2 * dc) write_netcdf(dsMesh, 'base_mesh.nc') dsGeom = xarray.open_dataset('input_geometry_processed.nc') min_ocean_fraction = config.getfloat('isomip_plus', 'min_ocean_fraction') dsMask = interpolate_ocean_mask(dsMesh, dsGeom, min_ocean_fraction) dsMesh = cull(dsMesh, dsInverse=dsMask, logger=logger) dsMesh.attrs['is_periodic'] = 'NO' dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', logger=logger) write_netcdf(dsMesh, 'culled_mesh.nc') ds = interpolate_geom(dsMesh, dsGeom, min_ocean_fraction) for var in ['landIceFraction']: ds[var] = ds[var].expand_dims(dim='Time', axis=0) ds['landIceMask'] = \ (ds.landIceFraction >= min_land_ice_fraction).astype(int) ref_density = constants['SHR_CONST_RHOSW'] landIcePressure, landIceDraft = compute_land_ice_pressure_and_draft( ssh=ds.ssh, modify_mask=ds.ssh < 0., ref_density=ref_density) ds['landIcePressure'] = landIcePressure ds['landIceDraft'] = landIceDraft if self.time_varying_forcing: self._write_time_varying_forcing(ds_init=ds) ds['bottomDepth'] = -ds.bottomDepthObserved section = config['isomip_plus'] min_column_thickness = section.getfloat('min_column_thickness') min_levels = section.getint('minimum_levels') interfaces = generate_1d_grid(config) # Deepen the bottom depth to maintain the minimum water-column # thickness min_depth = numpy.maximum(-ds.ssh + min_column_thickness, interfaces[min_levels + 1]) ds['bottomDepth'] = numpy.maximum(ds.bottomDepth, min_depth) init_vertical_coord(config, ds) ds['modifyLandIcePressureMask'] = \ (ds['landIceFraction'] > 0.01).astype(int) max_bottom_depth = -config.getfloat('vertical_grid', 'bottom_depth') frac = (0. - ds.zMid) / (0. - max_bottom_depth) # compute T, S init_top_temp = section.getfloat('init_top_temp') init_bot_temp = section.getfloat('init_bot_temp') init_top_sal = section.getfloat('init_top_sal') init_bot_sal = section.getfloat('init_bot_sal') ds['temperature'] = (1.0 - frac) * init_top_temp + frac * init_bot_temp ds['salinity'] = (1.0 - frac) * init_top_sal + frac * init_bot_sal # compute coriolis coriolis_parameter = section.getfloat('coriolis_parameter') ds['fCell'] = coriolis_parameter * xarray.ones_like(ds.xCell) ds['fEdge'] = coriolis_parameter * xarray.ones_like(ds.xEdge) ds['fVertex'] = coriolis_parameter * xarray.ones_like(ds.xVertex) normalVelocity = xarray.zeros_like(ds.xEdge) normalVelocity = normalVelocity.broadcast_like(ds.refBottomDepth) normalVelocity = normalVelocity.transpose('nEdges', 'nVertLevels') ds['normalVelocity'] = normalVelocity.expand_dims(dim='Time', axis=0) write_netcdf(ds, 'initial_state.nc') plot_folder = '{}/plots'.format(self.work_dir) if os.path.exists(plot_folder): shutil.rmtree(plot_folder) # plot a few fields section_y = config.getfloat('isomip_plus_viz', 'section_y') # show progress only if we're not writing to a log file show_progress = self.log_filename is None plotter = MoviePlotter(inFolder=self.work_dir, streamfunctionFolder=self.work_dir, outFolder=plot_folder, expt=self.experiment, sectionY=section_y, dsMesh=ds, ds=ds, showProgress=show_progress) plotter.plot_3d_field_top_bot_section(ds.zMid, nameInTitle='zMid', prefix='zmid', units='m', vmin=-720., vmax=0., cmap='cmo.deep_r') plotter.plot_3d_field_top_bot_section(ds.temperature, nameInTitle='temperature', prefix='temp', units='C', vmin=-2., vmax=1., cmap='cmo.thermal') plotter.plot_3d_field_top_bot_section(ds.salinity, nameInTitle='salinity', prefix='salin', units='PSU', vmin=33.8, vmax=34.7, cmap='cmo.haline') # compute restoring dsForcing = xarray.Dataset() restore_top_temp = section.getfloat('restore_top_temp') restore_bot_temp = section.getfloat('restore_bot_temp') restore_top_sal = section.getfloat('restore_top_sal') restore_bot_sal = section.getfloat('restore_bot_sal') dsForcing['temperatureInteriorRestoringValue'] = \ (1.0 - frac) * restore_top_temp + frac * restore_bot_temp dsForcing['salinityInteriorRestoringValue'] = \ (1.0 - frac) * restore_top_sal + frac * restore_bot_sal restore_rate = section.getfloat('restore_rate') restore_xmin = section.getfloat('restore_xmin') restore_xmax = section.getfloat('restore_xmax') frac = numpy.maximum( (ds.xCell - restore_xmin) / (restore_xmax - restore_xmin), 0.) frac = frac.broadcast_like(dsForcing.temperatureInteriorRestoringValue) # convert from 1/days to 1/s dsForcing['temperatureInteriorRestoringRate'] = \ frac * restore_rate / constants['SHR_CONST_CDAY'] dsForcing['salinityInteriorRestoringRate'] = \ dsForcing.temperatureInteriorRestoringRate # compute "evaporation" restore_evap_rate = section.getfloat('restore_evap_rate') mask = numpy.logical_and(ds.xCell >= restore_xmin, ds.xCell <= restore_xmax) mask = mask.expand_dims(dim='Time', axis=0) # convert to m/s, negative for evaporation rather than precipitation evap_rate = -restore_evap_rate / (constants['SHR_CONST_CDAY'] * 365) # PSU*m/s to kg/m^2/s sflux_factor = 1. # C*m/s to W/m^2 hflux_factor = 1. / (ref_density * constants['SHR_CONST_CPSW']) dsForcing['evaporationFlux'] = mask * ref_density * evap_rate dsForcing['seaIceSalinityFlux'] = \ mask*evap_rate*restore_top_sal/sflux_factor dsForcing['seaIceHeatFlux'] = \ mask*evap_rate*restore_top_temp/hflux_factor write_netcdf(dsForcing, 'init_mode_forcing_data.nc')