Exemple #1
0
    def get_values(self, rectangle):
        """Return an array covering the given rectangle.

        Increasing x/y array indexes correspond to increasing value in the projected space.
        Cell size is the one of the tile.
        """
        assert self.x_delta > 0
        ((x_min, x_max), (y_min, y_max)) = rectangle
        if self.y_delta > 0:
            # get indexes of sub-array
            xi_min, yi_min = self.projected_to_raster((x_min, y_min))
            xi_max, yi_max = self.projected_to_raster((x_max, y_max))
            # returns the subarray
            subarray = self.data[xi_min:xi_max + 1, yi_min:yi_max + 1]
            return GeoData(subarray,
                           *self.raster_to_projected((xi_min, yi_min)),
                           self.x_delta,
                           self.y_delta,
                           projection=self.geoprojection)
        else:  # our internal data structure is inversed on y-axis
            # get indexes of sub-array
            xi_min, yi_min = self.projected_to_raster((x_min, y_max))
            xi_max, yi_max = self.projected_to_raster((x_max, y_min))
            # returns the sub-array, inversed on the y-axis
            subarray = self.data[xi_min:xi_max + 1,
                                 yi_min:yi_max + 1][..., ::-1]
            return GeoData(subarray,
                           *self.raster_to_projected((xi_min, yi_max)),
                           self.x_delta,
                           -self.y_delta,
                           projection=self.geoprojection)
 def test_right_append(self):
     gd_right = GeoData(np.array([[31, 32], [41, 42]]), 2, 0, 1, 1)
     res = self.gd.append_right(gd_right)
     self.assertEqual(res.data[0, 0], 11)
     self.assertEqual(res.data[1, 1], 22)
     self.assertEqual(res.data[0, 1], 12)
     self.assertEqual(res.data[1, 0], 21)
     self.assertEqual(res.data[3, 0], 41)
     self.assertEqual(res.data.shape, (4, 2))
def fig_observation_contour(base_propagation: FirePropagation,
                            cells: ty.Mapping[ty.Tuple[int, int], float],
                            cmap="Greens_r",
                            binary=True,
                            gdd=None) -> display.GeoDataDisplay:
    gd = GeoData.full_like(base_propagation.prop_data, np.inf)
    for cell, time in cells.items():
        gd.data["ignition"][cell] = time if not binary else 1.0
    if not gdd:
        gdd = display.GeoDataDisplay.pyplot_figure(gd, frame=(0., 0.))
    gdd.draw_ignition_shade(cmap=cmap, geodata=gd)
    return gdd
 def test_geodata_conversion(self):
     from fire_rs.geodata.environment import World
     world = World()
     gd = world.get_elevation([[475060.0, 485060], [6200074.0, 6210074]])
     raster = gd.as_cpp_raster()
     print(raster)
     gd2 = GeoData.from_cpp_raster(raster, "elevation_cpp")
     print(gd2[10, 10][0])
     self.assertAlmostEqual(gd[10, 10][0], gd2[10, 10][0])
     self.assertAlmostEqual(gd.x_offset, gd2.x_offset)
     self.assertAlmostEqual(gd.y_offset, gd2.y_offset)
     self.assertEqual(gd.data.shape, gd2.data.shape)
     print(gd2)
Exemple #5
0
def make_utility_map(firemap: GeoData, flight_window: TimeWindow = TimeWindow(-np.inf, np.inf),
                     layer="ignition", output_layer="utility") -> GeoData:
    """Compute a utility map from a wildfire map"""
    gradient = rate_of_spread_map(firemap, layer=layer, output_layer="ros")
    grad_array = gradient["ros"]
    grad_array[grad_array >= np.inf] = np.NaN

    utility = 1 - (grad_array - np.nanmin(grad_array)) / (
            np.nanmax(grad_array) - np.nanmin(grad_array))
    utility[np.isnan(utility)] = 0.
    utility[(firemap[layer] < flight_window.start) | (firemap[layer] > flight_window.end)] = 0.

    return firemap.clone(data_array=utility, dtype=[(output_layer, 'float64')])
