def write_regridded_data_to_shapefile(dstfield):
    """
    :param dstfield: The ESMF field object containing a mesh to write to shapefile.
    :type dstfield: :class:`ESMF.api.field.Field`
    :returns: Path to the output shapefile.
    :rtype: str
    """
    # turn the shapefile into an OCGIS field and get the spatial information
    ofield = ocgis.RequestDataset(PATH_SHP).get()
    # get the time dimension from the original netCDF file
    otime = ocgis.RequestDataset(PATH_PR).get().temporal
    # create an OCGIS variable from the regridded data values
    pr = ocgis.Variable(name='pr', value=np.array(dstfield.reshape(1, otime.shape[0], 1, 1, ofield.shape[-1])))
    # this holds our variables
    vc = ocgis.VariableCollection([pr])
    # we want to maintain the original shapefile data, but it needs to reshaped to account for the new time dimension.
    for var in ofield.variables.itervalues():
        newvalue = np.zeros(pr.shape, dtype=var.dtype)
        newvalue[:] = var.value
        newvar = ocgis.Variable(name=var.name, value=newvalue)
        vc[newvar.name] = newvar
    # combine the spatial data with time and the regridded values
    ofield2 = ocgis.Field(temporal=otime, spatial=ofield.spatial, variables=vc)
    # write this to shapefile
    path_out_shp = ocgis.OcgOperations(dataset=ofield2, output_format='shp', prefix='pr_catchments',
                                       add_auxiliary_files=False).execute()

    return path_out_shp
Exemplo n.º 2
0
    def test_system_spatial_averaging_weights(self):
        """Test creating averaging weights from first principles."""

        # x/y coordinate arrays and grid objects. Coordinates may be two-dimensional otherwise,
        x = ocgis.Variable(name='xc',
                           dimensions='dimx',
                           value=np.arange(5, 360, 10, dtype=float))
        y = ocgis.Variable(name='yc',
                           dimensions='dimy',
                           value=np.arange(-85, 90, 10, dtype=float))
        grid = ocgis.Grid(x, y, crs=ocgis.crs.Spherical())
        # Create spatial bounds on the grid coordinates. This allows us to use polygons as opposed to points for the
        # spatial averaging.
        grid.set_extrapolated_bounds('xc_bounds', 'yc_bounds', 'bounds')
        self.assertEqual(grid.abstraction, ocgis.constants.Topology.POLYGON)

        # This is the subset geometry. OCGIS geometry variables may be used to take advantage of wrapping and coordinate
        # system conversion.
        subset_geom = shapely.geometry.box(52, -70, 83, 10)

        # Perform an intersection. First, data is reduced in spatial extent using an intersects operation. A
        # clip/intersection is then performed for each geometry object.
        sub, slc = grid.get_intersection(subset_geom, return_slice=True)
        slc = {dim.name: se
               for dim, se in zip(grid.dimensions, slc)
               }  # Just how to convert to a dictionary slice...
        # Weights are computed on demand and is equal to original_area/clipped_area.
        weights = sub.weights
        self.assertAlmostEqual(weights.sum(), 24.799999999999997)
Exemplo n.º 3
0
def create_data():
    col = np.linspace(-104., -100., 100)
    row = np.linspace(32, 36, 100)

    col = VectorDimension(value=col, name='longitude', name_bounds='longitude_bounds', attrs={'standard_name': 'longitude',
                                                                                              'units': 'degrees_east'})
    col.set_extrapolated_bounds()
    row = VectorDimension(value=row, name='latitude', name_bounds='latitude_bounds', attrs={'standard_name': 'latitude',
                                                                                            'units': 'degrees_north'})
    row.set_extrapolated_bounds()
    grid = ocgis.SpatialGridDimension(row=row, col=col)
    sdim = ocgis.SpatialDimension(grid=grid)

    start = datetime.datetime(2000, 1, 1)
    stop = datetime.datetime(2000, 12, 31)
    days = 1
    ret = []
    delta = datetime.timedelta(days=days)
    check = start
    while check <= stop:
        ret.append(check)
        check += delta
    temporal = ocgis.TemporalDimension(value=ret, unlimited=True)

    var_value = np.ones((1, temporal.shape[0], 1, row.shape[0], col.shape[0]), dtype=float)
    variable = ocgis.Variable(value=var_value, name='pr')

    field = ocgis.Field(spatial=sdim, temporal=temporal, variables=variable)

    ds = nc.Dataset(PATH_FAKE_DATA, 'w', format='NETCDF3_CLASSIC')
    field.write_netcdf(ds)
    ds.close()
