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 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')
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)
Exemple #5
0
options, args = parser.parse_args()

# required for compatibility with MPAS
netcdfFormat = 'NETCDF3_64BIT'

critical_passages = options.with_critical_passages or \
    (options.custom_critical_passages is not None)

land_blockages = options.with_critical_passages or \
    (options.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 options.with_cavities:
    fcAntarcticLand = gf.read(componentName='bedmachine',
                              objectType='region',
# 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')

# create a FeatureCollection containing all iceshelf regions wtih one of the
# 27 IMBIE basin tags tags
fc = FeatureCollection()
for basin in range(1, 28):
    print('Adding feature from IMBIE basin {:d}'.format(basin))
    basinName = 'Antarctica_IMBIE{:d}'.format(basin)
    tags = [basinName]
    # load the iceshelf regions for one IMBIE basin
    fcBasin = gf.read(componentName='iceshelves',
                      objectType='region',
                      tags=tags)

    # combine all regions in the basin into a single feature
    fcBasin = fcBasin.combine(featureName=basinName)

    # merge the feature for the basin into the collection of all basins
    fc.merge(fcBasin)

# save the feature collection to a geojson file
fc.to_geojson('Extended_Antarctic_Basins.geojson')

if plot:
    fc.plot(projection='southpole')
    plt.show()
Exemple #7
0
from geometric_features import GeometricFeatures

import matplotlib.pyplot as plt

plot = True
withCavities = False

# 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')

# 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 withCavities:
    fcAntarcticLand = gf.read(componentName='bedmap2',
                              objectType='region',
#!/usr/bin/env python
"""
This script creates a geojson file with Antarctic regions similar to
Timmermann et al. 2013
"""
from geometric_features import GeometricFeatures

regions = [
    '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'
]

# 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='region', featureNames=regions)

# save the feature collection to a geojson file
fc.to_geojson('antarcticRegions20200621.geojson')
Exemple #9
0
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
Exemple #10
0
from __future__ import absolute_import, division, print_function, \
    unicode_literals

from geometric_features import GeometricFeatures

import matplotlib.pyplot as plt

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')

# create a FeatureCollection containing all land-ice regions wtih one of three
# IMBIE tags
tags = [
    'WestAntarcticaIMBIE', 'AntarcticPeninsulaIMBIE', 'EastAntarcticaIMBIE'
]
fc = gf.read(componentName='landice',
             objectType='region',
             tags=tags,
             allTags=False)

# save the feature collection to a geojson file
fc.to_geojson('Antarctic_Basins.geojson')

if plot:
    fc.plot(projection='southpole')
    plt.show()
Exemple #11
0
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()
Exemple #12
0
# missing data
gf = GeometricFeatures()

# create a FeatureCollection containing all ice shelves and combined ice-shelf
# regions
fc = FeatureCollection()

# build analysis regions from combining ice shelves from regions with the
# appropriate tags
for shelfName in combinedIceShelves:
    subNames = combinedIceShelves[shelfName]
    print(shelfName)

    print(' * merging features')
    fcShelf = gf.read(componentName='iceshelves',
                      objectType='region',
                      tags=subNames,
                      allTags=False)

    print(' * combining features')
    fcShelf = fcShelf.combine(featureName=shelfName)

    # merge the feature for the basin into the collection of all basins
    fc.merge(fcShelf)

# build ice shelves from regions with the appropriate tags
for shelfName in iceShelfNames:
    print(shelfName)

    print(' * merging features')
    fcShelf = gf.read(componentName='iceshelves',
                      objectType='region',
Exemple #13
0
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 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()
#!/usr/bin/env python
"""
This script combines transects defining cricial passages.
"""

# stuff to make scipts work for python 2 and python 3
from __future__ import absolute_import, division, print_function, \
    unicode_literals

from geometric_features import GeometricFeatures

# 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')

# create a FeatureCollection containing all ocean transects wtih the
# "Critical_Passage" tag
fc = gf.read(componentName='ocean', objectType='transect',
             tags=['Critical_Passage'])

# save the feature collection to a geojson file
fc.to_geojson('criticalPassages.geojson')
Exemple #16
0
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)