Skip to content

Commit

Permalink
Initial support mobile agents
Browse files Browse the repository at this point in the history
  • Loading branch information
OliverSchmitz committed Nov 2, 2023
1 parent b0af79f commit 529b19a
Show file tree
Hide file tree
Showing 12 changed files with 414 additions and 57 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.18)

project(campo
VERSION 0.3.6
VERSION 0.3.7
DESCRIPTION "Modelling framework for fields and agents"
HOMEPAGE_URL "https://campo.computationalgeography.org/"
LANGUAGES NONE
Expand Down
14 changes: 14 additions & 0 deletions source/campo/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,17 @@ def select(

return result




def coordinates(dataset, phenomenon, propertyset, timestep):

lue_pset = dataset.phenomena[phenomenon].property_sets[propertyset]
object_ids = dataset.phenomena[phenomenon].object_id[:]


time_start_idx = len(object_ids) * (timestep - 1)
time_end_idx = time_start_idx + len(object_ids)

vals = lue_pset.space_domain.value[time_start_idx:time_end_idx]
return vals
92 changes: 68 additions & 24 deletions source/campo/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .points import Points
from .areas import Areas
from .phenomenon import Phenomenon
from .utils import _color_message

import campo.config as cc

Expand Down Expand Up @@ -230,13 +231,16 @@ def _generate_lue_property_set(self, phen_name, property_set):
space_type = ldm.SpaceDomainItemType.box
rank = 2

#if not space_domain.mobile:
space_configuration = ldm.SpaceConfiguration(
ldm.Mobility.stationary,
space_type
)
#else:
# raise NotImplementedError
if(property_set.is_mobile and not static):
space_configuration = ldm.SpaceConfiguration(
ldm.Mobility.mobile,
space_type
)
else:
space_configuration = ldm.SpaceConfiguration(
ldm.Mobility.stationary,
space_type
)

if static:
tmp_pset = dataset.phenomena[phen_name].add_property_set(property_set.name, space_configuration, np.dtype(np.float64), rank=rank)
Expand All @@ -249,24 +253,39 @@ def _generate_lue_property_set(self, phen_name, property_set):
tmp_pset = dataset.phenomena[phen_name].property_sets[property_set.name]


space_coordinate_dtype = tmp_pset.space_domain.value.dtype

# Assign coordinates
if space_type == ldm.SpaceDomainItemType.point:

space_coordinate_dtype = tmp_pset.space_domain.value.dtype
nr_timesteps_and_objects = None
if (property_set.is_mobile):
# Coordinates per timestep
nr_timesteps_and_objects = property_set.nr_objects * self._nr_timesteps
else:
nr_timesteps_and_objects = property_set.nr_objects

tmp_values = np.ones((property_set.nr_objects, 2), dtype=tmp_pset.space_domain.value.dtype)
tmp_values = -999* np.ones((nr_timesteps_and_objects, 2), dtype=space_coordinate_dtype)

# only for the initial
for idx, item in enumerate(property_set.space_domain):
tmp_values[idx, 0] = item[0]
tmp_values[idx, 1] = item[1]
tmp_pset.space_domain.value.expand(property_set.nr_objects)[-property_set.nr_objects:] = tmp_values
tmp_values[idx, 0] = item[0]
tmp_values[idx, 1] = item[1]

tmp_pset.space_domain.value.expand(nr_timesteps_and_objects)[-nr_timesteps_and_objects:] = tmp_values

time_boxes = 1

if tmp_pset.object_tracker.active_object_id.nr_ids == 0:
tmp_pset.object_tracker.active_object_id.expand(time_boxes * nr_timesteps_and_objects)[:] = np.arange(nr_timesteps_and_objects)
tmp_pset.object_tracker.active_set_index.expand(time_boxes)[:] = 0
time_domain = tmp_pset.time_domain
time_domain.value.expand(time_boxes)[:] = np.array([0, self._nr_timesteps])

elif space_type == ldm.SpaceDomainItemType.box:

space_coordinate_dtype = tmp_pset.space_domain.value.dtype

tmp_values = np.zeros((property_set.nr_objects, 4), dtype=tmp_pset.space_domain.value.dtype)
tmp_values = np.empty((property_set.nr_objects, 4), dtype=tmp_pset.space_domain.value.dtype)

for idx, item in enumerate(property_set.space_domain):
tmp_values[idx, 0] = item[0]
Expand Down Expand Up @@ -337,6 +356,21 @@ def _lue_write_property(self, phen_name, pset, prop, timestep):
lue_pset = dataset.phenomena[phen_name].property_sets[pset.name]
object_ids = dataset.phenomena[phen_name].object_id[:]

if pset._lue_filename is None:
pset._lue_filename = self.lue_filename

# Agents mobile during time
if(pset.is_mobile and timestep is not None):
coord_start_idx = len(object_ids) * (timestep - 1)
coord_end_idx = coord_start_idx + len(object_ids)

campo_pset = self._phenomena[phen_name].property_sets[pset.name]
campo_coords_ts = campo_pset.space_domain._get_coordinates()

lue_pset.space_domain.value[coord_start_idx:coord_end_idx] = campo_coords_ts


# Writing property values
if not prop.is_dynamic:
lue_prop = lue_pset.properties[prop.name]
if isinstance(prop.space_domain, Points):
Expand Down Expand Up @@ -368,19 +402,26 @@ def _lue_write_property(self, phen_name, pset, prop, timestep):


def write(self, timestep=None):
""" """
dataset = ldm.open_dataset(self.lue_filename, 'r')
# Get list of phenomena such that we can close the dataset immediately
dataset_phenomena = dataset.phenomena.names
dataset = None
""" Writing current state to a LUE dataset
:param timestep: None for initial, integer timestep number otherwise
"""
if (not self._nr_timesteps):
msg = _color_message(f"Number of timesteps not yet specified, use set_time")
raise RuntimeError(msg)

for p in self._phenomena:
if not p in dataset_phenomena:
self._generate_lue_phenomenon(self._phenomena[p])
dataset = ldm.open_dataset(self.lue_filename, 'r')
# Get list of phenomena such that we can close the dataset immediately
dataset_phenomena = dataset.phenomena.names
dataset = None

for p in self._phenomena:
if not p in dataset_phenomena:
self._generate_lue_phenomenon(self._phenomena[p])

for pset in self._phenomena[p].property_sets.values():
for prop in pset.properties.values():
self._lue_write_property(p, pset, prop, timestep)
for prop in pset.properties.values():
self._lue_write_property(p, pset, prop, timestep)


def set_time(self, start, unit, stepsize, nrTimeSteps):
Expand All @@ -390,6 +431,9 @@ def set_time(self, start, unit, stepsize, nrTimeSteps):
self._clock_unit_value = unit.value
self._clock_stepsize = stepsize

if (not self.lue_filename):
msg = _color_message(f"Dataset filename not yet specified, use create_dataset before")
raise RuntimeError(msg)

epoch = ldm.Epoch(ldm.Epoch.Kind.common_era, self._start_timestep, ldm.Calendar.gregorian)
clock = ldm.Clock(epoch, self._clock_unit_value, self._clock_stepsize)
Expand Down
56 changes: 36 additions & 20 deletions source/campo/op_fieldagents/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,23 @@ def uniform(lower, upper):

tmp_prop = Property('emptyuniformname', lower.pset_uuid, lower.space_domain, lower.shapes)

if isinstance(lower.space_domain, Points):
shape = 1
elif isinstance(lower.space_domain, Areas):
shape = (int(lower.space_domain.row_discr[0]), int(lower.space_domain.col_discr[0]))
else:
raise NotImplementedError

for idx in range(lower.nr_objects):
values = None
if isinstance(lower.space_domain, Points):
lower_value = lower.values()[idx][0]
upper_value = upper.values()[idx][0]
values = cc.rng.uniform(low=lower_value, high=upper_value, size=1)
values = cc.rng.uniform(low=lower_value, high=upper_value, size=shape)
elif isinstance(lower.space_domain, Areas):
raise NotImplementedError("WIP")
if seed != 0:
numpy.random.seed(seed + idx)
values = numpy.random.uniform(lower.values()[idx], upper.values()[idx], (int(lower.space_domain.row_discr[idx]), int(lower.space_domain.col_discr[idx])))
lower_value = lower.values()[idx]
upper_value = upper.values()[idx]
values = cc.rng.uniform(low=lower_value, high=upper_value, size=shape)
else:
raise NotImplementedError

Expand Down Expand Up @@ -74,17 +80,23 @@ def normal(mean, stddev):

tmp_prop = Property('emptynormalname', mean.pset_uuid, mean.space_domain, mean.shapes)

if isinstance(mean.space_domain, Points):
shape = 1
elif isinstance(mean.space_domain, Areas):
shape = (int(mean.space_domain.row_discr[0]), int(mean.space_domain.col_discr[0]))
else:
raise NotImplementedError

for idx in range(mean.nr_objects):
values = None
if isinstance(mean.space_domain, Points):
mean_value = mean.values()[idx][0]
stddev_value = stddev.values()[idx][0]
values = cc.rng.normal(loc=mean_value, scale=stddev_value, size=1)
values = cc.rng.normal(loc=mean_value, scale=stddev_value, size=shape)
elif isinstance(mean.space_domain, Areas):
raise NotImplementedError("WIP")
if seed != 0:
numpy.random.seed(seed + idx)
values = numpy.random.normal(lower.values()[idx], upper.values()[idx], (int(lower.space_domain.row_discr[idx]), int(lower.space_domain.col_discr[idx])))
mean_value = mean.values()[idx]
stddev_value = stddev.values()[idx]
values = cc.rng.normal(loc=mean_value, scale=stddev_value, size=shape)
else:
raise NotImplementedError

Expand All @@ -94,16 +106,14 @@ def normal(mean, stddev):



def random_integers(lower, upper, seed=0):
def random_integers(lower, upper):
""" Returns for each object random_integers values. Can be applied to fields and objects
:param lower: lower boundary
:type lower: Property
:param upper: upper boundary
:type upper: Property
:param seed: random seed (default 0)
:type seed: int
:returns: a property with random integers values
:returns: a property with random integers values from lower (inclusive) to upper (exclusive)
:rtype: Property
"""
Expand All @@ -120,17 +130,23 @@ def random_integers(lower, upper, seed=0):

tmp_prop = Property('emptynormalname', lower.pset_uuid, lower.space_domain, lower.shapes)

if isinstance(lower.space_domain, Points):
shape = 1
elif isinstance(lower.space_domain, Areas):
shape = (int(lower.space_domain.row_discr[0]), int(lower.space_domain.col_discr[0]))
else:
raise NotImplementedError

for idx in range(lower.nr_objects):
values = None
if isinstance(lower.space_domain, Points):
if seed != 0:
numpy.random.seed(seed + idx)
values = numpy.random.random_integers(lower.values()[idx], upper.values()[idx])
lower_value = lower.values()[idx][0]
upper_value = upper.values()[idx][0]
values = cc.rng.integers(low=lower_value, high=upper_value, size=shape)
elif isinstance(lower.space_domain, Areas):
if seed != 0:
numpy.random.seed(seed + idx)
values = numpy.random.random_integers(lower.values()[idx], upper.values()[idx], (int(lower.space_domain.row_discr[idx]), int(lower.space_domain.col_discr[idx])))
lower_value = lower.values()[idx]
upper_value = upper.values()[idx]
values = cc.rng.integers(low=lower_value, high=upper_value, size=shape)
else:
raise NotImplementedError

Expand Down
1 change: 1 addition & 0 deletions source/campo/phenomenon.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def add_property_set(self, pset_name, filename):
assert self._nr_objects == nr_objects

p = PropertySet(pset_name, nr_objects, domain, shape)
p._phenomenon_name = self._name
self._property_sets[pset_name] = p

self._nr_psets += 1
Expand Down
18 changes: 17 additions & 1 deletion source/campo/points.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def __init__(self, mobile=False):
self.xcoord = None
self.ycoord = None

self._coordinates = None

self._mobile = mobile

self.iter_idx = 0
Expand Down Expand Up @@ -78,7 +80,7 @@ def read(self, filename):
#self.xcoord = x
#self.ycoord = y

v = numpy.zeros((self.nr_items,2))
v = numpy.empty((self.nr_items,2))
for idx, item in enumerate(content):
v[idx,0] = item[0]
v[idx,1] = item[1]
Expand All @@ -88,6 +90,8 @@ def read(self, filename):
self.ycoord = v[:,1]


self._coordinates = numpy.empty((self.nr_items, 2))


def __iter__(self):
return self
Expand All @@ -98,6 +102,7 @@ def __next__(self):
raise StopIteration

values = (self.xcoord[self.iter_idx], self.ycoord[self.iter_idx])
values = self.xcoord[self.iter_idx], self.ycoord[self.iter_idx]
self.iter_idx += 1

return values
Expand All @@ -109,3 +114,14 @@ def __len__(self):

def __repr__(self):
return 'Point'


def _get_coordinates(self):

self._coordinates[:,0] = self.xcoord
self._coordinates[:,1] = self.ycoord
return self._coordinates


def _set_coordinates(self, values):
self._coordinates = values
Loading

0 comments on commit 529b19a

Please sign in to comment.