Exemplo n.º 1
0
        def add_stem_properties(phenomenon):

            # Property-set for properties attached to tree stems. Stems
            # are located in space using stationary 2D points.

            # Property-set
            space_configuration = lue.SpaceConfiguration(
                lue.Mobility.stationary, lue.SpaceDomainItemType.point)
            space_coordinate_datatype = np.dtype(np.float32)
            stem_points = phenomenon.add_property_set(
                "stems", space_configuration, space_coordinate_datatype, rank)

            # Space domain
            space_domain = stem_points.space_domain
            space_points = np.arange(nr_trees * rank,
                                     dtype=space_coordinate_datatype).reshape(
                                         nr_trees, 2)
            space_domain.value.expand(nr_trees)[:] = space_points

            # Property
            tree_kind = stem_points.add_property("kind",
                                                 dtype=np.dtype(np.uint8))
            tree_kind.value.expand(nr_trees)[:] = \
                (10 * np.random.rand(nr_trees)).astype(np.uint8)

            return stem_points
Exemplo n.º 2
0
    def test_case_study(self):

        dataset = lue.create_dataset("areas.lue")
        areas = dataset.add_phenomenon("areas")

        nr_areas = 10

        # IDs
        ids = numpy.arange(nr_areas, dtype=numpy.uint64)
        areas.object_id.expand(nr_areas)[:] = ids

        space_configuration = lue.SpaceConfiguration(
            lue.Mobility.stationary, lue.SpaceDomainItemType.box)
        coordinate_datatype = numpy.dtype(numpy.float32)
        rank = 2
        area_boxes = areas.add_property_set("areas", space_configuration,
                                            coordinate_datatype, rank)

        # Space domain
        space_domain = area_boxes.space_domain
        boxes = numpy.arange(nr_areas * rank * 2,
                             dtype=coordinate_datatype).reshape(nr_areas, 4)
        space_domain.value.expand(nr_areas)[:] = boxes

        # Discretization property
        count_datatype = lue.dtype.Count
        discretization = area_boxes.add_property("discretization",
                                                 dtype=count_datatype,
                                                 shape=(rank, ))
        shapes = numpy.arange(nr_areas * rank,
                              dtype=count_datatype).reshape(nr_areas, 2)
        discretization.value.expand(nr_areas)[:] = shapes

        # Elevation property
        elevation_datatype = numpy.dtype(numpy.float32)
        elevation = area_boxes.add_property("elevation",
                                            dtype=elevation_datatype,
                                            rank=rank)
        grids = elevation.value.expand(ids, shapes)
        for a in range(nr_areas):
            grids[ids[a]][:] = \
                (10 * numpy.random.rand(*shapes[a])).astype(elevation_datatype)

        # Link elevation to discretization
        elevation.set_space_discretization(
            lue.SpaceDiscretization.regular_grid, discretization)

        lue.assert_is_valid(dataset)
Exemplo n.º 3
0
import numpy as np
import lue

nr_areas = 10
rank = 2

dataset = lue.create_dataset("elevation.lue")
area = dataset.add_phenomenon("area")

# id = [2, 4, 6, 8, 10, 9, 7, 5, 3, 1]
# area.object_id.expand(nr_areas)[:] = id

time_configuration = lue.TimeConfiguration(lue.TimeDomainItemType.box)
clock = lue.Clock(lue.Unit.day, 1)
space_configuration = lue.SpaceConfiguration(lue.Mobility.stationary,
                                             lue.SpaceDomainItemType.box)
variable = area.add_property_set("variable",
                                 time_configuration,
                                 clock,
                                 space_configuration,
                                 space_coordinate_dtype=np.dtype(np.float32),
                                 rank=rank)

object_tracker = variable.object_tracker