class WorldTest(unittest.TestCase):
    def setUp(self):
        self.gd = GeoData(np.array([[11, 12], [21, 22]]), 0, 0, 1, 1)

    def test_access(self):
        self.assertEqual(self.gd.data[0, 0], 11)
        self.assertEqual(self.gd.data[1, 1], 22)
        self.assertEqual(self.gd.data[0, 1], 12)
        self.assertEqual(self.gd.data[1, 0], 21)

    def test_right_append(self):
        gd_right = GeoData(np.array([[31, 32], [41, 42]]), 2, 0, 1, 1)
        res = self.gd.append_right(gd_right)
        self.assertEqual(res.data[0, 0], 11)
        self.assertEqual(res.data[1, 1], 22)
        self.assertEqual(res.data[0, 1], 12)
        self.assertEqual(res.data[1, 0], 21)
        self.assertEqual(res.data[3, 0], 41)
        self.assertEqual(res.data.shape, (4, 2))

    def test_bottom_append(self):
        gd_right = GeoData(np.array([[31, 32], [41, 42]]), 0, 2, 1, 1)
        res = self.gd.append_bottom(gd_right)
        self.assertEqual(res.data.shape, (2, 4))

    def test_split(self):
        res = self.gd.split(2, 2)
        assert all([(1, 1) == t.data.shape for t in res])

        # recreate initial array from the split ones
        combined = res[0].append_right(res[1]).append_bottom(
            res[2].append_right(res[3]))
        np.testing.assert_allclose(self.gd.data, combined.data)

    def test_subset(self):
        res = self.gd.subset(Area(1, 1, 0, 1))
        self.assertEqual(res.data.shape, (1, 2))
Exemple #7
0
def plot_plan_with_background(plan: Plan, geodatadisplay: gdd, time_range,
                              output_options_plot):
    """Plot a plan trajectories with background geographic information in a geodata display."""
    # Draw background layers
    for layer in output_options_plot['background']:
        if layer == 'elevation_shade':
            geodatadisplay.draw_elevation_shade(
                with_colorbar=output_options_plot.get('colorbar', True),
                layer='elevation')
        if layer == 'elevation_planning_shade':
            geodatadisplay.draw_elevation_shade(
                with_colorbar=output_options_plot.get('colorbar', True),
                layer='elevation_planning')
        elif layer == 'ignition_shade':
            geodatadisplay.draw_ignition_shade(
                with_colorbar=output_options_plot.get('colorbar', True))
        elif layer == 'observedcells':
            raise NotImplementedError()
            # geodatadisplay.TrajectoryDisplayExtension.draw_observation_map(
            #     planner.expected_observed_map(layer_name="expected_observed"),
            #     layer='expected_observed', color='green', alpha=0.9)
            # geodatadisplay.TrajectoryDisplayExtension.draw_observation_map(
            #     planner.expected_ignited_map(layer_name="expected_ignited"),
            #     layer='expected_ignited', color='red', alpha=0.9)
        elif layer == 'ignition_contour':
            try:
                geodatadisplay.draw_ignition_contour(with_labels=True)
            except ValueError as e:
                logger.exception("ValueError while drawing ignition contour")
        elif layer == 'wind_quiver':
            geodatadisplay.draw_wind_quiver()
        elif layer == 'utilitymap':
            geodatadisplay.TrajectoryDisplayExtension.draw_utility_shade(
                geodata=GeoData.from_cpp_raster(
                    plan.utility_map(),
                    'utility',
                    projection=geodatadisplay.geodata.projection),
                layer='utility',
                vmin=0.,
                vmax=1.)

    plot_plan_trajectories(plan,
                           geodatadisplay,
                           layers=output_options_plot["foreground"],
                           time_range=time_range)
