From 218eb8831dc6661d657d9f04a54dae282d82f900 Mon Sep 17 00:00:00 2001 From: Derek Groen Date: Sat, 26 Aug 2023 21:23:53 +0200 Subject: [PATCH] A few bugs removed, flood-driven spawning now with test case. #81 --- flee/InputGeography.py | 4 ++- flee/SimulationSettings.py | 21 +++++++---- flee/spawning.py | 10 +++--- tests/test_conflict_driven_spawning.py | 3 -- tests/test_flood_driven_spawning.py | 49 ++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 tests/test_flood_driven_spawning.py diff --git a/flee/InputGeography.py b/flee/InputGeography.py index 71824251..b37b67b8 100644 --- a/flee/InputGeography.py +++ b/flee/InputGeography.py @@ -391,8 +391,10 @@ def StoreInputGeographyInEcosystem(self, e): @check_args_type - def UpdateLocationAttributes(self, e, attribute_name: str, time: int, Debug: bool = False) -> None: + def UpdateLocationAttributes(self, e, attribute_name: str, time: int) -> None: + attrlist = self.attributes[attribute_name] + for i in range(0, len(e.locations)): loc_name = e.locations[i].name if loc_name in attrlist: diff --git a/flee/SimulationSettings.py b/flee/SimulationSettings.py index 3574f0ec..998551d2 100644 --- a/flee/SimulationSettings.py +++ b/flee/SimulationSettings.py @@ -141,17 +141,28 @@ def ReadFromYML(ymlfile: str): else: SimulationSettings.spawn_rules["displaced_per_conflict_day"] = int(fetchss(dpsc,"displaced_per_conflict_day", 500)) + + # Setting False by default. + SimulationSettings.move_rules["FloodRulesEnabled"] = False + if spawn_type == "flood": dpsc = fetchss(dps,"flood_driven_spawning",None) if dpsc is not None: + SimulationSettings.move_rules["FloodRulesEnabled"] = True + + if SimulationSettings.spawn_rules["TakeFromPopulation"] is False: + print("ERROR in simulationsetting.yml: Flood rules are enabled but take_from_population in spawn_rules is set to False.", file=sys.stderr) + print("This is likely to lead to excessive production of agents in the simulation, so Flee does not support this at this stage.", file=sys.stderr) + sys.exit() + SimulationSettings.spawn_rules["flood_driven_spawning"] = True # Conflicts provide a direct push factor. - SimulationSettings.spawn_rules["flood_spawn_mode"] = fetchss(dpsc,"spawn_mode","constant") # constant, Poisson, pop_ratio + SimulationSettings.spawn_rules["flood_spawn_mode"] = fetchss(dpsc,"spawn_mode","pop_ratio") # constant, Poisson, pop_ratio if SimulationSettings.spawn_rules["flood_spawn_mode"] == "pop_ratio": - SimulationSettings.spawn_rules["displaced_per_flood_day"] = float(fetchss(dpsc,"displaced_per_conflict_day", 0.01)) + SimulationSettings.spawn_rules["displaced_per_flood_day"] = fetchss(dpsc,"displaced_per_flood_day", [0.0,0.1,0.2,0.5,0.9]) #expect an array. else: - SimulationSettings.spawn_rules["displaced_per_flood_day"] = int(fetchss(dpsc,"displaced_per_conflict_day", 500)) + SimulationSettings.spawn_rules["displaced_per_flood_day"] = fetchss(dpsc,"displaced_per_flood_day", [0,100,200,300,500]) SimulationSettings.spawn_rules["conflict_spawn_decay"] = fetchss(dps,"conflict_spawn_decay", None) # Expect an array or dict @@ -247,10 +258,8 @@ def ReadFromYML(ymlfile: str): SimulationSettings.move_rules["FloodLinkWeights"] = fetchss(dps,"flood_link_weights", None) # Expect an array or dict print("Flood Link Weights set to:", SimulationSettings.spawn_rules["FloodLinkWeights"], file=sys.stderr) - # Add verification code. + #TODO: Add verification code. - else: - SimulationSettings.move_rules["FloodRulesEnabled"] = False dpo = fetchss(dp, "optimisations", None) SimulationSettings.optimisations["PopulationScaleDownFactor"] = int(fetchss(dpo,"hasten",1)) diff --git a/flee/spawning.py b/flee/spawning.py index cc9b4dc5..056ca417 100644 --- a/flee/spawning.py +++ b/flee/spawning.py @@ -174,16 +174,18 @@ def spawn_daily_displaced(e, t, d, SumFromCamps=False): num_spawned = 0 - if e.locations[i].attributes["flood_level"] > 0: + print(e.locations[i].attributes) + flood_level = e.locations[i].attributes["flood_level"] + if flood_level > 0: ## BASE RATES if SimulationSettings.spawn_rules["flood_spawn_mode"] == "constant": - num_spawned = int(SimulationSettings.spawn_rules["displaced_per_conflict_day"] * e.locations[i].conflict) + num_spawned = int(SimulationSettings.spawn_rules["displaced_per_conflict_day"][flood_level]) elif SimulationSettings.spawn_rules["flood_spawn_mode"] == "pop_ratio": - num_spawned = int(SimulationSettings.spawn_rules["displaced_per_conflict_day"] * e.locations[i].pop * e.locations[i].conflict) + num_spawned = int(SimulationSettings.spawn_rules["displaced_per_conflict_day"][flood_level] * e.locations[i].pop) elif SimulationSettings.spawn_rules["flood_spawn_mode"].lower() == "poisson": - num_spawned = np.random.poisson(SimulationSettings.spawn_rules["displaced_per_conflict_day"] * e.locations[i].conflict) + num_spawned = np.random.poisson(int(SimulationSettings.spawn_rules["displaced_per_conflict_day"][flood_level])) ## Doing the actual spawning here. for j in range(0, num_spawned): diff --git a/tests/test_conflict_driven_spawning.py b/tests/test_conflict_driven_spawning.py index fcb7a832..3dcd0a47 100644 --- a/tests/test_conflict_driven_spawning.py +++ b/tests/test_conflict_driven_spawning.py @@ -6,7 +6,6 @@ def test_conflict_driven_spawning(): - print("Testing basic data handling and simulation kernel.") flee.SimulationSettings.ReadFromYML("empty.yml") @@ -42,8 +41,6 @@ def test_conflict_driven_spawning(): # All agents should have reached l2, and be deactivated. assert len(e.agents) == 1000 - print("Test successful!") - if __name__ == "__main__": test_conflict_driven_spawning() diff --git a/tests/test_flood_driven_spawning.py b/tests/test_flood_driven_spawning.py new file mode 100644 index 00000000..9afc6cf2 --- /dev/null +++ b/tests/test_flood_driven_spawning.py @@ -0,0 +1,49 @@ +from flee import flee, datamanager + +""" +Testing flood drive spawning for DFlee. +""" + + +def test_flood_driven_spawning(): + + flee.SimulationSettings.ReadFromYML("empty.yml") + + flee.SimulationSettings.move_rules["MaxMoveSpeed"] = 5000.0 + flee.SimulationSettings.move_rules["MaxWalkSpeed"] = 5000.0 + flee.SimulationSettings.move_rules["ForeignWeight"] = 0.0 + + #These values are normally specified in simsetting.yml + flee.SimulationSettings.spawn_rules["flood_driven_spawning"] = True + flee.SimulationSettings.spawn_rules["flood_spawn_mode"] = "constant" + flee.SimulationSettings.spawn_rules["displaced_per_conflict_day"] = [0,100,200,300,400] + + + end_time = 10 + e = flee.Ecosystem() + + l1 = e.addLocation(name="A", movechance=0.0, foreign=False, attributes={"flood_level": 1}) + l2 = e.addLocation(name="B", movechance=0.0, foreign=True, attributes={"flood_level": 0}) + l1.conflict = True + + e.linkUp(endpoint1="A", endpoint2="B", distance=100.0) + + for t in range(0, end_time): + + new_refs,refugees_raw,refugee_debt = flee.spawning.spawn_daily_displaced(e,t,None) + print("new agents: {}".format(new_refs)) + + flee.spawning.refresh_spawn_weights(e) + + # Propagate the model by one time step. + e.evolve() + + assert t == 9 + + # All agents should be spawned in l1 and not be in l2. + assert len(e.agents) == 1000 + assert l1.numAgents == 1000 + + +if __name__ == "__main__": + test_conflict_driven_spawning()