### # Time domain contains 1D boxes, with a resolution of 1 day
### time_domain = located.create_time_box_domain(areas, lue.Clock(lue.unit.day, 1))
### nr_time_boxes = 4
### time_boxes = time_domain.reserve(nr_time_boxes)
### # A box is defined by a begin and end time point (two coordinates per box)
### # Here, we configure time boxes with a duration of 10 days. The time
Exemplo n.º 4
0
        def discharge_property(phenomenon):

            nr_outlets = 10

            ids = numpy.arange(nr_outlets, dtype=numpy.uint64)
            phenomenon.object_id.expand(nr_outlets)[:] = ids

            # Time domain
            time_configuration = lue.TimeConfiguration(
                lue.TimeDomainItemType.box)
            clock = lue.Clock(lue.Unit.day, 1)

            # Space domain
            space_configuration = lue.SpaceConfiguration(
                lue.Mobility.stationary, lue.SpaceDomainItemType.point)
            space_coordinate_datatype = numpy.dtype(numpy.float64)
            rank = 2

            # Property set
            outlet_points = phenomenon.add_property_set(
                "outlets", time_configuration, clock, space_configuration,
                space_coordinate_datatype, rank)

            # IDs
            object_tracker = outlet_points.object_tracker

            object_tracker.active_set_index.expand(nr_time_boxes)

            active_set_sizes = numpy.random.randint(
                0, nr_outlets, nr_time_boxes).astype(dtype=lue.dtype.Count)
            active_set_idxs = numpy.empty(nr_time_boxes, dtype=lue.dtype.Index)
            active_object_ids = numpy.empty(active_set_sizes.sum(),
                                            dtype=lue.dtype.ID)

            lue.test.select_random_ids(active_set_sizes, active_set_idxs,
                                       active_object_ids, nr_outlets)

            object_tracker.active_object_id.expand(len(active_object_ids))

            active_set_idx = numpy.uint64(0)

            for s in range(nr_time_boxes):
                active_set_size = active_set_sizes[s]
                object_tracker.active_set_index[s] = active_set_idxs[s]
                object_tracker.active_object_id[
                        active_set_idx:active_set_idx + active_set_size] = \
                    active_object_ids[active_set_idx:active_set_idx + active_set_size]
                active_set_idx += active_set_size

            # Time domain
            time_domain = outlet_points.time_domain
            time_coordinate_datatype = lue.dtype.TickPeriodCount
            time_boxes = numpy.arange(nr_time_boxes * 2,
                                      dtype=time_coordinate_datatype).reshape(
                                          nr_time_boxes, 2)
            time_domain.value.expand(nr_time_boxes)[:] = time_boxes

            # Space domain
            space_domain = outlet_points.space_domain
            space_points = numpy.arange(
                nr_outlets * rank,
                dtype=space_coordinate_datatype).reshape(nr_outlets, 2)
            space_domain.value.expand(nr_outlets)[:] = space_points

            # Property
            discharge_datatype = numpy.dtype(numpy.float32)
            discharge = outlet_points.add_property(
                "discharge",
                dtype=discharge_datatype,
                rank=1,
                shape_per_object=lue.ShapePerObject.same,
                shape_variability=lue.ShapeVariability.variable)

            discharge_values = [
                numpy.arange(shapes[t] * active_set_sizes[t],
                             dtype=discharge_datatype)
                for t in range(nr_time_boxes)
            ]

            for t in range(nr_time_boxes):
                discharge.value.expand(
                        t, active_set_sizes[t], (shapes[t],))[:] = \
                    discharge_values[t]

            return discharge