Exemple #8
0
def geodata_from_raster_msg(msg: Raster, layer: str, invert=False):
    """Deserialize a Raster msg into a GeoData object.

    if layer is "elevation", the raster is inverted
    """
    array = np.fromiter(zip(msg.data), dtype=[(layer, 'float64')])
    array.resize((msg.metadata.x_width, msg.metadata.y_height))
    # FIXME (Workaround) invert elevation rasters as they are shown inverted in the GUI
    if layer == "elevation":
        array = array[..., ::-1]
    if invert:
        array = array[..., ::-1]
    return GeoData(array,
                   msg.metadata.x_offset,
                   msg.metadata.y_offset,
                   msg.metadata.cell_width,
                   msg.metadata.cell_width,
                   projection=msg.metadata.epsg)
def plot_sr_with_background(sr: 'planning.up.SearchResult', geodatadisplay, time_range,
                            output_options_plot,
                            plan: 'Union[str, int]' = 'final'):
    """Plot a plan trajectories with background geographic information in a geodata display."""
    # Draw background layers
    for layer in output_options_plot['background']:
        if layer == 'elevation_shade':
            geodatadisplay.draw_elevation_shade(
                with_colorbar=output_options_plot.get('colorbar', True), layer='elevation')
        if layer == 'elevation_planning_shade':
            geodatadisplay.draw_elevation_shade(
                with_colorbar=output_options_plot.get('colorbar', True), layer='elevation_planning')
        elif layer == 'ignition_shade':
            geodatadisplay.draw_ignition_shade(
                with_colorbar=output_options_plot.get('colorbar', True))
        # elif layer == 'observedcells':
        #     geodatadisplay.TrajectoryDisplayExtension.draw_observation_map(
        #         planner.expected_observed_map(layer_name="expected_observed"),
        #         layer='expected_observed', color='green', alpha=0.9)
        #     geodatadisplay.TrajectoryDisplayExtension.draw_observation_map(
        #         planner.expected_ignited_map(layer_name="expected_ignited"),
        #         layer='expected_ignited', color='red', alpha=0.9)
        elif layer == 'ignition_contour':
            try:
                geodatadisplay.draw_ignition_contour(with_labels=True)
            except ValueError as e:
                logger.exception("ValueError while drawing ignition contour")
        elif layer == 'wind_quiver':
            geodatadisplay.draw_wind_quiver()
        elif layer == 'utilitymap':
            geodatadisplay.TrajectoryDisplayExtension.draw_utility_shade(
                geodata=GeoData.from_cpp_raster(sr.final_plan().utility_map(), 'utility'),
                layer='utility', vmin=0., vmax=1.)

    plot_plan_trajectories(sr.plan(plan), geodatadisplay,
                           layers=output_options_plot["foreground"], time_range=time_range)
 def observed(self) -> GeoData:
     return GeoData.from_cpp_raster(self._gfmapper.observed,
                                    self.observed_fire_layer)
 def pr(cpp_raster, blocking=False):  # plots a cpp raster
     return GeoData.from_cpp_raster(cpp_raster,
                                    "xx").plot(blocking=blocking)
    # output_format="pdf"

    area = ((481000.0, 484000.0), (6211000.0, 6213500.0))

    expected_env = propagation.Environment(area, wind_speed=5., wind_dir=0.)
    now = datetime.datetime.now().timestamp()
    ignition_point = TimedPoint(area[0][0] + 1000.0, area[1][0] + 1000.0, now)
    expected_fire = propagation.propagate_from_points(
        expected_env, ignition_point, now + datetime.timedelta(hours=2).total_seconds())

    env = propagation.Environment(area, wind_speed=6., wind_dir=0.)
    fire = propagation.propagate_from_points(
        env, ignition_point, now + datetime.timedelta(hours=2).total_seconds())

    # Create fire perimeter geodata
    fire_perimeter = GeoData.full_like(fire.prop_data.slice("ignition"), np.nan)
    # Create contour with scikit-image
    contours = skimage.measure.find_contours(fire.prop_data.data["ignition"],
                                             now + datetime.timedelta(hours=1).total_seconds())
    # Draw contour in the geodata
    for contour in contours:
        for pt_i in range(len(contour)):
            if pt_i < len(contour) / 3:
                continue
            rr, cc = skimage.draw.line(*np.asarray(contour[pt_i - 1], dtype=int),
                                       *np.asarray(contour[pt_i], dtype=int))
            fire_perimeter.data[rr, cc] = fire.prop_data.data["ignition"][rr, cc]

    contours = skimage.measure.find_contours(fire.prop_data.data["ignition"],
                                             now + datetime.timedelta(minutes=30).total_seconds())
    # Draw contour in the geodata