Exemplo n.º 4
0
def do_record_test(exedir, record):
    # The record's unique HRU identifier
    hruid = record['properties']['hruid']
    # The current output directory
    curr_outdir = OUTDIR_TEMPLATE.format(hruid)
    # Create the directory
    os.makedirs(curr_outdir, exist_ok=True)
    # Make that the current working directory
    os.chdir(curr_outdir)
    # We need to transform the coordinate system from WGS84 to Spherical for ESMF
    crs = ocgis.crs.CoordinateReferenceSystem(value=record['meta']['crs'])
    field = ocgis.Field.from_records([record], crs=crs)
    field.update_crs(ocgis.crs.Spherical())
    # Convert the field geometry to an unstructured grid format based on the UGRID spec.
    gc = field.geom.convert_to(pack=PACK,
                               node_threshold=NODE_THRESHOLD,
                               split_interiors=SPLIT_INTERIORS,
                               remove_self_intersects=False,
                               allow_splitting_excs=False)
    # Path to the output netCDF file for the current element
    out_element_nc = os.path.join(curr_outdir,
                                  "esmf-element_hruid-{}.nc".format(hruid))
    # Add the center coordinate to make ESMF happy (even though we are not using it)
    centerCoords = np.array(
        [field.geom.v()[0].centroid.x,
         field.geom.v()[0].centroid.y]).reshape(1, 2)
    ocgis.Variable(name='centerCoords',
                   value=centerCoords,
                   dimensions=['elementCount', 'coordDim'],
                   attrs={'units': 'degrees'},
                   parent=gc.parent)
    # When writing the data to file, convert to ESMF unstructured format.
    gc.parent.write(out_element_nc, driver='netcdf-esmf-unstruct')
    # Run the simple regridding test
    success = do_esmf(out_element_nc, exedir, curr_outdir)
    if success:
        # If successful, remove the directory
        assert 'hruid-tmp-' in curr_outdir
        shutil.rmtree(curr_outdir)
    else:
        # If it's not successful, leave the directory. Write the shapefile so it's easy to look at. Also send the record
        # string to a file.
        field.geom.write_vector('02-problem-hruid-{}.shp'.format(hruid))
        record_out = '01-problem-record-hruid-{}.out'.format(hruid)
        with open(record_out, 'w') as f:
            f.write(str(record))
    # Change back to the execution directory
    os.chdir(exedir)
    # Try to remove the log file if it exists.
    if os.path.exists('PET0.ESMF_LogFile'):
        os.remove('PET0.ESMF_LogFile')
Exemplo n.º 5
0
def run():
    import ocgis

    print('Hello from run(). I am rank: {}'.format(ocgis.vm.rank))

    dist = ocgis.vmachine.mpi.OcgDist()
    dim = dist.create_dimension('foo', 10, dist=True)
    dist.update_dimension_bounds()

    var = ocgis.Variable(name='a_var', dimensions=dim)
    var.get_value()[:] = ocgis.vm.rank

    var.parent.write('a_var_data.nc')

    if ocgis.vm.rank == 0:
        invar = ocgis.RequestDataset('a_var_data.nc').create_field()['a_var']
        print('Value on disk:', invar.get_value())
Exemplo n.º 6
0
import os

import ocgis
from ocgis.constants import DimensionMapKey

OUT_NC = os.path.join(os.getcwd(), 'ocgis_example_dimension_map.nc')

########################################################################################################################
# Write some initial data.

var_x = ocgis.Variable(name='nonstandard_x',
                       value=[10, 20, 30],
                       dimensions='nsx')
var_y = ocgis.Variable(name='nonstandard_y',
                       value=[40, 50, 60, 70],
                       dimensions='nsy')
var_t = ocgis.Variable(name='nonstandard_time',
                       value=[1, 2, 3],
                       units='days since 2000-1-1',
                       attrs={'calendar': 'standard'},
                       dimensions='nst')
data_dimensions = [
    var_t.dimensions[0], var_x.dimensions[0], var_y.dimensions[0]
]
var_data = ocgis.Variable(name='some_data', dimensions=data_dimensions)

vc = ocgis.VariableCollection(variables=[var_x, var_y, var_t, var_data])
vc.write(OUT_NC)

