:py:mod:`gnome.maps` ==================== .. py:module:: gnome.maps .. autoapi-nested-parse:: maps for GNOME. imports to have it all in one namespace Submodules ---------- .. toctree:: :titlesonly: :maxdepth: 1 map/index.rst tideflat_map/index.rst Package Contents ---------------- Classes ~~~~~~~ .. autoapisummary:: gnome.maps.MapFromBNA gnome.maps.GnomeMap gnome.maps.RasterMap gnome.maps.ParamMap .. py:class:: MapFromBNA(filename, raster_size=4096 * 4096, map_bounds=None, spillable_area=None, shift_lons=0, **kwargs) Bases: :py:obj:`RasterMap` A raster land-water map, created from file with polygons in it. Currently only support BNA, but could be shapefile, or ??? Creates a RasterMap from a data file. It is expected that you will get the spillable area and map bounds from the data file -- if they exist Required arguments: :param filename: full path to the data file :param raster_size: the total number of pixels (bytes) to make the raster -- the actual size will match the aspect ratio of the bounding box of the land :type raster_size: integer :param shiftLons: shift longitudes to be in -180 to 180 coords or 0 to 360. 180, or 360 are valid inputs :type shiftLons: integer Optional arguments (kwargs): :param refloat_halflife: the half-life (in hours) for the re-floating. :param map_bounds: The polygon bounding the map -- could be larger or smaller than the land raster :param spillable_area: The polygon bounding the spillable_area :param id: unique ID of the object. Using UUID as a string. This is only used when loading object from save file. :type id: string .. py:property:: raster_size Maximum physical size of the raster in bytes .. py:attribute:: _schema .. py:method:: build_raster(land_polys=None, BB=None) Build the underlying raster used for the map This should be called if the resolution or land polygons change .. py:method:: to_geojson() Output the vector version of the shoreline polygons. This is what gets drawn in the WebGNOME client, for example This version directly writes the polygons already stored in the map object -- keeping the door open to that data coming from something other than a bna file. FIXME: Technically, geojson recommends ccw polygons -- but putting that check in was pretty slow, so it's commented out. FIXME: This really should export the map_bounds and spillable_area as well. .. py:class:: GnomeMap(map_bounds=None, spillable_area=None, land_polys=None, **kwargs) Bases: :py:obj:`gnome.gnomeobject.GnomeId` The very simplest map for GNOME -- all water with only a bounding box for the map bounds. This also serves as a description of the interface and base class for more complex maps The __init__ will be different for other implementations :param map_bounds: The polygon bounding the map if any elements are outside the map bounds, they are removed from the simulation. :param spillable_area: The PolygonSet bounding the spillable_area. :type spillable_area: Either a PolygonSet object or a list of lists from which a polygon set can be created. Each element in the list is a list of points defining a polygon. :param land_polys: The PolygonSet holding the land polygons :type land_polys: Either a PolygonSet object or a list of lists from which a polygon set can be created. Each element in the list is a list of points defining a polygon. Note on 'map_bounds': ``[(lon, lat), (lon, lat), (lon, lat), ..`` An NX2 array of points that describe a polygon if no map bounds is provided -- the whole world is valid .. py:property:: map_bounds Bounds of the map -- an NX2 array of float describing a polygon. [(lon, lat), (lon, lat), ...] .. py:property:: spillable_area List of polygons defining the region in which it is legal to set spills .. py:property:: land_polys Sequence of polygons surrounding land -- mostly used for rendering. .. py:attribute:: _schema .. py:attribute:: refloat_halflife .. py:attribute:: _ref_as :value: 'map' .. py:method:: __add__(other) .. py:method:: get_polygons() .. py:method:: _attr_from_list_to_array(l_) dict returned as list of tuples to be converted to numpy array Again used to update_from_dict map_bounds and spillable_area .. py:method:: get_map_bounding_box() return a bounding box of the map needed because map_bounds can be a polygon bounding box is a 2x2 tuple: ((left, bottom), (right, top)) .. py:method:: on_map(coords) Determine whether points are on the map or not :param coords: location for test. :type coords: NX3 numpy array of floats: (long, lat, depth) or something that can be turned into one. :return: bool array: True if the location is on the map, False otherwise Note: coords are 3-d, but the concept of "on the map" is 2-d in this context, so depth is ignored. .. py:method:: on_land(coord) :param coord: location for test. :type coord: 3-tuple of floats: (long, lat, depth) :return: - Always returns False-- no land in this implementation .. py:method:: in_water(coords) Determines if the points are in water (rather than on land) :param coords: location for test. :type coords: 3-tuple of floats: (long, lat, depth) or an Nx3 array :returns: - True if the point is in the water, - False if the point is on land (or off map?) This implementation has no land, so always True in on the map. .. py:method:: allowable_spill_position(coord) :param coord: location for test. :type coord: 3-tuple of floats: (long, lat, depth) :return: - True if the point is an allowable spill position - False if the point is not an allowable spill position .. note:: it could be either off the map, or in a location that spills aren't allowed .. py:method:: _set_off_map_status(sc) Determines which elements moved off the map Called by beach_elements after checking for land-hits :param sc: current SpillContainer :type sc: :class:`gnome.spill_container.SpillContainer` .. py:method:: beach_elements(sc, model_time=None) Determines which LEs were or weren't beached or moved off_map. status_code is changed to oil_status.off_maps if off the map. Called by the model in the main time loop, after all movers have acted. :param sc: current SpillContainer :type sc: :class:`gnome.spill_container.SpillContainer` This map class has no land, so only the map check and resurface_airborn elements is done: noting else changes. subclasses that override this probably want to make sure that: self.resurface_airborne_elements(sc) self._set_off_map_status(sc) are called. .. py:method:: refloat_elements(spill_container, time_step, model_time=None) This method performs the re-float logic -- changing the element status flag, and moving the element to the last known water position :param spill_container: current SpillContainer :type spill_container: :class:`gnome.spill_container.SpillContainer` .. note:: This map class has no land, and so is a no-op. .. py:method:: resurface_airborne_elements(spill_container) Takes any elements that are left above the water surface (z < 0.0) and puts them on the surface (z == 0.0) :param spill_container: current SpillContainer :type spill_container: :class:`gnome.spill_container.SpillContainer` .. note:: While this shouldn't occur according to the physics we're modeling, some movers may push elements up too high, or multiple movers may add vertical movement that adds up to over the surface. e.g rise velocity. .. py:method:: to_geojson() .. py:class:: RasterMap(raster=None, projection=None, refloat_halflife=1, **kwargs) Bases: :py:obj:`GnomeMap` A land water map implemented as a raster This one uses a numpy array of uint8, so there are 8 bits to choose from... It requires a constant refloat half-life in hours This will usually be initialized in a sub-class (from a BNA, etc) NOTE: Nothing new added to _state attribute for serialization create a new RasterMap :param raster: A numpy array that stores the land-water map 0 is water. 1 is land. In theory, other values could be used for other purposes. If the array is not C-contiguous, it will be copied to a C-contiguus array. :type raster: a (W,H) numpy array of type uint8 :param projection: A Projection object -- used to convert from lat-long to pixels in the array :type projection: :class:`gnome.map_canvas.Projection` Optional arguments (kwargs) :param refloat_halflife: The halflife for refloating off land -- assumed to be the same for all land. 0.0 means all refloat every time step < 0.0 means never re-float. :type refloat_halflife: float. Units are hours :param map_bounds: The polygon bounding the map -- could be larger or smaller than the land raster :type map_bounds: (N,2) numpy array of floats :param spillable_area: The polygon bounding the spillable_area :type spillable_area: (N,2) numpy array of floats :param id: unique ID of the object. Using UUID as a string. This is only used when loading object from save file. :type id: string .. py:property:: ratios .. py:property:: raster .. py:property:: refloat_halflife .. py:property:: approximate_raster_interval .. py:attribute:: seconds_in_hour .. py:attribute:: land_flag :value: 1 .. py:method:: build_coarser_rasters() Builds the list which contains the different resolution raster maps. Scale -> raster example for base map of 1024 x 1024: 0 -> 1/16th raster 64 base cells per cell 1 -> 1/32nd raster 32:1 2 -> 1/64th raster 16:1 3 -> 1/128th raster 8:1 4 -> 1/256th raster 4:1 5 -> 1/512th raster 2:1 6 -> 1/1024th raster (== base map 1:1) The general idea is that the particle position (an int) can quickly be mapped into any scale and the path can begin from there. For example, if your path begins offshore and ends in a narrow inlet, your scale might begin on the 32:1 map. But as soon as the path crosses into the (32:1) raster cell containing the inlet (which will register as a land cell on that raster), the scale will decrease to 4:1, when the cell is completely water. In the end, if the scale decreases to 1:1 and there's still a land hit, then land was hit. .. py:method:: save_as_image(filename) Save the land-water raster as a PNG save_as_image :param filename: the name of the file to save to. .. py:method:: _off_raster(coord) are these pixel coordinates on the raster We can't just use an IndexError, as negative indexes can be legal with numpy, but aren't expected here. .. py:method:: _on_land_pixel(coord) returns 1 if the point is on land, 0 otherwise :param coord: pixel coordinates of point of interest :type coord: tuple: (row, col) .. note:: Only used internally or for testing -- no need for external API to use pixel coordinates. .. py:method:: on_land(coord) :param coord: (long, lat, depth) location -- depth is ignored here. :type coord: 3-tuple of floats -- (long, lat, depth) :return: - 1 if point on land - 0 if not on land .. note:: to_pixel() converts to array of points... .. py:method:: _in_water_pixel(coord) .. py:method:: in_water(coord) checks if it's on the map, first. (depth is ignored in this version) :param coord: (lon, lat, depth) coordinate :return: true if the point given by coord is in the water .. py:method:: beach_elements(sc, model_time=None) Determines which elements were or weren't beached. Any that are beached have the beached flag set, and a "last known water position" (lkwp) is computed This version uses a modified Bresenham algorithm to find out which pixels the LE may have crossed. :param sc: the current spill container :type sc: :class:`gnome.spill_container.SpillContainer` It must have the following data arrays: ('prev_position', 'positions', 'last_water_pt', 'status_code') .. py:method:: refloat_elements(spill_container, time_step, model_time=None) This method performs the re-float logic -- changing the element status flag, and moving the element to the last known water position :param spill_container: the current spill container :type spill_container: :class:`gnome.spill_container.SpillContainer` .. py:method:: _check_land_layers(raster_map_layers, ratios, positions, end_positions, status_codes, last_water_positions) Do the actual land-checking. This method simply calls a Cython version: gnome.cy_gnome.cy_land_check.check_land() The arguments 'status_codes', 'positions' and 'last_water_positions' are altered in place. .. py:method:: allowable_spill_position(coord) Returns true if the spill position is in the allowable spill area .. note:: This may not be the same as in_water! :param coord: (lon, lat, depth) coordinate .. py:method:: to_pixel_array(coords) Projects an array of (lon, lat) tuples onto the raster, and modifies it in place to hold the corresponding projected values. :param coords: a numpy array of (lon, lat, depth) points :return: a numpy array of (x, y) pixel values .. py:class:: ParamMap(center=(0.0, 0.0), distance=30000, bearing=90, units=None, **kwargs) Bases: :py:obj:`GnomeMap` The very simplest map for GNOME -- all water with only a bounding box for the map bounds. This also serves as a description of the interface and base class for more complex maps Creates a parameratized map, essentially a straight shoreline set a certain distance and bearing from a location, usually a spill. It is up to the user to put the spill and the map center in the same location. Required arguments: :param center: tuple of coordinates describing the center point of the map :param distance: The distance in meters the closest point on the shoreline is from the center :param bearing: The bearing the closest point on the shoreline is from the center. .. py:property:: distance .. py:attribute:: _schema .. py:attribute:: _valid_dist_units .. py:method:: build(center, distance, bearing, units) .. py:method:: _check_units(units) Checks the user provided units are in list of valid volume or mass units .. py:method:: get_map_bounds() .. py:method:: get_land_polygon() .. py:method:: on_map(coord) :param coord: location for test. :type coord: 3-tuple of floats: (long, lat, depth) :return: bool array: True if the location is on the map, False otherwise Note: coord is 3-d, but the concept of "on the map" is 2-d in this context, so depth is ignored. .. py:method:: on_land(coord) :param coord: location for test. :type coord: 3-tuple of floats: (long, lat, depth) or Nx3 numpy array :return: - Always returns False-- no land in this implementation .. py:method:: in_water(coord) :param coord: location for test. :type coord: 3-tuple of floats: (long, lat, depth) :returns: - True if the point is in the water, - False if the point is on land (or off map?) This implementation has no land, so always True in on the map. .. py:method:: allowable_spill_position(coord) :param coord: location for test. :type coord: 3-tuple of floats: (long, lat, depth) :return: - True if the point is an allowable spill position - False if the point is not an allowable spill position .. note:: it could be either off the map, or in a location that spills aren't allowed .. py:method:: find_last_water_pos(starts, ends) .. py:method:: beach_elements(sc, model_time=None) Determines which LEs were or weren't beached or moved off_map. status_code is changed to oil_status.off_maps if off the map. Called by the model in the main time loop, after all movers have acted. :param sc: current SpillContainer :type sc: :class:`gnome.spill_container.SpillContainer` This map class does not use a raster map for collision detection. Since the land is so simple the collisions are detected via intersection. .. py:method:: refloat_elements(spill_container, time_step, model_time=None) This method performs the re-float logic -- changing the element status flag, and moving the element to the last known water position :param spill_container: the current spill container :type spill_container: :class:`gnome.spill_container.SpillContainer` .. py:method:: update_from_dict(data) .. py:method:: to_geojson()