Exemplo n.º 5
0
        def add_crown_properties(phenomenon):

            # Property-set for properties attached to tree crowns. Crowns
            # are located in space using stationary 2D boxes within
            # which the presence is discretized. The presence of the
            # growing crowns changes through time.
            # So, even though the boxes are stationary, presence can
            # still vary through time.

            # Property set
            time_configuration = lue.TimeConfiguration(
                lue.TimeDomainItemType.box)
            clock = lue.Clock(lue.Unit.week, 1)

            space_configuration = lue.SpaceConfiguration(
                lue.Mobility.stationary, lue.SpaceDomainItemType.box)
            space_coordinate_datatype = np.dtype(np.float32)

            crown_boxes = phenomenon.add_property_set(
                "crowns", time_configuration, clock, space_configuration,
                space_coordinate_datatype, rank)

            # [0, nr_trees, 2 * nr_tree, ..., t * nr_trees]
            crown_boxes.object_tracker.active_set_index.expand(
                    nr_time_boxes)[:] = \
                np.array(
                    [t * nr_trees for t in range(nr_time_boxes)],
                    dtype=lue.dtype.Index)

            # [0, 0, 0, ..., nr_time_boxes-1, nr_time_boxes-1]
            crown_boxes.object_tracker.active_object_index.expand(
                    nr_time_boxes * nr_trees)[:] = \
                np.repeat(
                    np.arange(0, nr_time_boxes, dtype=lue.dtype.Index),
                    repeats=nr_trees)

            # [id1, id2, ..., idn, ..., id1, id2, ...idn]
            crown_boxes.object_tracker.active_object_id.expand(
                    nr_time_boxes * nr_trees)[:] = \
                np.repeat(
                    ids.reshape((1, nr_trees)),
                    repeats=nr_time_boxes,
                    axis=0).flatten()

            # Space domain
            space_domain = crown_boxes.space_domain
            boxes = np.arange(
                nr_trees * rank * 2, dtype=space_coordinate_datatype) \
                    .reshape(nr_trees, 4)
            space_domain.value.expand(nr_trees)[:] = boxes

            # Time domain
            time_domain = crown_boxes.time_domain
            time_coordinate_datatype = lue.dtype.TickPeriodCount
            boxes = np.arange(
                nr_time_boxes * 2, dtype=time_coordinate_datatype) \
                    .reshape(nr_time_boxes, 2)
            time_domain.value.expand(nr_time_boxes)[:] = boxes

            presence = discretized_presence(crown_boxes)
            crown_boxes.space_domain.set_presence_discretization(presence)

            return crown_boxes