########################################################################################################################
# This metadata is not self-describing. Hence, no data or coordinate variables are interpretable. OpenClimateGIS will
Exemplo n.º 7
0
lat = field.get('XLAT_M').get_value()

ydim = field.dimensions["south_north"]
xdim = field.dimensions["west_east"]
# 
lon_notime = lon[0,:,:]
lat_notime = lat[0,:,:]

# import ipdb; ipdb.set_trace()

field.remove_variable('XLONG_M')
field.remove_variable('XLAT_M')

attrs = {"units":"degrees_east",
         "axis":"x"}
var = ocgis.Variable(name='lon', value=lon_notime, dimensions=[ydim, xdim], 
                     attrs=attrs)
field.add_variable(var)


attrs = {"units":"degrees_north",
         "axis":"y"}
var = ocgis.Variable(name='lat', value=lat_notime, dimensions=[ydim, xdim],
                     attrs=attrs)
field.add_variable(var)

# field["lon_center"].set_name("lon")
# field["lat_center"].set_name("lat")

# now create a grid and write bounds
## grid = field.grid
# field["lon"].set_bounds(field.get('bounds_lon').extract(), force=True)
Exemplo n.º 8
0
    def _preformatting_(self, i, coll):
        """
        Modify in place the collections so they can be saved as discrete
        geometries along a new spatial dimension.
        """
        # TODO: UGID and GID show up in the output file, but they are equal. Remove one.

        if not self.ops or self.ops.aggregate is False:
            return coll

        # Size of spatial dimension
        ncoll = len(self.ops.geom)

        udim = DimensionName.UNIONED_GEOMETRY

        ugids = coll.properties.keys()
        assert len(ugids) == 1
        ugid = list(ugids)[0]

        # Geometry centroid location
        lon, lat = coll.geoms[ugid].centroid.xy

        for field in coll.iter_fields():

            lon_attrs = field.x.attrs.copy()
            lat_attrs = field.y.attrs.copy()
            xn = field.x.name
            yn = field.y.name

            # Removed for now. It'd be nice to find an elegant way to retain those.
            field.remove_variable(xn)
            field.remove_variable(yn)

            # Create new lon and lat variables
            field.add_variable(
                ocgis.Variable(xn,
                               value=lon,
                               dimensions=(udim, ),
                               attrs=dict(
                                   lon_attrs,
                                   **{'long_name': 'Centroid longitude'})))

            field.add_variable(
                ocgis.Variable(yn,
                               value=lat,
                               dimensions=(udim, ),
                               attrs=dict(lat_attrs,
                                          **{'long_name':
                                             'Centroid latitude'})))

            if VariableName.SPATIAL_MASK in field:
                # Remove the spatial_mask.
                field.remove_variable(VariableName.SPATIAL_MASK)
                field.dimension_map.set_spatial_mask(None)

            grid = ocgis.Grid(field[xn],
                              field[yn],
                              abstraction='point',
                              crs=field.crs,
                              parent=field)
            field.set_grid(grid)

            # Geometry variables from the geom properties dict
            dm = get_data_model(self.ops)

            # Some dtypes are not supported by netCDF3. Use the netCDF4
            # data model to avoid these issues.
            for key, val in coll.properties[ugid].items():
                if np.issubdtype(type(val), int):
                    dt = get_dtype('int', dm)
                elif np.issubdtype(type(val), float):
                    dt = get_dtype('float', dm)
                else:
                    dt = 'auto'

                # There is no metadata for those yet, but it could be passed
                # using the output_format_options keyword.
                field.add_variable(
                    ocgis.Variable(key,
                                   value=[
                                       val,
                                   ],
                                   dtype=dt,
                                   dimensions=(udim, )), )

                # Propagate max string length if it is set.
                smg = coll.children[ugid][key].string_max_length_global
                if smg is not None:
                    field[key].set_string_max_length_global(value=smg)

            # ------------------ Dimension update ------------------------ #
            # Modify the dimensions for the number of geometries
            gdim = field.dimensions[udim]
            gdim.set_size(ncoll)

            for var in field.iter_variables_by_dimensions([gdim]):
                d = var.dimensions_dict[udim]
                d.bounds_local = (i, i + 1)
            # ------------------------------------------------------------ #

            # CF-Conventions
            # Options for cf-role are timeseries_id, profile_id, trajectory_id
            gid = field[HeaderName.ID_GEOMETRY]
            gid.attrs['cf_role'] = 'timeseries_id'

            # Name of spatial dimension
            if self.options.get('geom_dim', None):
                gdim.set_name(self.options.get('geom_dim', None))

            return coll