Exemple #13
0
 def observed(self) -> 'GeoData':
     return GeoData.from_cpp_raster(self._gfmapper.observed,
                                    self.output_fire_layer)
 def test_bottom_append(self):
     gd_right = GeoData(np.array([[31, 32], [41, 42]]), 0, 2, 1, 1)
     res = self.gd.append_bottom(gd_right)
     self.assertEqual(res.data.shape, (2, 4))
Exemple #15
0
def make_fire_data(fire_map: GeoData, elevation_map: GeoData, fire_map_layer: str = 'ignition',
                   elevation_map_layer: str = 'elevation'):
    return FireData(fire_map.as_cpp_raster(fire_map_layer),
                    elevation_map.as_cpp_raster(elevation_map_layer))
Exemple #16
0
 def utility_map(self, layer_name='utility') -> 'GeoData':
     return GeoData.from_cpp_raster(
         self._searchresult.final_plan().utility_map(), layer_name)
 def setUp(self):
     self.gd = GeoData(np.array([[11, 12], [21, 22]]), 0, 0, 1, 1)
Exemple #18
0
def run_benchmark(scenario: Scenario, save_directory: str, instance_name: str,
                  output_options_plot: ty.Mapping[str, ty.Any],
                  output_options_planning: ty.Mapping[str,
                                                      ty.Any], snapshots: bool,
                  vns_name: str, output_options_data: ty.Mapping[str, ty.Any]):
    _logger.info("Starting benchmark instance %s", instance_name)

    # Fetch scenario environment data with additional elevation mode for planning
    env = PlanningEnvironment(
        scenario.area,
        wind_speed=scenario.wind_speed,
        wind_dir=scenario.wind_direction,
        planning_elevation_mode=output_options_planning['elevation_mode'],
        discrete_elevation_interval=DISCRETE_ELEVATION_INTERVAL,
        world=fire_rs.geodata.environment.World(
            landcover_to_fuel_remap=fire_rs.geodata.environment.
            EVERYTHING_FUELMODEL_REMAP))

    # Propagate fires in the environment
    propagation_end_time = scenario.time_window_end + 60 * 10
    _logger.debug("Propagating fire ignitions %s until %s",
                  str(scenario.ignitions), str(propagation_end_time))
    prop = propagation.propagate_from_points(env,
                                             scenario.ignitions,
                                             until=propagation_end_time)
    ignitions = prop.ignitions()

    # Transform altitude of UAV bases from agl (above ground level) to absolute
    for f in scenario.flights:
        base_h = 0.  # If flat, start at the default segment insertion h
        if output_options_planning['elevation_mode'] != 'flat':
            base_h = base_h + env.raster["elevation"][env.raster.array_index(
                (f.base_waypoint.x, f.base_waypoint.y))]
        # The new WP is (old_x, old_y, old_z + elevation[old_x, old_y], old_dir)
        f.base_waypoint = Waypoint(f.base_waypoint.x, f.base_waypoint.y,
                                   base_h, f.base_waypoint.dir)

    conf = {
        'min_time': scenario.time_window_start,
        'max_time': scenario.time_window_end,
        'save_every': 0,
        'save_improvements': snapshots,
        'vns': vns_configurations[vns_name]
    }
    conf['vns']['configuration_name'] = vns_name

    # Define the flight window
    flight_window = TimeWindow(scenario.time_window_start,
                               scenario.time_window_end)

    # Create utility map
    utility = make_utility_map(ignitions,
                               flight_window,
                               layer='ignition',
                               output_layer='utility')
    utility_cpp = utility.as_cpp_raster('utility')

    # Make a FireData object
    fire_data = make_fire_data(ignitions,
                               env.raster,
                               elevation_map_layer='elevation_planning')

    # Create an initial plan
    initial_plan = Plan(instance_name, [f.as_cpp() for f in scenario.flights],
                        fire_data, flight_window, utility_cpp)

    # Set up a Planner object from the initial Plan
    pl = Planner(initial_plan, vns_configurations[vns_name])
    pl.save_improvements = snapshots
    pl.save_every = 0

    search_result = pl.compute_plan()
    final_plan = search_result.final_plan()

    # Propagation was running more time than desired in order to reduce edge effect.
    # Now we need to filter out-of-range ignition times. Crop range is rounded up to the next
    # 10-minute mark (minus 1). This makes color bar ranges and fire front contour plots nicer
    ignitions['ignition'][ignitions['ignition'] > \
                          int(scenario.time_window_end / 60. + 5) * 60. - 60] = _DBL_MAX
    # Representation of unburned cells using max double is not suitable for display,
    # so those values must be converted to NaN
    ignitions_nan = ignitions['ignition'].copy()
    ignitions_nan[ignitions_nan == _DBL_MAX] = np.nan
    first_ignition = np.nanmin(ignitions_nan)
    last_ignition = np.nanmax(ignitions_nan)

    # Create the geodatadisplay object & extensions that are going to be used
    geodatadisplay = GeoDataDisplay.pyplot_figure(
        env.raster.combine(ignitions), frame=(0, 0))
    geodatadisplay.add_extension(TrajectoryDisplayExtension, (None, ), {})

    plot_plan_with_background(final_plan, geodatadisplay,
                              (first_ignition, last_ignition),
                              output_options_plot)

    # Save the picture
    filepath = os.path.join(
        save_directory,
        instance_name + "." + str(output_options_plot.get('format', 'png')))
    _logger.info("Saving as figure as: %s", str(filepath))
    geodatadisplay.axes.get_figure().set_size_inches(
        *output_options_plot.get('size', (15, 10)))
    geodatadisplay.axes.get_figure().savefig(filepath,
                                             dpi=output_options_plot.get(
                                                 'dpi', 150),
                                             bbox_inches='tight')

    # Save rasters
    if output_options_data['save_rasters']:
        raster_data_dir = os.path.join(save_directory, instance_name + "_data")
        if not os.path.exists(raster_data_dir):
            os.makedirs(raster_data_dir)
        env.raster.write_to_file(
            os.path.join(
                raster_data_dir, ".".join(("_".join(
                    (instance_name, "elevation_planning")), 'tif'))),
            'elevation_planning')
        env.raster.write_to_file(
            os.path.join(
                raster_data_dir, ".".join(("_".join(
                    (instance_name, "wind_velocity")), 'tif'))),
            'wind_velocity')
        env.raster.write_to_file(
            os.path.join(
                raster_data_dir, ".".join(("_".join(
                    (instance_name, "wind_angle")), 'tif'))), 'wind_angle')
        prop.ignitions().write_to_file(os.path.join(
            raster_data_dir, ".".join(("_".join(
                (instance_name, "ignition")), 'tif'))),
                                       'ignition',
                                       nodata=np.inf)
        u_initial_map = GeoData.from_cpp_raster(initial_plan.utility_map(),
                                                "utility",
                                                projection=utility.projection)
        u_initial_map.write_to_file(
            os.path.join(
                raster_data_dir, ".".join(("_".join(
                    (instance_name, "utility_initial")), 'tif'))), 'utility')
        u_final_map = GeoData.from_cpp_raster(final_plan.utility_map(),
                                              "utility",
                                              projection=utility.projection)
        u_final_map.write_to_file(
            os.path.join(
                raster_data_dir, ".".join(("_".join(
                    (instance_name, "utility_final")), 'tif'))), 'utility')

    # print([o.as_tuple() for o in final_plan.observations()])

    # Log planned trajectories metadata
    for i, t in enumerate(final_plan.trajectories()):
        _logger.debug("traj #{} duration: {} / {}".format(
            i, t.duration(), t.conf.max_flight_time))

    # save metadata to file
    with open(os.path.join(save_directory, instance_name + ".json"),
              "w") as metadata_file:
        import json
        parsed = json.loads(search_result.metadata())
        parsed["benchmark_id"] = instance_name
        parsed["date"] = datetime.datetime.now().isoformat()
        metadata_file.write(json.dumps(parsed, indent=4))

    matplotlib.pyplot.close(geodatadisplay.axes.get_figure())

    # If intermediate plans are available, save them
    for i, plan in enumerate(search_result.intermediate_plans):
        geodatadisplay = GeoDataDisplay.pyplot_figure(
            env.raster.combine(ignitions))
        geodatadisplay.add_extension(TrajectoryDisplayExtension, (None, ), {})
        plot_plan_with_background(plan, geodatadisplay,
                                  (first_ignition, last_ignition),
                                  output_options_plot)

        i_plan_dir = os.path.join(save_directory, instance_name)
        if not os.path.exists(i_plan_dir):
            os.makedirs(i_plan_dir)

        filepath = os.path.join(
            i_plan_dir,
            str(i) + "." + str(output_options_plot.get('format', 'png')))

        _logger.info("Saving intermediate plan as: %s", str(filepath))
        geodatadisplay.axes.get_figure().set_size_inches(
            *output_options_plot.get('size', (15, 10)))
        geodatadisplay.axes.get_figure().savefig(filepath,
                                                 dpi=output_options_plot.get(
                                                     'dpi', 150),
                                                 bbox_inches='tight')
        matplotlib.pyplot.close(geodatadisplay.axes.get_figure())

    del search_result
