def split_features(): ''' Features in the collection are split into individual files in the geometric_data cache ''' parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument("-f", "--feature_file", dest="feature_file", help="File containing features to split up", metavar="FILE", required=True) parser.add_argument("-o", "--output_dir", dest="output_dir_name", help="Output directory, default is determined by the " "component property", metavar="PATH", default="./geometric_data") parser.add_argument('-v', '--version', action='version', version='geometric_features {}'.format( geometric_features.__version__), help="Show version number and exit") args = parser.parse_args() fc = read_feature_collection(args.feature_file) gf = GeometricFeatures() gf.split(fc, args.output_dir_name)
def transects_and_regions(config): # {{{ mesh_name = config.get('mesh', 'long_name') ice_shelf_cavities = config.getboolean('main', 'ice_shelf_cavities') make_moc_masks(mesh_name) gf = GeometricFeatures() features = [ 'Southern Ocean', 'Southern Ocean 60S', 'Eastern Weddell Sea Shelf', 'Eastern Weddell Sea Deep', 'Western Weddell Sea Shelf', 'Western Weddell Sea Deep', 'Weddell Sea Shelf', 'Weddell Sea Deep', 'Bellingshausen Sea Shelf', 'Bellingshausen Sea Deep', 'Amundsen Sea Shelf', 'Amundsen Sea Deep', 'Eastern Ross Sea Shelf', 'Eastern Ross Sea Deep', 'Western Ross Sea Shelf', 'Western Ross Sea Deep', 'East Antarctic Seas Shelf', 'East Antarctic Seas Deep' ] fcMask = gf.read('ocean', 'region', features) make_region_masks(mesh_name, suffix='antarcticRegions', fcMask=fcMask) fcMask = gf.read('ocean', 'region', tags=['Arctic']) make_region_masks(mesh_name, suffix='arcticRegions', fcMask=fcMask) fcMask = make_ocean_basins_masks(gf) make_region_masks(mesh_name, suffix='oceanBasins', fcMask=fcMask) fcMask = gf.read('ocean', 'transect') make_region_masks(mesh_name, suffix='transportTransects', fcMask=fcMask) if ice_shelf_cavities: fcMask = make_ice_shelf_masks(gf) make_region_masks(mesh_name, suffix='iceShelfMasks', fcMask=fcMask)
def make_moc_masks(mesh_name): # {{{ gf = GeometricFeatures() mesh_filename = '../mesh.nc' mask_filename = '{}_moc_masks.nc'.format(mesh_name) mask_and_transect_filename = '{}_moc_masks_and_transects.nc'.format( mesh_name) geojson_filename = 'moc_basins.geojson' make_moc_basins_and_transects(gf, mesh_filename, mask_and_transect_filename, geojson_filename=geojson_filename, mask_filename=mask_filename) # make links in output directories (both inputdata and diagnostics) output_dir = '../assembled_files_for_upload/inputdata/ocn/mpas-o/{}'.format( mesh_name) make_link( '../../../../../transects_and_regions/{}'.format( mask_and_transect_filename), '{}/{}'.format(output_dir, mask_and_transect_filename)) output_dir = '../assembled_files_for_upload/diagnostics/mpas_analysis/' \ 'region_masks' make_link( '../../../../transects_and_regions/{}'.format( mask_and_transect_filename), '{}/{}'.format(output_dir, mask_and_transect_filename))
def _make_moc_masks(mesh_short_name, logger, cores): gf = GeometricFeatures() mesh_filename = 'restart.nc' function, prefix, date = get_aggregator_by_name('MOC Basins') fcMask = function(gf) suffix = '{}{}'.format(prefix, date) geojson_filename = '{}.geojson'.format(suffix) mask_filename = '{}_{}.nc'.format(mesh_short_name, suffix) fcMask.to_geojson(geojson_filename) # these defaults may have been updated from config options -- pass them # along to the subprocess netcdf_format = mpas_tools.io.default_format netcdf_engine = mpas_tools.io.default_engine args = ['compute_mpas_region_masks', '-m', mesh_filename, '-g', geojson_filename, '-o', mask_filename, '-t', 'cell', '--process_count', '{}'.format(cores), '--format', netcdf_format, '--engine', netcdf_engine] check_call(args, logger=logger) mask_and_transect_filename = '{}_mocBasinsAndTransects{}.nc'.format( mesh_short_name, date) dsMesh = xarray.open_dataset(mesh_filename) dsMask = xarray.open_dataset(mask_filename) dsMasksAndTransects = add_moc_southern_boundary_transects( dsMask, dsMesh, logger=logger) write_netcdf(dsMasksAndTransects, mask_and_transect_filename, char_dim_name='StrLen') # make links in output directories (both inputdata and diagnostics) output_dir = '../assembled_files/inputdata/ocn/mpas-o/{}'.format( mesh_short_name) symlink( '../../../../../diagnostics_files/{}'.format( mask_and_transect_filename), '{}/{}'.format(output_dir, mask_and_transect_filename)) output_dir = '../assembled_files/diagnostics/mpas_analysis/' \ 'region_masks' symlink( '../../../../diagnostics_files/{}'.format( mask_and_transect_filename), '{}/{}'.format(output_dir, mask_and_transect_filename))
def make_transect_mask(self): """ If the geojson mask file has not already been cached in the diagnostics or custom diagnostic directories, it will be created in the analysis output's masks directory. """ function = self.region['function'] filename = self.geojsonFileName if not os.path.exists(filename): gf = GeometricFeatures() fc = function(gf) fc.to_geojson(filename)
def test_assign_groupname(self, componentName='ocean', objectType='region', featureName='Celtic Sea', groupName='testGroupName'): """ Write example file to test groupName functionality. Parameters ---------- componentName : {'bedmap2', 'iceshelves', 'landice', 'natural_earth', 'ocean'}, optional The component from which to retieve the feature objectType : {'point', 'transect', 'region'}, optional The type of geometry to load, a point (0D), transect (1D) or region (2D) featureName : str, optional The names of geometric feature to read groupName : str, optional The group name to assign """ # Authors # ------- # Phillip J. Wolfram # Xylar Asay-Davis # verification that groupName is in file def verify_groupName(destfile, groupName): with open(destfile) as f: filevals = json.load(f) assert 'groupName' in filevals, \ 'groupName does not exist in {}'.format(destfile) assert filevals['groupName'] == groupName, \ 'Incorrect groupName of {} specified instead of ' \ '{}.'.format(filevals['groupName'], groupName) # test via shell script gf = GeometricFeatures(cacheLocation=str(self.datadir), remoteBranchOrTag='master') fc = gf.read(componentName, objectType, [featureName]) fc.set_group_name(groupName) assert fc.otherProperties['groupName'] == groupName, \ 'groupName not assigned to FeatureCollection' destfile = str(self.datadir.join('test.geojson')) fc.to_geojson(destfile) verify_groupName(destfile, groupName)
#!/usr/bin/env python """ Create a geojson file with the standard transport transects """ from geometric_features import GeometricFeatures # create a GeometricFeatures object that knows which geometric data we want gf = GeometricFeatures() # create a FeatureCollection to which we will add all regions fc = gf.read(componentName='ocean', objectType='transect', tags=['standard_transport_sections']) # save the feature collection to a geojson file fc.to_geojson('transportTransects20200621.geojson')
iceMask = numpy.logical_or(iceMask, bedMask) groundedMask = numpy.logical_or(groundedMask, bedMask) masks = dict() masks['AntarcticIceCoverage'] = iceMask masks['AntarcticGroundedIceCoverage'] = groundedMask fc = FeatureCollection() for name in masks: properties = dict() properties['name'] = name properties['component'] = 'bedmachine' properties['author'] = \ 'Morlighem et al. (2019) doi:10.1038/s41561-019-0510-8' properties['object'] = 'region' properties['tags'] = '' feature = dict() feature['properties'] = properties feature['geometry'] = extract_geometry(masks[name]) fc.add_feature(feature) fc.to_geojson(out_file_name) gf = GeometricFeatures(cacheLocation='./geometric_data') gf.split(fc) write_feature_names_and_tags(gf.cacheLocation) os.rename('features_and_tags.json', 'geometric_features/features_and_tags.json')
fcOut.add_feature(copy.deepcopy(feature)) else: print("{} has been removed.".format( feature['pproperties']['name'])) print(' * Removed {} small polygons'.format(removedCount)) return fcOut plot = True # create a GeometricFeatures object that points to a local cache of geometric # data and knows which branch of geometric_feature to use to download # missing data gf = GeometricFeatures('./geometric_data') fcOceanBasins = build_ocean_basins(gf, plot) fcOceanBasins.to_geojson('oceanBasins.geojson') fcMOC = build_MOC_basins(gf) fcMOC.to_geojson('MOCBasins.geojson') fcNino = build_Nino_regions(gf) fcNino.to_geojson('NinoRegions.geojson') if plot: fcOceanBasins.plot(projection='cyl') fcMOC.plot(projection='cyl') fcNino.plot(projection='cyl') plt.show()
def main(): author = 'Milena Veneziani' # make a geometric features object that knows about the geometric data # cache up a couple of directories gf = GeometricFeatures(cacheLocation='../../geometric_data') fc = FeatureCollection() # ********* OSNAP array West ********* # Read in OSNAP West lon,lat OSNAPwestLonLat = csv.reader(open('./OSNAParrayWest20210322.csv', 'r')) # Skip 4 header lines next(OSNAPwestLonLat, None) next(OSNAPwestLonLat, None) next(OSNAPwestLonLat, None) next(OSNAPwestLonLat, None) coords = [] for line in OSNAPwestLonLat: coords.append([float(line[0]), float(line[1])]) feature = {} feature['type'] = 'Feature' feature['properties'] = {} feature['properties']['name'] = 'OSNAP section West' feature['properties']['tags'] = 'arctic_sections' feature['properties']['object'] = 'transect' feature['properties']['component'] = 'ocean' feature['properties']['author'] = author feature['geometry'] = {} feature['geometry']['type'] = 'LineString' feature['geometry']['coordinates'] = coords fcOW = FeatureCollection([feature]) fcOW.plot(projection='northpole') fc.merge(fcOW) # ********* OSNAP array East ********* # Read in OSNAP East lon,lat OSNAPeastLonLat = csv.reader(open('./OSNAParrayEast20210322.csv', 'r')) # Skip 4 header lines next(OSNAPeastLonLat, None) next(OSNAPeastLonLat, None) next(OSNAPeastLonLat, None) next(OSNAPeastLonLat, None) coords = [] for line in OSNAPeastLonLat: coords.append([float(line[0]), float(line[1])]) feature = {} feature['type'] = 'Feature' feature['properties'] = {} feature['properties']['name'] = 'OSNAP section East' feature['properties']['tags'] = 'arctic_sections' feature['properties']['object'] = 'transect' feature['properties']['component'] = 'ocean' feature['properties']['author'] = author feature['geometry'] = {} feature['geometry']['type'] = 'LineString' feature['geometry']['coordinates'] = coords fcOE = FeatureCollection([feature]) fcOE.plot(projection='northpole') fc.merge(fcOE) # "split" these features into individual files in the geometric data cache gf.split(fc) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') plt.show()
def main(): author = 'Xylar Asay-Davis' timTags = 'Antarctic;Timmermann' orsiTags = 'Antarctic;Orsi' # make a geometric fieatures object that knows about the geometric data # cache up a couple of directories gf = GeometricFeatures('../../geometric_data') bedmap2_bin_to_netcdf('bedmap2.nc') fcContour700 = get_longest_contour(contourValue=-700., author=author) fcContour800 = get_longest_contour(contourValue=-800., author=author) fc = FeatureCollection() fcWeddell = split_rectangle(lon0=-63., lon1=0., lat0=-80., lat1=-65., name='Weddell Sea', author=author, tags=timTags, fcContour=fcContour800) # get rid of the Weddell Sea because we're not that happy with this # definition, but keep the deep/shelf ones fcWeddell.features = fcWeddell.features[1:] fc.merge(fcWeddell) fcEW = split_rectangle(lon0=-20., lon1=25., lat0=-80., lat1=-55., name='Eastern Weddell Sea', author=author, tags=orsiTags, fcContour=fcContour800) fc.merge(fcEW) fcWW = split_rectangle(lon0=-63., lon1=-20., lat0=-80., lat1=-60., name='Western Weddell Sea', author=author, tags=orsiTags, fcContour=fcContour800) fc.merge(fcWW) # The Weddell feature is the sum of the Eastern and Western features before # splitting into shelf/deep fcWeddell = FeatureCollection() fcWeddell.features.append(fcEW.features[0]) fcWeddell.features.append(fcWW.features[0]) # now combine these into a single feature fcWeddell = fcWeddell.combine('Weddell Sea') props = fcWeddell.features[0]['properties'] props['tags'] = orsiTags props['zmin'] = -1000. props['zmax'] = -400. fc.merge(fcWeddell) # add the Weddell Sea back as the sum of Eastern and Western fc.merge( make_rectangle(lon0=-63., lon1=45., lat0=-80., lat1=-58., name='Weddell Sea', author=author, tags=orsiTags)) fc.merge( split_rectangle(lon0=-100., lon1=-63., lat0=-80., lat1=-67., name='Bellingshausen Sea', author=author, tags=timTags, fcContour=fcContour700)) fc.merge( split_rectangle(lon0=-140., lon1=-100., lat0=-80., lat1=-67., name='Amundsen Sea', author=author, tags=timTags, fcContour=fcContour800)) fc.merge( split_rectangle(lon0=-180., lon1=-140., lat0=-80., lat1=-67., name='Eastern Ross Sea', author=author, tags=timTags, fcContour=fcContour700)) fc.merge( split_rectangle(lon0=160., lon1=180., lat0=-80., lat1=-67., name='Western Ross Sea', author=author, tags=timTags, fcContour=fcContour700)) fc.merge( split_rectangle(lon0=25., lon1=160., lat0=-80., lat1=-62., name='East Antarctic Seas', author=author, tags=orsiTags, fcContour=fcContour800)) fc.merge( make_rectangle(lon0=-180., lon1=180., lat0=-80., lat1=-60., name='Southern Ocean 60S', author=author, tags=timTags)) fcSO = gf.read('ocean', 'region', ['Southern Ocean']) props = fcSO.features[0]['properties'] props['zmin'] = -1000. props['zmax'] = -400. fc.merge(fcSO) fc.plot(projection='southpole') fc.to_geojson('antarctic_ocean_regions.geojson') # "split" these features into individual files in the geometric data cache gf.split(fc) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') plt.show()
"--geom_data_path", type="string", dest="path", default="geometric_data", help="Path to the geometric_data from the geometric_features" " repository.") parser.add_option("--preserve_floodplain", action="store_true", dest="preserve_floodplain", default=False) options, args = parser.parse_args() # required for compatibility with MPAS netcdfFormat = 'NETCDF3_64BIT' gf = GeometricFeatures(cacheLocation='{}'.format(options.path)) # 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
def make_diagnostics_files(config, logger, mesh_short_name, with_ice_shelf_cavities, cores): """ Run this step of the testcase Parameters ---------- config : configparser.ConfigParser Configuration options for this test case logger : logging.Logger A logger for output from the step mesh_short_name : str The E3SM short name of the mesh with_ice_shelf_cavities : bool Whether the mesh has ice-shelf cavities cores : int The number of cores to use to build mapping files """ for directory in [ '../assembled_files/inputdata/ocn/mpas-o/{}'.format( mesh_short_name), '../assembled_files/diagnostics/mpas_analysis/region_masks', '../assembled_files/diagnostics/mpas_analysis/maps']: try: os.makedirs(directory) except OSError: pass _make_moc_masks(mesh_short_name, logger, cores) gf = GeometricFeatures() region_groups = ['Antarctic Regions', 'Arctic Ocean Regions', 'Arctic Sea Ice Regions', 'Ocean Basins', 'Ocean Subbasins', 'ISMIP6 Regions'] if with_ice_shelf_cavities: region_groups.append('Ice Shelves') for region_group in region_groups: function, prefix, date = get_aggregator_by_name(region_group) suffix = '{}{}'.format(prefix, date) fcMask = function(gf) _make_region_masks(mesh_short_name, suffix=suffix, fcMask=fcMask, logger=logger, cores=cores) transect_groups = ['Transport Transects'] for transect_group in transect_groups: function, prefix, date = get_aggregator_by_name(transect_group) suffix = '{}{}'.format(prefix, date) fcMask = function(gf) _make_transect_masks(mesh_short_name, suffix=suffix, fcMask=fcMask, logger=logger, cores=cores) _make_analysis_lat_lon_map(config, mesh_short_name, cores, logger) _make_analysis_polar_map(config, mesh_short_name, projection='antarctic', cores=cores, logger=logger) _make_analysis_polar_map(config, mesh_short_name, projection='arctic', cores=cores, logger=logger) # make links in output directory files = glob.glob('map_*') # make links in output directory output_dir = '../assembled_files/diagnostics/mpas_analysis/maps' for filename in files: symlink('../../../../diagnostics_files/{}'.format(filename), '{}/{}'.format(output_dir, filename))
def main(): author = 'Milena Veneziani' # make a geometric features object that knows about the geometric data # cache up a couple of directories gf = GeometricFeatures(cacheLocation='../../geometric_data', remoteBranchOrTag='master') fc = FeatureCollection() # *********** First, fix Atlantic_Basin regions in such a way that ******** # ********** they do not overlap each other (so that, we can combine # ********* them together to form a Atlantic Basin region) # ********* New Baltic Sea (modified feature) ********* # Combine old Baltic Sea feature with other small features fcBalticSea = gf.read('ocean', 'region', ['Baltic Sea']) fcFinland = gf.read('ocean', 'region', ['Gulf of Finland']) fcBothnia = gf.read('ocean', 'region', ['Gulf of Bothnia']) fcRiga = gf.read('ocean', 'region', ['Gulf of Riga']) fcKattegat = gf.read('ocean', 'region', ['Kattegat']) fcSkaggerak = gf.read('ocean', 'region', ['Skaggerak']) fcBalticSea.merge(fcFinland) fcBalticSea.merge(fcBothnia) fcBalticSea.merge(fcRiga) fcBalticSea.merge(fcKattegat) fcBalticSea.merge(fcSkaggerak) fcBalticSea = fcBalticSea.combine('Baltic Sea') props = fcBalticSea.features[0]['properties'] props['tags'] = 'Baltic_Sea;Arctic;Atlantic_Basin' props['author'] = author fc = fcBalticSea # ********* New North Atlantic Ocean (modified feature) ********* # Fix North Atlantic so that it does not overlap with new Labdrador # Sea, Irminger Sea, North Sea, Greenland Sea, and Norwegian Sea fcNorthAtlantic = gf.read('ocean', 'region', ['North Atlantic Ocean']) fcLabSea = gf.read('ocean', 'region', ['Labrador Sea']) fcIrmSea = gf.read('ocean', 'region', ['Irminger Sea']) fcGS = gf.read('ocean', 'region', ['Greenland Sea']) fcNS = gf.read('ocean', 'region', ['Norwegian Sea']) fcNorthSea = gf.read('ocean', 'region', ['North Sea']) fc_todiscard = fcLabSea fc_todiscard.merge(fcIrmSea) fc_todiscard.merge(fcGS) fc_todiscard.merge(fcNS) fc_todiscard.merge(fcNorthSea) fc_todiscard = fc_todiscard.combine('Combined region to discard') fcNorthAtlantic.merge(fc_todiscard) fcNorthAtlantic = fcNorthAtlantic.combine('North Atlantic Ocean') fcNorthAtlantic = fcNorthAtlantic.difference(fc_todiscard) props = fcNorthAtlantic.features[0]['properties'] props['tags'] = 'North_Atlantic_Ocean;Atlantic_Basin' props['author'] = author fc.merge(fcNorthAtlantic) # *********** Second, complete definition of oceanography-relevant ********* # ********** Arctic regions, started in part I, and identified with # ********* tag='Arctic' # ********* New Canadian Archipelago (modified feature) ********* # Modify old CAA by 1) including the shelf in the Arctic Ocean, and # 2) including Nares Strait. Old CAA feature will be superseded by this. fcContour500 = get_longest_contour(contourValue=-500., author=author) fcContour1000 = get_longest_contour(contourValue=-1000., author=author) fcCAA1 = make_rectangle(lon0=-130., lon1=-90., lat0=67.0, lat1=86.0, name='West Canadian Archipelago', author=author, tags='Canadian_Archipelago;Arctic;Atlantic_Basin') fcCAA1 = fcCAA1.difference(fcContour500) fcCAA2 = make_rectangle(lon0=-90., lon1=-70., lat0=67.0, lat1=86.0, name='Mid Canadian Archipelago', author=author, tags='Canadian_Archipelago;Arctic;Atlantic_Basin') fcCAA2 = fcCAA2.difference(fcContour1000) fcCAA3 = make_rectangle(lon0=-70., lon1=-50.5, lat0=76.0, lat1=86.0, name='East Canadian Archipelago', author=author, tags='Canadian_Archipelago;Arctic;Atlantic_Basin') fcCAA3 = fcCAA3.difference(fcContour500) fcCAA = fcCAA1 fcCAA.merge(fcCAA2) fcCAA.merge(fcCAA3) fcCAA = fcCAA.combine('Canadian Archipelago') fcHudson = gf.read('ocean', 'region', ['Hudson Bay']) fcCAA = fcCAA.difference(fcHudson) fcBaffin = gf.read('ocean', 'region', ['Baffin Bay']) fcCAA = fcCAA.difference(fcBaffin) props = fcCAA.features[0]['properties'] props['tags'] = 'Canadian_Archipelago;Arctic;Atlantic_Basin' props['author'] = author fc.merge(fcCAA) # ********* Canada Basin (new feature) ********* # This is a slightly modified version of the Beaufort Gyre feature # defined in part I. Differences include 1) a region that expands to # the west to touch the northern boundary of the new CAA feature, and # 2) a region that includes the Canada Basin shelf (whereas, for the # Beuafort Gyre, we have separated the 'Gyre' from the 'Gyre Shelf'). fcContour300 = get_longest_contour(contourValue=-300., author=author) fcCB1 = make_rectangle(lon0=-170., lon1=-156.65, lat0=67.0, lat1=80.0, name='West Canada Basin', author=author, tags='Canada_Basin;Arctic;Arctic_Basin') fcCB = fcCB1.difference(fcContour300) fcCB = fcCB1.difference(fcCB) fcCB2 = make_rectangle(lon0=-156.65, lon1=-100.0, lat0=67.0, lat1=80.0, name='East Canada Basin', author=author, tags='Canada_Basin;Arctic;Arctic_Basin') fcCB2 = fcCB2.difference(fcCAA) fcCB.merge(fcCB2) fcCB = fcCB.combine('Canada Basin') props = fcCB.features[0]['properties'] props['tags'] = 'Canada_Basin;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcCB) # ********* Chukchi Sea (new feature) ********* # This supersedes the old Chukchi Sea feature fcChukchi = make_rectangle(lon0=-180., lon1=-156.65, lat0=65.0, lat1=80.0, name='Chukchi Sea', author=author, tags='Chukchi_Sea;Arctic;Arctic_Basin') fcChukchi = fcChukchi.difference(fcContour300) fcChukchi_NSIDC = gf.read('ocean', 'region', ['Chukchi Sea NSIDC']) fcChukchi_todiscard = fcChukchi.difference(fcChukchi_NSIDC) fcChukchi = fcChukchi.difference(fcChukchi_todiscard) props = fcChukchi.features[0]['properties'] props['tags'] = 'Chukchi_Sea;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcChukchi) # ********* East Siberian Sea (new feature) ********* # This supersedes the old East Siberian Sea feature fcESS = make_rectangle(lon0=142., lon1=180.0, lat0=68.5, lat1=80.0, name='East Siberian Sea', author=author, tags='East_Siberian_Sea;Arctic;Arctic_Basin') fcESS = fcESS.difference(fcContour300) props = fcESS.features[0]['properties'] props['tags'] = 'East_Siberian_Sea;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcESS) # ********* Laptev Sea (new feature) ********* # This supersedes the old Laptev Sea feature fcLap = make_rectangle(lon0=90., lon1=142.0, lat0=70.0, lat1=81.25, name='Laptev Sea', author=author, tags='Laptev_Sea;Arctic;Arctic_Basin') fcLap = fcLap.difference(fcContour300) fcKara = gf.read('ocean', 'region', ['Kara Sea']) fcLap = fcLap.difference(fcKara) props = fcLap.features[0]['properties'] props['tags'] = 'Laptev_Sea;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcLap) # ********* Central Arctic (new feature) ********* # Define Central Arctic region as Arctic Ocean minus Canadian # Archipelago, Canada Basin, Chukchi Sea, ESS, and Laptev Sea fcArctic = gf.read('ocean', 'region', ['Arctic Ocean']) fcCentralArctic = fcArctic.difference(fcCAA) fcCentralArctic = fcCentralArctic.difference(fcCB) fcCentralArctic = fcCentralArctic.difference(fcChukchi) fcCentralArctic = fcCentralArctic.difference(fcESS) fcCentralArctic = fcCentralArctic.difference(fcLap) props = fcCentralArctic.features[0]['properties'] props['name'] = 'Central Arctic' props['tags'] = 'Central_Arctic;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcCentralArctic) # *********** Third, complete definition of seaice-relevant *********** # ***** Arctic regions, started in part I, according to NSIDC # ***** (regions map: https://nsidc.org/data/masie/browse_regions) # **** and identified with tag='Arctic_NSIDC' # ********* New Chukchi Sea NSIDC (modified feature) ********* # This supersedes the Chukchi Sea NSIDC feature defined in part I fcChukchi_NSIDC = FeatureCollection() fcChukchi_NSIDC.add_feature({ "type": "Feature", "properties": { "name": 'Chukchi Sea NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Chukchi_Sea_NSIDC;Arctic_NSIDC' }, "geometry": { "type": "Polygon", "coordinates": [[[-156.65, 65.37], [-180.0, 66.0], [-180.0, 80.0], [-156.48, 80.0], [-156.65, 65.37]]] } }) fc.merge(fcChukchi_NSIDC) # ********* Beaufort Sea NSIDC (new feature) ********* fcBS_NSIDC = FeatureCollection() fcBS_NSIDC.add_feature({ "type": "Feature", "properties": { "name": 'Beaufort Sea NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Beaufort_Sea_NSIDC;Arctic_NSIDC' }, "geometry": { "type": "Polygon", "coordinates": [[[-156.65, 65.37], [-156.48, 80.0], [-112.34, 77.69], [-124.58, 75.67], [-124.0, 65.0], [-156.65, 65.37]]] } }) fc.merge(fcBS_NSIDC) # ********* Canadian Archipelago NSIDC (new feature) ********* fcCAA_NSIDC = FeatureCollection() fcCAA_NSIDC.add_feature({ "type": "Feature", "properties": { "name": 'Canadian Archipelago NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Canadian_Archipelago_NSIDC;Arctic_NSIDC' }, "geometry": { "type": "Polygon", "coordinates": [[[-103.41, 60.69], [-124.0, 65.0], [-124.58, 75.67], [-112.34, 77.69], [-69.33, 82.67], [-81.21, 71.79], [-83.94, 70.43], [-84.45, 67.27], [-93.04, 65.70], [-103.41, 60.69]]] } }) fc.merge(fcCAA_NSIDC) # ********* Hudson Bay NSIDC (new feature) ********* fcHudson_NSIDC = FeatureCollection() fcHudson_NSIDC.add_feature({ "type": "Feature", "properties": { "name": 'Hudson Bay NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Hudson_Bay_NSIDC;Arctic_NSIDC' }, "geometry": { "type": "Polygon", "coordinates": [[[-81.24, 49.19], [-103.41, 60.69], [-93.04, 65.70], [-84.45, 67.27], [-83.94, 70.43], [-81.21, 71.79], [-70.70, 66.95], [-70.12, 65.99], [-63.70, 57.35], [-81.24, 49.19]]] } }) fc.merge(fcHudson_NSIDC) # ********* Baffin Bay NSIDC (new feature) ********* fcBaffin_NSIDC = FeatureCollection() fcBaffin_NSIDC.add_feature({ "type": "Feature", "properties": { "name": 'Baffin Bay NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Baffin_Bay_NSIDC;Arctic_NSIDC' }, "geometry": { "type": "Polygon", "coordinates": [[[-53.20, 42.0], [-68.07, 38.38], [-76.82, 48.01], [-60.85, 54.33], [-63.70, 57.35], [-70.12, 65.99], [-70.70, 66.95], [-81.21, 71.79], [-69.33, 82.67], [-45.0, 60.0], [-45.0, 42.0], [-53.20, 42.0]]] } }) fc.merge(fcBaffin_NSIDC) # ********* Central Arctic NSIDC (new feature) ********* fcCentralArctic_NSIDC = FeatureCollection() fcCentralArctic_NSIDC.add_feature({ "type": "Feature", "properties": { "name": 'Central Arctic NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Central_Arctic_NSIDC;Arctic_NSIDC' }, "geometry": { "type": "Polygon", "coordinates": [[[180.0, 80.0], [180.0, 90.0], [-69.33, 90.0], [-180.0, 90.0], [-180.0, 80.0], [-156.48, 80.0], [-112.34, 77.69], [-69.33, 82.67], [-51.66, 74.25], [-12.72, 81.41], [18.99, 79.18], [58.68, 81.08], [94.95, 81.08], [145.0, 80.0], [180.0, 80.0]]] } }) fc.merge(fcCentralArctic_NSIDC) # "split" these features into individual files in the geometric data cache gf.split(fc) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') # Fix features if necessary fcArcticTags = gf.read(componentName='ocean', objectType='region', tags=['Arctic']) for feature in fcArcticTags.features: featureName = feature['properties']['name'] shape = shapely.geometry.shape(feature['geometry']) print('{} is_valid: {}'.format(featureName, shape.is_valid)) if not shape.is_valid: fixed = shape.buffer(0) print(' Fixed? {}'.format(fixed.is_valid)) feature['geometry'] = shapely.geometry.mapping(fixed) fcArcticTags.plot(projection='northpole') fcArcticTags.to_geojson('arctic_ocean_regions.geojson') fcArcticNSIDCTags = gf.read(componentName='ocean', objectType='region', tags=['Arctic_NSIDC']) for feature in fcArcticNSIDCTags.features: featureName = feature['properties']['name'] shape = shapely.geometry.shape(feature['geometry']) print('{} is_valid: {}'.format(featureName, shape.is_valid)) if not shape.is_valid: fixed = shape.buffer(0) print(' Fixed? {}'.format(fixed.is_valid)) feature['geometry'] = shapely.geometry.mapping(fixed) fcArcticNSIDCTags.plot(projection='northpole') fcArcticNSIDCTags.to_geojson('arcticNSIDC_ocean_regions.geojson') fcArctic = fcArcticTags fcArctic.merge(fcArcticNSIDCTags) # "split" these features into individual files in the geometric data cache gf.split(fcArctic) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') plt.show()
"--geom_data_path", type="string", dest="path", default="geometric_data", help="Path to the geometric_data from the geometric_features" " repository.") parser.add_option("--preserve_floodplain", action="store_true", dest="preserve_floodplain", default=False) options, args = parser.parse_args() # required for compatibility with MPAS netcdfFormat = 'NETCDF3_64BIT' gf = GeometricFeatures(cacheLocation='{}'.format(options.path), remoteBranchOrTag='convert_to_package') # 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
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 main(): # create a GeometricFeatures object that knows which geometric data we want gf = GeometricFeatures() fcOceanBasins = build_ocean_basins(gf) fcOceanBasins.to_geojson('oceanBasins20200621.geojson')
def main(): author = 'Milena Veneziani' # make a geometric features object that knows about the geometric data # cache up a couple of directories gf = GeometricFeatures(cacheLocation='../../geometric_data') fc = FeatureCollection() # ********* New Hudson Bay (modified feature) ********* # Extract Foxe Basin from Northwestern Passages, and merge it # to old Hudson Bay feature. Also combine Hudson Strait with # Hudson Bay. Note that the created feature needs to be further # edited by hand to eliminate a seem, due to Foxe Basin not # completely aligning with one side of the old Hudson Bay feature # (and this feature is not fixed by the last step in this script # either). fcCAA = gf.read('ocean', 'region', ['Northwestern Passages']) fcbox1 = make_rectangle(lon0=-84.3, lon1=-71.7, lat0=67.1, lat1=70.75, name='Foxe Basin Box 1', author=author, tags='Hudson_Bay;Arctic;Atlantic_Basin') fcbox2 = make_rectangle(lon0=-86., lon1=-71.7, lat0=63.5, lat1=67.1, name='Foxe Basin Box 2', author=author, tags='Hudson_Bay;Arctic;Atlantic_Basin') fcFoxe_tmp = fcbox1.difference(fcCAA) fcFoxe_tmp = fcbox1.difference(fcFoxe_tmp) fcFoxe = fcbox2.difference(fcCAA) fcFoxe = fcbox2.difference(fcFoxe) fcFoxe.merge(fcFoxe_tmp) fcFoxe = fcFoxe.combine('Foxe Basin') fcHudson = gf.read('ocean', 'region', ['Hudson Bay']) fcHudson.merge(gf.read('ocean', 'region', ['Hudson Strait'])) fcHudson.merge(fcFoxe) fcHudson = fcHudson.combine('Hudson Bay') props = fcHudson.features[0]['properties'] props['tags'] = 'Hudson Bay;Arctic;Atlantic_Basin' props['author'] = author fc = fcHudson # ********* New Canadian Archipelago (modified feature) ********* # Remove Foxe Basin from Northwestern Passages and make new # Canadian Archipelago feature fcCAA = fcCAA.difference(fcFoxe) props = fcCAA.features[0]['properties'] props['name'] = 'Canadian Archipelago' props['tags'] = 'Canadian_Archipelago;Arctic;Atlantic_Basin' props['author'] = author fc.merge(fcCAA) # ********* New Barents Sea (modified feature) ********* # NOTE: this is dependent on existence of *old* features; # in particular, the Barentsz_Sea feature will # be removed after this script is applied # Combine Barentsz_Sea and White_Sea into new Barents Sea feature fcBS = gf.read('ocean', 'region', ['Barentsz Sea']) fcBS.merge(gf.read('ocean', 'region', ['White Sea'])) fcBS = fcBS.combine('Barents Sea') props = fcBS.features[0]['properties'] props['tags'] = 'Barents_Sea;Arctic;Arctic_NSIDC;Arctic_Basin' props['author'] = author fc.merge(fcBS) # ********* Kara Sea (unchanged feature) ********* fcKara = gf.read('ocean', 'region', ['Kara Sea']) props = fcKara.features[0]['properties'] props['tags'] = 'Kara_Sea;Arctic;Arctic_NSIDC;Arctic_Basin' fc.merge(fcKara) # ********* New Arctic Ocean (modified feature) ********* # NOTE: this is dependent on existence of *old* features; # in particular, the Arctic_Ocean, Chukchi_Sea, # East_Siberian_Sea, and Laptev_Sea features will # be superseded after this script is applied # Define triangle between Greenland Sea and Arctic_Ocean # (north of Fram Strait) that is not part of any of the # currently defined Arctic features fc_tmp = gf.read('ocean', 'region', ['Arctic Ocean']) fc_tmp.merge(gf.read('ocean', 'region', ['Lincoln Sea'])) fc_tmp.merge(fcBS) fcArctic = make_rectangle(lon0=-36., lon1=20., lat0=86., lat1=79., name='North of Fram Strait', author=author, tags='Arctic_Basin') fcArctic = fcArctic.difference(fc_tmp) # Define full Arctic *but* Barents and Kara Seas fcArctic.merge(gf.read('ocean', 'region', ['Arctic Ocean'])) fcArctic.merge(gf.read('ocean', 'region', ['Laptev Sea'])) fcArctic.merge(gf.read('ocean', 'region', ['East Siberian Sea'])) fcArctic.merge(gf.read('ocean', 'region', ['Chukchi Sea'])) fcArctic.merge(gf.read('ocean', 'region', ['Beaufort Sea'])) fcArctic.merge(gf.read('ocean', 'region', ['Lincoln Sea'])) fcArctic = fcArctic.combine('Arctic Ocean') props = fcArctic.features[0]['properties'] props['tags'] = 'Arctic_Ocean;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcArctic) # ********* Beaufort Gyre (entirely new feature) ********* fcContour300 = get_longest_contour(contourValue=-300., author=author) fcBG_firstTry = make_rectangle(lon0=-170., lon1=-130., lat0=70.5, lat1=80.5, name='Beaufort Gyre', author=author, tags='Beaufort_Gyre;Arctic_Proshutinsky') fcBG = fcBG_firstTry.difference(fcContour300) fcBG = fcBG_firstTry.difference(fcBG) fc.merge(fcBG) # ********* New NSIDC Chukchi Sea (new feature) ********* # Define Chukchi Sea as MASIE region #2 minus intersection with # Beaufort Gyre, and with Bering Strait transect as southern boundary fcChukchi = FeatureCollection() fcChukchi.add_feature( {"type": "Feature", "properties": {"name": 'Chukchi Sea NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Chukchi_Sea_NSIDC;Arctic_NSIDC'}, "geometry": { "type": "Polygon", "coordinates": [[[-167.15, 65.74], [-168.01, 65.84], [-168.62, 65.91], [-169.43, 66.01], [-170.24, 66.1], [-180., 66.6], [-180., 80.0], [-156.48, 80.0], [-156.65, 65.37], [-167.15, 65.74]]]}}) fcChukchi = fcChukchi.difference(fcBG) fc.merge(fcChukchi) # ********* Beaufort Gyre shelf (entirely new feature) ********* # Define Beaufort Gyre shelf region, minus intersection with Chukchi Sea fcBGshelf_firstTry = make_rectangle(lon0=-170., lon1=-130., lat0=68.0, lat1=80.5, name='Beaufort Gyre Shelf Box', author=author, tags='Beaufort_Gyre_Shelf;Arctic_Proshutinsky') fcBGshelf = fcBGshelf_firstTry.difference(fcContour300) fcBGshelf_secondTry = fcBGshelf_firstTry.difference(fcBG) fcBGshelf_secondTry = fcBGshelf_secondTry.difference(fcBGshelf) fcBGshelf.merge(fcBGshelf_secondTry) fcBGshelf = fcBGshelf.combine('Beaufort Gyre Shelf') fcBGshelf = fcBGshelf.difference(fcChukchi) props = fcBGshelf.features[0]['properties'] props['name'] = 'Beaufort Gyre Shelf' props['author'] = author props['tags'] = 'Beaufort_Gyre_Shelf;Arctic_Proshutinsky' fc.merge(fcBGshelf) # ********* New NSIDC East Siberian Sea (new feature) ********* # Define East Siberian Sea as MASIE region #3 fcESS = FeatureCollection() fcESS = make_rectangle(lon0=180., lon1=145., lat0=67., lat1=80., name='East Siberian Sea NSIDC', author=author, tags='East_Siberian_Sea_NSIDC;Arctic_NSIDC') fc.merge(fcESS) # ********* New NSIDC Laptev Sea (new feature) ********* # Define Laptev Sea as MASIE region #4, minus intersection with # Kara Sea fcLap = FeatureCollection() fcLap.add_feature( {"type": "Feature", "properties": {"name": 'Laptev Sea NSIDC', "author": author, "object": 'region', "component": 'ocean', "tags": 'Laptev_Sea_NSIDC;Arctic_NSIDC'}, "geometry": { "type": "Polygon", "coordinates": [[[145., 68.], [145., 80.], [95.4, 81.29], [99.89, 78.27], [102., 72.], [145., 68.]]]}}) fcLap = fcLap.difference(fcKara) fc.merge(fcLap) # ********* Central Arctic (entirely new feature) ********* # Define Central Arctic region as New Arctic Ocean minus BG, BGshelf, # New Chukchi, New ESS, and New Laptev fcCentralArctic = fcArctic.difference(fcBG) fcCentralArctic = fcCentralArctic.difference(fcBGshelf) fcCentralArctic = fcCentralArctic.difference(fcChukchi) fcCentralArctic = fcCentralArctic.difference(fcESS) fcCentralArctic = fcCentralArctic.difference(fcLap) props = fcCentralArctic.features[0]['properties'] props['name'] = 'Central Arctic' props['tags'] = 'Central_Arctic;Arctic;Arctic_Basin' props['author'] = author fc.merge(fcCentralArctic) # "split" these features into individual files in the geometric data cache gf.split(fc) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') # Fix features if necessary fcArcticTags = gf.read(componentName='ocean', objectType='region', tags=['Arctic']) for feature in fcArcticTags.features: featureName = feature['properties']['name'] shape = shapely.geometry.shape(feature['geometry']) print('{} is_valid: {}'.format(featureName, shape.is_valid)) if not shape.is_valid: fixed = shape.buffer(0) print(' Fixed? {}'.format(fixed.is_valid)) feature['geometry'] = shapely.geometry.mapping(fixed) fcArcticNSIDCTags = gf.read(componentName='ocean', objectType='region', tags=['Arctic_NSIDC']) for feature in fcArcticNSIDCTags.features: featureName = feature['properties']['name'] shape = shapely.geometry.shape(feature['geometry']) print('{} is_valid: {}'.format(featureName, shape.is_valid)) if not shape.is_valid: fixed = shape.buffer(0) print(' Fixed? {}'.format(fixed.is_valid)) feature['geometry'] = shapely.geometry.mapping(fixed) fcArctic = fcArcticTags fcArctic.merge(fcArcticNSIDCTags) fcArctic.to_geojson('arctic_ocean_regions.geojson') fcArctic.plot(projection='northpole') # "split" these features into individual files in the geometric data cache gf.split(fcArctic) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') plt.show()
def merge_features(): ''' Entry point for merging features from the geometric_data cache ''' parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument("-f", "--feature_file", dest="feature_file", help="Single feature file to append to " "output_file_name", metavar="FILE") parser.add_argument("-c", "--component", dest="component", help="The component (ocean, landice, etc.) from which " "to retieve the geometric features", metavar="COMP") parser.add_argument("-b", "--object_type", dest="object_type", help="The type of geometry to load, a point (0D), " "transect (1D) or region (2D)", metavar="TYPE") parser.add_argument("-n", "--feature_names", dest="feature_names", help="Semicolon separated list of features", metavar='"FE1;FE2;FE3"') parser.add_argument("-t", "--tags", dest="tags", help="Semicolon separated list of tags to match " "features against.", metavar='"TAG1;TAG2;TAG3"') parser.add_argument("-o", "--output", dest="output_file_name", help="Output file, e.g., features.geojson.", metavar="PATH", default="features.geojson") parser.add_argument("--cache", dest="cache_location", help="Location of local geometric_data cache.", metavar="PATH") parser.add_argument('-v', '--version', action='version', version='geometric_features {}'.format( geometric_features.__version__), help="Show version number and exit") args = parser.parse_args() fc = FeatureCollection() if os.path.exists(args.output_file_name): fc = read_feature_collection(args.output_file_name) if args.feature_file: fc.merge(read_feature_collection(args.feature_file)) if args.component and args.object_type: gf = GeometricFeatures(args.cache_location) if args.feature_names: featureNames = args.feature_names.split(';') else: featureNames = None if args.tags: tags = args.tags.split(';') else: tags = None fc.merge(gf.read(args.component, args.object_type, featureNames, tags)) fc.to_geojson(args.output_file_name)
def _cull_mesh_with_logging(logger, with_cavities, with_critical_passages, custom_critical_passages, custom_land_blockages, preserve_floodplain, use_progress_bar, process_count): """ Cull the mesh once the logger is defined for sure """ critical_passages = with_critical_passages or \ (custom_critical_passages is not None) land_blockages = with_critical_passages or \ (custom_land_blockages is not None) gf = GeometricFeatures() # 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='bedmachine', objectType='region', featureNames=['AntarcticGroundedIceCoverage']) else: fcAntarcticLand = gf.read( componentName='bedmachine', objectType='region', featureNames=['AntarcticIceCoverage']) fcLandCoverage.merge(fcAntarcticLand) # save the feature collection to a geojson file fcLandCoverage.to_geojson('land_coverage.geojson') # these defaults may have been updated from config options -- pass them # along to the subprocess netcdf_format = mpas_tools.io.default_format netcdf_engine = mpas_tools.io.default_engine # Create the land mask based on the land coverage, i.e. coastline data args = ['compute_mpas_region_masks', '-m', 'base_mesh.nc', '-g', 'land_coverage.geojson', '-o', 'land_mask.nc', '-t', 'cell', '--process_count', '{}'.format(process_count), '--format', netcdf_format, '--engine', netcdf_engine] check_call(args, logger=logger) dsBaseMesh = xarray.open_dataset('base_mesh.nc') dsLandMask = xarray.open_dataset('land_mask.nc') dsLandMask = add_land_locked_cells_to_mask(dsLandMask, dsBaseMesh, latitude_threshold=43.0, nSweeps=20) # 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']) if land_blockages: if with_critical_passages: # merge transects for critical land blockages into # critical_land_blockages.geojson fcCritBlockages = gf.read( componentName='ocean', objectType='transect', tags=['Critical_Land_Blockage']) else: fcCritBlockages = FeatureCollection() if custom_land_blockages is not None: fcCritBlockages.merge(read_feature_collection( custom_land_blockages)) # create masks from the transects fcCritBlockages.to_geojson('critical_blockages.geojson') args = ['compute_mpas_transect_masks', '-m', 'base_mesh.nc', '-g', 'critical_blockages.geojson', '-o', 'critical_blockages.nc', '-t', 'cell', '-s', '10e3', '--process_count', '{}'.format(process_count), '--format', netcdf_format, '--engine', netcdf_engine] check_call(args, logger=logger) dsCritBlockMask = xarray.open_dataset('critical_blockages.nc') dsLandMask = add_critical_land_blockages(dsLandMask, dsCritBlockMask) fcCritPassages = FeatureCollection() dsPreserve = [] if critical_passages: if with_critical_passages: # merge transects for critical passages into fcCritPassages fcCritPassages.merge(gf.read(componentName='ocean', objectType='transect', tags=['Critical_Passage'])) if custom_critical_passages is not None: fcCritPassages.merge(read_feature_collection( custom_critical_passages)) # create masks from the transects fcCritPassages.to_geojson('critical_passages.geojson') args = ['compute_mpas_transect_masks', '-m', 'base_mesh.nc', '-g', 'critical_passages.geojson', '-o', 'critical_passages.nc', '-t', 'cell', 'edge', '-s', '10e3', '--process_count', '{}'.format(process_count), '--format', netcdf_format, '--engine', netcdf_engine] check_call(args, logger=logger) dsCritPassMask = xarray.open_dataset('critical_passages.nc') # Alter critical passages to be at least two cells wide, to avoid sea # ice blockage dsCritPassMask = widen_transect_edge_masks(dsCritPassMask, dsBaseMesh, latitude_threshold=43.0) dsPreserve.append(dsCritPassMask) if preserve_floodplain: dsPreserve.append(dsBaseMesh) # cull the mesh based on the land mask dsCulledMesh = cull(dsBaseMesh, dsMask=dsLandMask, dsPreserve=dsPreserve, logger=logger) # create a mask for the flood fill seed points dsSeedMask = compute_mpas_flood_fill_mask(dsMesh=dsCulledMesh, fcSeed=fcSeed, logger=logger) # cull the mesh a second time using a flood fill from the seed points dsCulledMesh = cull(dsCulledMesh, dsInverse=dsSeedMask, graphInfoFileName='culled_graph.info', logger=logger) write_netcdf(dsCulledMesh, 'culled_mesh.nc') if critical_passages: # make a new version of the critical passages mask on the culled mesh fcCritPassages.to_geojson('critical_passages.geojson') args = ['compute_mpas_transect_masks', '-m', 'culled_mesh.nc', '-g', 'critical_passages.geojson', '-o', 'critical_passages_mask_final.nc', '-t', 'cell', '-s', '10e3', '--process_count', '{}'.format(process_count), '--format', netcdf_format, '--engine', netcdf_engine] check_call(args, logger=logger) if with_cavities: fcAntarcticIce = gf.read( componentName='bedmachine', objectType='region', featureNames=['AntarcticIceCoverage']) fcAntarcticIce.to_geojson('ice_coverage.geojson') args = ['compute_mpas_region_masks', '-m', 'culled_mesh.nc', '-g', 'ice_coverage.geojson', '-o', 'ice_coverage.nc', '-t', 'cell', '--process_count', '{}'.format(process_count), '--format', netcdf_format, '--engine', netcdf_engine] check_call(args, logger=logger) dsMask = xarray.open_dataset('ice_coverage.nc') landIceMask = dsMask.regionCellMasks.isel(nRegions=0) dsLandIceMask = xarray.Dataset() dsLandIceMask['landIceMask'] = landIceMask write_netcdf(dsLandIceMask, 'land_ice_mask.nc') dsLandIceCulledMesh = cull(dsCulledMesh, dsMask=dsMask, logger=logger) write_netcdf(dsLandIceCulledMesh, 'no_ISC_culled_mesh.nc') extract_vtk(ignore_time=True, dimension_list=['maxEdges='], variable_list=['allOnCells'], filename_pattern='culled_mesh.nc', out_dir='culled_mesh_vtk', use_progress_bar=use_progress_bar) if with_cavities: extract_vtk(ignore_time=True, dimension_list=['maxEdges='], variable_list=['allOnCells'], filename_pattern='no_ISC_culled_mesh.nc', out_dir='no_ISC_culled_mesh_vtk', use_progress_bar=use_progress_bar)
def main(): author = 'Xylar Asay-Davis, Alice Barthel, Nicolas Jourdain' tags = 'Antarctic;ISMIP6' # make a geometric features object that knows about the geometric data # cache up a couple of directories gf = GeometricFeatures('../../geometric_data') bedmap2_bin_to_netcdf('bedmap2.nc') fcContour1500 = get_longest_contour(contourValue=-1500., author=author) fc = FeatureCollection() lons = [-65., -25., -25., -65.] lats = [-80., -80., -77., -71.] fc.merge( shelf_polygon(lons, lats, name='ISMIP6 Weddell Sea', author=author, tags=tags, fcContour=fcContour1500)) lons = [-128., -128., -90., -90.] lats = [-76., -69., -69., -76.] fc.merge( shelf_polygon(lons, lats, name='ISMIP6 Amundsen Sea', author=author, tags=tags, fcContour=fcContour1500)) lons = [45., 45., 90., 90.] lats = [-70., -60., -60., -70.] fc.merge( shelf_polygon(lons, lats, name='ISMIP6 Amery Sector', author=author, tags=tags, fcContour=fcContour1500)) lons = [-22.5, -22.5, 22.5, 22.5] lats = [-75., -65., -65., -75.] fc.merge( shelf_polygon(lons, lats, name='ISMIP6 Dronning Maud Land', author=author, tags=tags, fcContour=fcContour1500)) lons = [110., 110., 130., 130.] lats = [-70., -60., -60., -70.] fc.merge( shelf_polygon(lons, lats, name='ISMIP6 Totten Region', author=author, tags=tags, fcContour=fcContour1500)) lons = [165., 165., 180., 180.] lats = [-80., -71., -73., -80.] fc_ross = shelf_polygon(lons, lats, name='ISMIP6 Western Ross Sea', author=author, tags=tags, fcContour=fcContour1500) lons = [-180., -180., -150., -150.] lats = [-80., -73., -77., -80.] fc_ross.merge( shelf_polygon(lons, lats, name='ISMIP6 Eastern Ross Sea', author=author, tags=tags, fcContour=fcContour1500)) old_props = fc_ross.features[0]['properties'] fc_ross = fc_ross.combine('ISMIP6 Ross Sea') props = fc_ross.features[0]['properties'] for prop in ['tags', 'zmin', 'zmax']: props[prop] = old_props[prop] fc.merge(fc_ross) fc.plot(projection='southpole') fc.to_geojson('ismip6_antarctic_ocean_regions.geojson') # "split" these features into individual files in the geometric data cache gf.split(fc) # update the database of feature names and tags write_feature_names_and_tags(gf.cacheLocation) # move the resulting file into place shutil.copyfile('features_and_tags.json', '../../geometric_features/features_and_tags.json') plt.show()