示例#1
0
文件: test_geom.py 项目: NCPP/ocgis
    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)
示例#2
0
文件: nc.py 项目: nmizukami/ocgis
    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
示例#3
0
文件: nc.py 项目: Ouranosinc/ocgis
    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