Exemple #19
0
def make_flat_utility_map(firemap: GeoData, flight_window: TimeWindow = TimeWindow(-np.inf, np.inf),
                     layer="ignition", output_layer="utility") -> GeoData:
    """Create a constant utility map"""
    utility = firemap.clone(fill_value=1., dtype=[(output_layer, 'float64')])
    utility[output_layer][(firemap[layer] < flight_window.start) | (firemap[layer] > flight_window.end)] = 0.
    return utility
Exemple #20
0
 def firemap(self) -> 'GeoData':
     return GeoData.from_cpp_raster(self._gfmapper.firemap,
                                    self.output_fire_layer)
Exemple #21
0
def empty_firemap(base_raster: GeoData, layer: str = "ignition") -> GeoData:
    """Create an empty fire map from a base raster"""
    return base_raster.clone(fill_value=np.inf, dtype=[(layer, 'float64')])
Exemple #22
0
    # Obtain Obs fire using a firemapper over a fake ground truth.
    # In normal conditions, Obs fire should be provided by neptus
    elevation_draster = pl_env.raster.as_cpp_raster('elevation')
    ignition_draster = ignitions.as_cpp_raster()
    gfmapper = fmapping.GhostFireMapper(
        op.FireData(ignition_draster, elevation_draster))
    # Suposing we follow exactly the planned path
    # executed_path is a tuple with a list of waypoints and a list of the corresponding time
    executed_path = search_result.final_plan().trajectories(
    )[0].sampled_with_time(step_size=10)
    executed_path_wp = executed_path[0]
    executed_path_t = executed_path[1]

    # type: 'op.DRaster'
    obs_fire_raster = gfmapper.observed_firemap(executed_path_wp,
                                                executed_path_t,
                                                flight_confs_cpp[0].uav)

    obs_fire = GeoData.from_cpp_raster(obs_fire_raster, 'ignition')

    gdd = GeoDataDisplay.pyplot_figure(obs_fire)
    gdd.add_extension(TrajectoryDisplayExtension, (None, ))
    gdd.draw_ignition_contour(geodata=ignitions, cmap=mcm.Greens)
    gdd.draw_ignition_shade()
    plot_plan_trajectories(search_result.final_plan(), gdd)

    print("fin")
    # TODO: Reconstruct fire perimeter from Obs fire

    # search_result = observation_planner.replan_after_time(later)