Exemplo n.º 6
0
    def test_case_study2(self):

        dataset = lue.create_dataset("forest.lue")

        # We are assuming here that we can model biomass of trees in a
        # forest on a daily basis, during the growth season. This allows
        # us to use multiple discretized time boxes.
        time_cell_configuration = lue.TimeConfiguration(
            lue.TimeDomainItemType.cell)
        clock = lue.Clock(lue.Unit.day, 1)
        time_coordinate_datatype = lue.dtype.TickPeriodCount

        # Trees usually don't move. Forests neither.
        stationary_space_point_configuration = lue.SpaceConfiguration(
            lue.Mobility.stationary, lue.SpaceDomainItemType.point)
        stationary_space_box_configuration = lue.SpaceConfiguration(
            lue.Mobility.stationary, lue.SpaceDomainItemType.box)
        space_coordinate_datatype = np.dtype(np.float32)
        space_rank = 2

        count_datatype = lue.dtype.Count
        cell_size = 0.5  # m
        max_size_of_crown = int(20 / cell_size)  # 20 m in nr of cells
        nr_cells_in_crown = max_size_of_crown**2

        biomass_datatype = np.dtype(np.float32)

        # Trees ----------------------------------------------------------------
        trees = dataset.add_phenomenon("trees")
        stems = trees.add_property_set("stems",
                                       stationary_space_point_configuration,
                                       space_coordinate_datatype, space_rank)
        crowns = trees.add_property_set("crowns", time_cell_configuration,
                                        clock,
                                        stationary_space_box_configuration,
                                        space_coordinate_datatype, space_rank)
        crowns_biomass = crowns.add_property(
            "biomass",
            dtype=biomass_datatype,
            shape=(max_size_of_crown, max_size_of_crown),
            value_variability=lue.ValueVariability.variable)

        # Biomass discretization
        # Each biomass value is a 2D value with the same shape
        # (max_size_of_crown x max_size_of_crown). In this value biomass
        # values are stored per cell. The discretization of each extent
        # is stored in the crown discretization property. This property
        # only needs to store a single value with nr_rows/nr_cols of each
        # crown extent. This value is the same for each crown and does
        # not change through time. It can therefore be stored as a static
        # property in the collection property sets of the trees phenomenon.
        trees_globals = trees.add_collection_property_set("globals")
        crowns_biomass_discretization = trees_globals.add_property(
            "biomass_discretization",
            dtype=count_datatype,
            shape=(space_rank, ))
        crowns_biomass_discretization.value.expand(1)[:] = np.array(
            [max_size_of_crown, max_size_of_crown],
            dtype=count_datatype).reshape(1, space_rank)

        # Link biomass to discretization
        crowns_biomass.set_space_discretization(
            lue.SpaceDiscretization.regular_grid,
            crowns_biomass_discretization)

        # Forests --------------------------------------------------------------
        # TODO Each forest could be represented by a boolean space
        #    grid in the property set. If this is not necessary, biomass
        #    can be a discretized property within an extent.
        forests = dataset.add_phenomenon("forests")
        areas = forests.add_property_set("areas", crowns.time_domain,
                                         stationary_space_box_configuration,
                                         space_coordinate_datatype, space_rank)
        areas_biomass = areas.add_property(
            "biomass",
            dtype=biomass_datatype,
            rank=space_rank,
            shape_per_object=lue.ShapePerObject.different,
            shape_variability=lue.ShapeVariability.constant)

        # Forest biomass discretization
        forests_globals = forests.add_collection_property_set("globals")
        forests_biomass_discretization = forests_globals.add_property(
            "biomass_discretization",
            dtype=count_datatype,
            shape=(space_rank, ))

        # TODO The extent of the forest must be known beforehand
        nr_forests = 1
        forest_ids = np.arange(nr_forests, dtype=lue.dtype.ID)
        forest_shapes = \
            np.arange(nr_forests * space_rank, dtype=count_datatype) \
                .reshape(nr_forests, space_rank) + 10
        forests_biomass_discretization.value.expand(nr_forests)[:] = np.array(
            [100, 100], dtype=count_datatype).reshape(nr_forests, space_rank)

        # Link biomass to discretization
        areas_biomass.set_space_discretization(
            lue.SpaceDiscretization.regular_grid,
            forests_biomass_discretization)

        # Iterate over time boxes (only growth season)
        #     Iterate over time cells
        #         - Calculate birth and death of trees
        #             - Birth:
        #                 - Add ID to trees phenomenon
        #                 - Add location to stem property-set
        #                 - Add ID to crowns property set object tracker
        #                 - Center max_crown_extent sized space box
        #                     around stem and add to crowns property-set
        #                 - Store presence in boolean presence space grid
        #                     and for all true cell store a biomass, or
        #                 - store biomass distribution as a discretized
        #                     2D value
        #             - Death
        #                 - Stop writing ID to crowns property set
        #                     object tracker
        #                 - Stop writing (presence grid and) biomass
        #                     property values
        #         - Calculate tree growth of living trees
        #         - Calculate the distribution of biomass within the forest
        #             - Per forest, write current biomass to biomass
        #                 property

        # TODO Fix handling of time

        # Per year, only changes in state during the growth season
        # are stored
        nr_years = 10
        nr_days_per_year = 365
        start_of_growth_season = 50  # Within each year
        nr_days_per_growth_season = 200

        crowns_time_boxes = crowns.time_domain.value.expand(nr_years)
        crowns_time_cell_counts = \
            crowns.time_domain.value.count.expand(nr_years)

        crowns_active_set_index = crowns.object_tracker.active_set_index
        crowns_active_object_id = crowns.object_tracker.active_object_id

        areas_active_set_index = areas.object_tracker.active_set_index
        areas_active_object_id = areas.object_tracker.active_object_id
        areas_active_object_idx = areas.object_tracker.active_object_index

        for id_ in forest_ids:
            areas_biomass.value.expand(forest_ids[id_],
                                       tuple(forest_shapes[id_]),
                                       nr_years * nr_days_per_growth_season)

        for y in range(nr_years):

            # Time domain item for this growth season
            t_start = (y * nr_days_per_year) + start_of_growth_season
            t_end = t_start + nr_days_per_growth_season
            time_box = np.array([t_start, t_end],
                                dtype=time_coordinate_datatype)
            crowns_time_boxes[y] = time_box
            crowns_time_cell_counts[y] = nr_days_per_growth_season

            for d in range(nr_days_per_growth_season):
                d_idx = y * nr_days_per_growth_season + d

                # TODO
                # Determine collection of starting trees:
                # - ID
                # - Stem location
                # - Crown extent
                starting_tree_ids = np.array([d_idx], dtype=lue.dtype.ID)
                nr_starting_trees = len(starting_tree_ids)
                starting_tree_stem_locations = np.arange(
                    nr_starting_trees * space_rank,
                    dtype=space_coordinate_datatype).reshape(
                        nr_starting_trees, space_rank)
                starting_tree_crown_locations = np.arange(
                    nr_starting_trees * space_rank * 2,
                    dtype=space_coordinate_datatype).reshape(
                        nr_starting_trees, space_rank * 2)

                # Store IDs of starting trees in collection of IDs
                trees.object_id.expand(nr_starting_trees)[-nr_starting_trees] = \
                    starting_tree_ids

                # Store stem locations of starting trees
                stems.space_domain.value.expand(nr_starting_trees)[-nr_starting_trees] = \
                    starting_tree_stem_locations

                # Store crown extents of starting trees
                crowns.space_domain.value.expand(nr_starting_trees)[-nr_starting_trees] = \
                    starting_tree_crown_locations

                # Determine collection of stopping trees:
                # - ID
                stopping_tree_ids = np.array([], dtype=lue.dtype.ID)

                # Determine collection of active trees
                # - ID
                # - Biomass
                active_tree_ids = starting_tree_ids  # TODO remove stopping trees

                # Store IDs of active trees in the active set
                object_index = crowns_active_object_id.nr_ids
                crowns_active_set_index.expand(1)[-1] = object_index
                nr_active_trees = len(active_tree_ids)

                crowns_active_object_id.expand(nr_active_trees)[object_index:] = \
                    active_tree_ids

                # For all active trees, calculate new biomass values and
                # write them to the biomass property
                crowns_biomass_values = \
                    np.arange(
                        nr_active_trees * nr_cells_in_crown,
                        dtype=biomass_datatype).reshape(
                            nr_active_trees,
                            max_size_of_crown, max_size_of_crown)
                crowns_biomass.value.expand(nr_active_trees)[object_index:] = \
                    crowns_biomass_values

                # Store IDs of active forests in the active set
                # Currently this is the one and only forest containing
                # all trees.
                active_forest_ids = np.array([0], dtype=lue.dtype.ID)
                active_forest_idxs = np.array([d], dtype=lue.dtype.Index)
                object_index = areas_active_object_id.nr_ids
                areas_active_set_index.expand(1)[-1] = object_index
                nr_active_forests = len(active_forest_ids)
                areas_active_object_id.expand(nr_active_forests)[object_index:] = \
                    active_forest_ids
                areas_active_object_idx.expand(nr_active_forests)[object_index:] = \
                    active_forest_idxs

                # For all forests, calculate new biomass values and
                # write them to the biomass property
                for id_ in forest_ids:
                    forest_shape = tuple(forest_shapes[id_])
                    nr_cells_in_forest = forest_shape[0] * forest_shape[1]
                    areas_biomass.value[id_][y] = \
                        np.arange(nr_cells_in_forest, dtype=biomass_datatype) \
                            .reshape(*forest_shape)

        # Initialize forests. All trees should be located within one of
        # the forests. For now, we assume all trees are part of a
        # single forest. The extent of this forest is the bounding box
        # around all tree crowns.

        nr_trees = len(crowns.space_domain.value)

        if nr_trees > 0:

            # Store IDs of starting trees in collection of IDs
            forests.object_id.expand(1)[-1] = 0

            min_x, min_y, max_x, max_y = crowns.space_domain.value[0]

            for crown_space_box in crowns.space_domain.value[1:]:
                min_x, min_y, max_x, max_y = \
                    min(min_x, crown_space_box[0]), \
                    min(min_y, crown_space_box[1]), \
                    max(max_x, crown_space_box[2]), \
                    max(max_y, crown_space_box[3])

            forest_space_box = np.array([min_x, min_y, max_x, max_y],
                                        dtype=space_coordinate_datatype)
            areas.space_domain.value.expand(1)[-1] = forest_space_box

        lue.assert_is_valid(dataset)
