Exemple #1
0
        fcCritPassages.merge(
            gf.read(componentName='ocean',
                    objectType='transect',
                    tags=['Critical_Passage']))

    if options.custom_critical_passages is not None:
        fcCritPassages.merge(
            read_feature_collection(options.custom_critical_passages))

    # create masks from the transects
    dsCritPassMask = conversion.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=43.0)

    dsPreserve.append(dsCritPassMask)

if options.preserve_floodplain:
    dsPreserve.append(dsBaseMesh)

# cull the mesh based on the land mask
dsCulledMesh = conversion.cull(dsBaseMesh,
                               dsMask=dsLandMask,
                               dsPreserve=dsPreserve)

# create a mask for the flood fill seed points
dsSeedMask = conversion.mask(dsCulledMesh, fcSeed=fcSeed)
Exemple #2
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
                        metavar="MASKFILE",
                        required=True)
    parser.add_argument("-m",
                        "--mesh_file",
                        dest="mesh_filename",
                        help="MPAS Mesh filename.",
                        metavar="MESHFILE",
                        required=True)
    parser.add_argument("-o",
                        "--out_file",
                        dest="out_filename",
                        help="Output mask file,different from input filename.",
                        metavar="MASKFILE",
                        required=True)
    parser.add_argument("-l",
                        "--latitude_threshold",
                        dest="latitude_threshold",
                        help="Minimum latitude, degrees, for transect "
                        "widening.",
                        required=False,
                        type=float,
                        default=43.0)
    args = parser.parse_args()

    dsMask = xarray.open_dataset(args.mask_filename)

    dsMesh = xarray.open_dataset(args.mesh_filename)

    dsMask = widen_transect_edge_masks(dsMask, dsMesh, args.latitude_threshold)
    dsMask.to_netcdf(args.out_filename)
Exemple #4
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)