Exemplo n.º 9
0
nodeCoords[:, 0] = esmf_corners_x.flatten()
nodeCoords[:, 1] = esmf_corners_y.flatten()

# Get the center coordinates
centerCoords = np.zeros((elementCount, 2), dtype=np.float32)
centerCoords[:, 0] = grid.x.v().flatten()
centerCoords[:, 1] = grid.y.v().flatten()

# Number of nodes per element. Always four corners in this case
numElementConn = np.ones(elementCount, dtype=np.int32) * 4

# Write out the data
vc = ocgis.VariableCollection()
nodeCoordsV = ocgis.Variable(name='nodeCoords',
                             value=nodeCoords,
                             dimensions=['nodeCount', 'coordDim'],
                             attrs={'units': 'degrees'},
                             parent=vc)
elementConnV = ocgis.Variable(
    name='elementConn',
    value=elementConn,
    dimensions=['elementCount', 'maxNodePElement'],
    attrs={'long_name': 'Node indices that define the element connectivity'},
    parent=vc)
numElementConnV = ocgis.Variable(
    name='numElementConn',
    value=numElementConn,
    dimensions=['elementCount'],
    attrs={'long_name': 'Number of nodes per element'},
    parent=vc)
centerCoordsV = ocgis.Variable(name='centerCoords',
Exemplo n.º 10
0
    def write(self):
        ocgis_lh('starting write method', self._log, logging.DEBUG)

        # Indicates if user geometries should be written to file.
        write_ugeom = False

        ncoll = len(self.ops.geom)

        build = True
        for i, coll in enumerate(self):
            ugids = coll.properties.keys()
            assert len(ugids) == 1
            ugid = ugids[0]

            # Geometry centroid location
            lon, lat = coll.geoms[ugid].centroid.xy

            for field in coll.iter_fields():

                lon_attrs = field.x.attrs.copy()
                lat_attrs = field.y.attrs.copy()

                # Removed for now. It'd be nice to find an elegant way to retain those.
                field.remove_variable('lat')
                field.remove_variable('lon')

                # Create new lon and lat variables
                field.add_variable(
                    ocgis.Variable('lon',
                                   value=lon,
                                   dimensions=(DimensionName.UNIONED_GEOMETRY,),
                                   attrs=dict(lon_attrs, **{'long_name':'Centroid longitude'})
                                   )
                )


                field.add_variable(
                    ocgis.Variable('lat',
                                   value=lat,
                                   dimensions=(DimensionName.UNIONED_GEOMETRY,),
                                   attrs=dict(lat_attrs, **{'long_name':'Centroid latitude'})
                                   )
                )


                if 'ocgis_spatial_mask' in field:
                    # Remove the spatial_mask and replace by new one.
                    field.remove_variable('ocgis_spatial_mask')


                grid = ocgis.Grid(field['lon'], field['lat'], abstraction='point',
                  crs=field.crs, parent=field)
                grid.set_mask([[False,]])
                field.set_grid(grid)

                # Geometry variables from the geom properties dict
                # There is no metadata for those...
                dm = get_data_model(self.ops)

                for key, val in coll.properties[ugid].items():
                    if np.issubdtype(type(val), int):
                        dt = get_dtype('int', dm)
                    elif np.issubdtype(type(val), float):
                        dt = get_dtype('float', dm)
                    else:
                        dt='auto'
                    field.add_variable(
                        ocgis.Variable(key,
                                       value=[val,],
                                       dtype=dt,
                                       dimensions=(DimensionName.UNIONED_GEOMETRY,)))

                # ------------------ Dimension update ------------------------ #
                # Modify the dimensions for the number of geometries
                gdim = field.dimensions[DimensionName.UNIONED_GEOMETRY]
                gdim.set_size(ncoll)

                for var in field.iter_variables_by_dimensions([gdim]):
                    d = var.dimensions_dict[DimensionName.UNIONED_GEOMETRY]
                    d.bounds_local = (i, i+1)
                # ------------------------------------------------------------ #

                # CF-Conventions
                # Can this be anything else than a timeseries_id
                # Options are timeseries_id, profile_id, trajectory_id
                gid = field[HeaderName.ID_GEOMETRY]
                gid.attrs['cf_role'] = 'timeseries_id'

                # TODO: Hard-code the name in constants.py
                gdim.set_name('region')

            # Path to the output object.
            # I needed to put it here because _write_archetype pops it, so it's not available after the first loop.
            f = {KeywordArgument.PATH: self.path}

            # This will be changed to "write" if we are on the build loop.
            write_mode = MPIWriteMode.APPEND

            if build:
                # During a build loop, create the file and write the first series of records. Let the drivers determine
                # the appropriate write modes for handling parallelism.
                write_mode = None

                # Write the user geometries if selected and there is one present on the incoming collection.
                if self._add_ugeom and coll.has_container_geometries:
                    write_ugeom = True

                if write_ugeom:
                    if vm.rank == 0:
                        # The output file name for the user geometries.
                        ugid_shp_name = self.prefix + '_ugid.shp'
                        if self._add_ugeom_nest:
                            ugeom_fiona_path = os.path.join(self._get_or_create_shp_folder_(), ugid_shp_name)
                        else:
                            ugeom_fiona_path = os.path.join(self.outdir, ugid_shp_name)
                    else:
                        ugeom_fiona_path = None

                build = False

            f[KeywordArgument.WRITE_MODE] = write_mode
            self._write_coll_(f, coll)

            if write_ugeom:
                with vm.scoped(SubcommName.UGEOM_WRITE, [0]):
                    if not vm.is_null:
                        for subset_field in list(coll.children.values()):
                            subset_field.write(ugeom_fiona_path, write_mode=write_mode, driver=DriverVector)

        # The metadata and dataset descriptor files may only be written if OCGIS operations are present.
        ops = self.ops
        if ops is not None and self.add_auxiliary_files and MPI_RANK == 0:
            # Add OCGIS metadata output if requested.
            if self.add_meta:
                ocgis_lh('adding OCGIS metadata file', 'conv', logging.DEBUG)
                from ocgis.conv.meta import MetaOCGISConverter

                lines = MetaOCGISConverter(ops).write()
                out_path = os.path.join(self.outdir, self.prefix + '_' + MetaOCGISConverter._meta_filename)
                with open(out_path, 'w') as f:
                    f.write(lines)

            # Add the dataset descriptor file if requested.
            if self._add_did_file:
                ocgis_lh('writing dataset description (DID) file', 'conv', logging.DEBUG)
                path = os.path.join(self.outdir, self.prefix + '_did.csv')
                _write_dataset_identifier_file_(path, ops)

            # Add source metadata if requested.
            if self._add_source_meta:
                ocgis_lh('writing source metadata file', 'conv', logging.DEBUG)
                path = os.path.join(self.outdir, self.prefix + '_source_metadata.txt')
                _write_source_meta_(path, ops)

        # Return the internal path unless overloaded by subclasses.
        ret = self._get_return_()

        return ret
Exemplo n.º 11
0
# Should I be using ESMF corners?
# # Convert ocgis corners to esmf corners
# esmf_corners_x = get_esmf_corners_from_ocgis_corners(grid.x.bounds.v())
# esmf_corners_y = get_esmf_corners_from_ocgis_corners(grid.y.bounds.v())
# # Create one-based global index
# indexing = np.arange(1, esmf_corners_x.size + 1, dtype=np.int32).reshape(esmf_corners_x.shape)

# Write out the data
grid_size = grid.archetype.size
lat, lon = grid.x.shape
grid_corners = grid.x.bounds.shape[2]

vc = ocgis.VariableCollection()
grid_dims = ocgis.Variable(name='grid_dims',
                           value=grid.x.shape,
                           dimensions=['grid_rank'],
                           parent=vc)
latitude = ocgis.Variable(name='grid_center_lat',
                          value=grid.y.v().flatten(),
                          dimensions=['grid_size'],
                          attrs={'units': 'degrees'},
                          parent=vc)
longitude = ocgis.Variable(name='grid_center_lon',
                           value=grid.x.v().flatten(),
                           dimensions=['grid_size'],
                           attrs={'units': 'degrees'},
                           parent=vc)

gxbf = np.zeros([grid_size, grid_corners])
for i in range(lat):
    gxbf[i * lon:(i + 1) * lon, :] = grid.x.bounds.v()[i, :, :]