Exemplo n.º 7
0
    def test_case_study(self):

        # Time series as implemented here:
        # - Discharge at catchment outlets
        #     - Located at fixed points in space
        #     - Variable number of outlets per time cell
        #     - Presence of outlets is discretized within multiple time boxes

        # - Time domain contains time cells
        # - Space domain contains space points
        # - Property values are same_shape::constant_shape (shape of value is
        #     related to what is stored per cell)
        # - Property values are not discretized
        # - Per time cell the set of active objects is tracked
        # - Use this approach if the active set is variable within a
        #     time box
        #     - - Additional storage required for tracking active sets,
        #         compared to Time series I
        #     - + Possible to let objects be 'born' and 'die' during
        #         iterative simulation

        dataset = lue.create_dataset("outlets2.lue")
        phenomenon = dataset.add_phenomenon("areas")

        # Assume we are simulating some temporal variable (discharge at
        # catchment outlets).
        # The existance of the objects is modelled using time cells,
        # which are discretized time boxes (daily time steps). Per cell we
        # can store which objects are active.
        # Property values are located in time at time cells.
        # Property values are located in space at stationary space points.

        # Time domain
        time_configuration = lue.TimeConfiguration(lue.TimeDomainItemType.cell)
        epoch = lue.Epoch(lue.Epoch.Kind.common_era, "2019-01-01",
                          lue.Calendar.gregorian)
        clock = lue.Clock(epoch, lue.Unit.day, 1)
        time_coordinate_datatype = lue.dtype.TickPeriodCount

        # Space domain
        space_configuration = lue.SpaceConfiguration(
            lue.Mobility.stationary, lue.SpaceDomainItemType.point)
        space_coordinate_datatype = numpy.dtype(numpy.float32)
        rank = 2

        # Property set
        outlet_points = phenomenon.add_property_set("outlets",
                                                    time_configuration, clock,
                                                    space_configuration,
                                                    space_coordinate_datatype,
                                                    rank)
        time_domain = outlet_points.time_domain
        space_domain = outlet_points.space_domain
        active_set_index = outlet_points.object_tracker.active_set_index
        active_object_id = outlet_points.object_tracker.active_object_id

        # Property
        discharge_datatype = numpy.dtype(numpy.float32)
        discharge = outlet_points.add_property(
            "discharge",
            dtype=discharge_datatype,
            shape=(1, ),
            value_variability=lue.ValueVariability.variable)

        nr_time_boxes = 5
        max_nr_objects = 100

        # Iterate over the time boxes
        for t in range(nr_time_boxes):

            # Store additional time box and count
            time_box = numpy.array([t, t + 1], dtype=time_coordinate_datatype)
            time_domain.value.expand(1)[-1] = time_box
            count = int(10 * random.random())
            time_domain.value.count.expand(1)[-1] = count

            # Iterate over the time cells within each time box
            for c in range(count):

                # Store IDs of objects in the active set
                object_index = active_object_id.nr_ids
                active_set_index.expand(1)[-1] = object_index
                nr_objects = int(random.random() * max_nr_objects)

                object_id = numpy.empty(nr_objects, dtype=lue.dtype.ID)
                lue.test.select_random_ids(object_id, max_nr_objects)
                active_object_id.expand(nr_objects)[object_index:] = object_id

                # Store property values of active objects
                discharge_values = \
                    numpy.arange(nr_objects, dtype=discharge_datatype)
                discharge.value.expand(nr_objects)[object_index:] = \
                    discharge_values

        lue.assert_is_valid(dataset)

        del dataset

        dataset = lue.open_dataset("outlets2.lue")
        phenomenon = dataset.phenomena["areas"]
        outlet_points = phenomenon.property_sets["outlets"]
        time_domain = outlet_points.time_domain
        clock = time_domain.clock

        self.assertEqual(clock.epoch.kind, lue.Epoch.Kind.common_era)
        self.assertEqual(clock.epoch.origin, "2019-01-01")
        self.assertEqual(clock.epoch.calendar, lue.Calendar.gregorian)
        self.assertEqual(clock.unit, lue.Unit.day)
        self.assertEqual(clock.nr_units, 1)