Skip to content

Commit

Permalink
Refactor simulation options
Browse files Browse the repository at this point in the history
  • Loading branch information
jvail committed Nov 10, 2023
1 parent fcafb17 commit 0fa5eb1
Show file tree
Hide file tree
Showing 17 changed files with 96 additions and 116 deletions.
56 changes: 10 additions & 46 deletions notebooks/simulation.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[general]
date_start = 1994-05-01
date_end = 2000-06-30
date_end = 2010-06-30
seed = 1163078255
second_year_draws = true
ruptures = false
ruptures = true
stake = true
select_trunk = 0
mechanics = true
Expand All @@ -12,6 +12,7 @@ stride_number = 5
pruning = false
convergence_steps = 2

# relative to vmapplet/lpy
[input.lpy_files]
axiom = 'axiom.lpy'
parameters = 'parameters.lpy'
Expand All @@ -20,21 +21,22 @@ statistics = 'statistics.lpy'
structure = 'structure.lpy'
interpretation = 'interpretation.lpy'

# relative to vmapplet/data/markov
[input.markov_files]
terminal_fate = 'fuji/terminal_fate.toml'
models = 'fuji/models'

[output]
dates = [
{ day = 1, month = 6 },
{ day = 1, month = 11 },
]

# All of those attributes will be available in the MTGs
[output.attributes]
tree = [
'growth_units'
]
# FIX: mtg display error when GUs are exported
growth_unit = [
'year',
'inflorescence'
]
metamer = [
'number',
'closest_apex',
Expand Down Expand Up @@ -100,48 +102,10 @@ terminal_expansion_rate = 2e-5
minimum_size = 0.00075
maximum_size = 0.003

[markov]
[shoot]
maximum_length = 70
minimum_length = 4

# order matters: index = year_no - 1
[[markov.terminal_fate]]
large = [0.500, 0.167, 0.000, 0.333]
medium = [0.000, 0.000, 0.000, 1.000]
small = [0.100, 0.100, 0.300, 0.500]
floral = [0.100, 0.300, 0.600, 0.000]

[[markov.terminal_fate]]
large = [0.246, 0.185, 0.000, 0.569]
medium = [0.016, 0.238, 0.032, 0.714]
small = [0.066, 0.067, 0.317, 0.550]
floral = [0.317, 0.250, 0.433, 0.000]

[[markov.terminal_fate]]
large = [0.351, 0.106, 0.010, 0.533]
medium = [0.123, 0.148, 0.063, 0.666]
small = [0.015, 0.094, 0.453, 0.438]
floral = [0.182, 0.249, 0.569, 0.000]

[[markov.terminal_fate]]
large = [0.213, 0.082, 0.000, 0.705]
medium = [0.027, 0.046, 0.016, 0.911]
small = [0.000, 0.024, 0.205, 0.771]
floral = [0.003, 0.413, 0.584, 0.000]

[[markov.terminal_fate]]
large = [0.100, 0.050, 0.000, 0.850]
medium = [0.000, 0.020, 0.130, 0.850]
small = [0.000, 0.000, 0.375, 0.625]
floral = [0.008, 0.325, 0.667, 0.000]

[[markov.terminal_fate]]
large = [0.000, 0.100, 0.000, 0.900]
medium = [0.000, 0.050, 0.050, 0.900]
small = [0.000, 0.000, 0.350, 0.650]
floral = [0.000, 0.200, 0.800, 0.000]


[fruit]
flower_duration = 10.0
max_relative_growth_rate = 0.167
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
36 changes: 36 additions & 0 deletions vmapplet/data/markov/fuji/terminal_fate.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# order matters: index = year_no - 1
[[terminal_fate]]
large = [0.500, 0.167, 0.000, 0.333]
medium = [0.000, 0.000, 0.000, 1.000]
small = [0.100, 0.100, 0.300, 0.500]
floral = [0.100, 0.300, 0.600, 0.000]

[[terminal_fate]]
large = [0.246, 0.185, 0.000, 0.569]
medium = [0.016, 0.238, 0.032, 0.714]
small = [0.066, 0.067, 0.317, 0.550]
floral = [0.317, 0.250, 0.433, 0.000]

[[terminal_fate]]
large = [0.351, 0.106, 0.010, 0.533]
medium = [0.123, 0.148, 0.063, 0.666]
small = [0.015, 0.094, 0.453, 0.438]
floral = [0.182, 0.249, 0.569, 0.000]

[[terminal_fate]]
large = [0.213, 0.082, 0.000, 0.705]
medium = [0.027, 0.046, 0.016, 0.911]
small = [0.000, 0.024, 0.205, 0.771]
floral = [0.003, 0.413, 0.584, 0.000]

[[terminal_fate]]
large = [0.100, 0.050, 0.000, 0.850]
medium = [0.000, 0.020, 0.130, 0.850]
small = [0.000, 0.000, 0.375, 0.625]
floral = [0.008, 0.325, 0.667, 0.000]

[[terminal_fate]]
large = [0.000, 0.100, 0.000, 0.900]
medium = [0.000, 0.050, 0.050, 0.900]
small = [0.000, 0.000, 0.350, 0.650]
floral = [0.000, 0.200, 0.800, 0.000]
51 changes: 8 additions & 43 deletions vmapplet/data/simulation.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ stride_number = 5
pruning = false
convergence_steps = 2

# relative to vmapplet/lpy
[input.lpy_files]
axiom = 'axiom.lpy'
parameters = 'parameters.lpy'
Expand All @@ -20,21 +21,22 @@ statistics = 'statistics.lpy'
structure = 'structure.lpy'
interpretation = 'interpretation.lpy'

# relative to vmapplet/data/markov
[input.markov_files]
terminal_fate = 'fuji/terminal_fate.toml'
models = 'fuji/models'

[output]
dates = [
{ day = 1, month = 6 },
{ day = 1, month = 11 },
]

# All of those attributes will be available in the MTGs
[output.attributes]
tree = [
'growth_units'
]
# FIX: mtg display error when GUs are exported
# growth_unit = [
# 'year',
# 'inflorescence'
# ]
metamer = [
'number',
'closest_apex',
Expand Down Expand Up @@ -100,47 +102,10 @@ terminal_expansion_rate = 2e-5
minimum_size = 0.00075
maximum_size = 0.003

[markov]
[shoot]
maximum_length = 70
minimum_length = 4

# order matters: index = year_no - 1
[[markov.terminal_fate]]
large = [0.500, 0.167, 0.000, 0.333]
medium = [0.000, 0.000, 0.000, 1.000]
small = [0.100, 0.100, 0.300, 0.500]
floral = [0.100, 0.300, 0.600, 0.000]

[[markov.terminal_fate]]
large = [0.246, 0.185, 0.000, 0.569]
medium = [0.016, 0.238, 0.032, 0.714]
small = [0.066, 0.067, 0.317, 0.550]
floral = [0.317, 0.250, 0.433, 0.000]

[[markov.terminal_fate]]
large = [0.351, 0.106, 0.010, 0.533]
medium = [0.123, 0.148, 0.063, 0.666]
small = [0.015, 0.094, 0.453, 0.438]
floral = [0.182, 0.249, 0.569, 0.000]

[[markov.terminal_fate]]
large = [0.213, 0.082, 0.000, 0.705]
medium = [0.027, 0.046, 0.016, 0.911]
small = [0.000, 0.024, 0.205, 0.771]
floral = [0.003, 0.413, 0.584, 0.000]

[[markov.terminal_fate]]
large = [0.100, 0.050, 0.000, 0.850]
medium = [0.000, 0.020, 0.130, 0.850]
small = [0.000, 0.000, 0.375, 0.625]
floral = [0.008, 0.325, 0.667, 0.000]

[[markov.terminal_fate]]
large = [0.000, 0.100, 0.000, 0.900]
medium = [0.000, 0.050, 0.050, 0.900]
small = [0.000, 0.000, 0.350, 0.650]
floral = [0.000, 0.200, 0.800, 0.000]

[fruit]
flower_duration = 10.0
max_relative_growth_rate = 0.167
Expand Down
2 changes: 1 addition & 1 deletion vmapplet/lpy/axiom.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module tree(): scale=0
axiom:
parameters = {
**options.apex,
**options.markov
**options.shoot
}
produce tree(tree_data) root() apex(ApexData(hlu=tree_data.initial_hlu, observation=Observation.TRUNK, **parameters))

Expand Down
2 changes: 1 addition & 1 deletion vmapplet/lpy/statistics.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ apex(a):
elif a.get_observation() == Observation.FLORAL:
a.set_observation(Observation.DORMANT)
else:
a.set_observation(terminal_fate(simulation.year_no, a.get_observation(), options.markov.terminal_fate))
a.set_observation(terminal_fate(simulation.year_no, a.get_observation(), options.input.terminal_fate))
a.radius = 0
a.max_terminal_radius_target()
tree_data.growth_units += 1
Expand Down
6 changes: 3 additions & 3 deletions vmapplet/lpy/structure.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ metamer(m) > metamer(mr) apex(a):
hlu = rotate_frame_at_branch(m.hlu, m.branching_angle, m.phyllotactic_angle);
apex_parameters = {
**options.apex,
**options.markov
**options.shoot
}
sylleptic_apex = ApexData(hlu, terminal_fate(simulation.year_no, Observation.FLORAL, options.markov.terminal_fate), **apex_parameters)
sylleptic_apex = ApexData(hlu, terminal_fate(simulation.year_no, Observation.FLORAL, options.input.terminal_fate), **apex_parameters)
sylleptic_apex.parent_observation = Observation.FLORAL
if m.parent_fbr_id == 0:
tree_data.first_branches += 1
Expand Down Expand Up @@ -138,7 +138,7 @@ metamer(m):
hlu = rotate_frame_at_branch(m.hlu, m.branching_angle, m.phyllotactic_angle)
apex_parameters = {
**options.apex,
**options.markov
**options.shoot
}
a = ApexData(hlu, m.observation, **apex_parameters)
if m.parent_fbr_id == 0:
Expand Down
46 changes: 29 additions & 17 deletions vmapplet/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dataclasses as dc
import pathlib
from datetime import date
import io

import toml

Expand Down Expand Up @@ -57,12 +58,37 @@ class OptionsOutput(OptionsBase):
attributes: Dict[str, List[str]] = dc.field(default_factory=lambda: dict())


markov_files = dict(terminal_fate="fuji/terminal_fate.toml", models="fuji/models")


@dc.dataclass
class OptionsInput(OptionsBase):
lpy_files: LsystemPaths = dc.field(default_factory=lambda: dict())
lpy_path: str = dc.field(
default_factory=lambda: str(pathlib.Path(__file__).parent.joinpath("lpy"))
)
markov_files: dict[str, str] = dc.field(default_factory=lambda: markov_files)
markov_path: str = dc.field(
default_factory=lambda: str(
pathlib.Path(__file__).parent.joinpath("data/markov")
)
)
terminal_fate: Dict[Any, Any] = dc.field(default_factory=lambda: dict())

def __post_init__(self):
# create the expected structure/types from toml input
# i.e. a list of dicts with observations as keys
terminal_fate = {}
if "terminal_fate" in self.markov_files:
path = pathlib.Path(self.markov_path) / self.markov_files["terminal_fate"]
with io.open(path) as file:
terminal_fate = toml.loads(file.read())["terminal_fate"]
for i, item in enumerate(terminal_fate):
for observation_str, probabilities in item.items():
# start with year_no = 1
self.terminal_fate[
(i + 1, Observation(observation_str.upper()))
] = probabilities


@dc.dataclass
Expand Down Expand Up @@ -126,23 +152,9 @@ class OptionsApex(OptionsBase):


@dc.dataclass
class OptionsMarkov(OptionsBase):
class OptionsShoot(OptionsBase):
maximum_length: int = 70 # < 100
minimum_length: int = 4
terminal_fate: Dict[Any, Any] = dc.field(default_factory=lambda: dict())

def __post_init__(self):
# create the expected structure/types from toml input
# i.e. a list of dicts with observations as keys
terminal_fate = {}
if self.terminal_fate is not None:
for i, item in enumerate(self.terminal_fate):
for observation_str, probabilities in item.items():
# start with year_no = 1
terminal_fate[
(i + 1, Observation(observation_str.upper()))
] = probabilities
self.terminal_fate = terminal_fate


@dc.dataclass
Expand Down Expand Up @@ -176,7 +188,7 @@ class Options(OptionsBase):
wood: OptionsWood = dc.field(default_factory=lambda: OptionsWood())
internode: OptionsInternode = dc.field(default_factory=lambda: OptionsInternode())
apex: OptionsApex = dc.field(default_factory=lambda: OptionsApex())
markov: OptionsMarkov = dc.field(default_factory=lambda: OptionsMarkov())
shoot: OptionsShoot = dc.field(default_factory=lambda: OptionsShoot())
fruit: OptionsFruit = dc.field(default_factory=lambda: OptionsFruit())
leaf: OptionsLeaf = dc.field(default_factory=lambda: OptionsLeaf())

Expand All @@ -189,7 +201,7 @@ def __post_init__(self):
self.wood = _make_dataclass(OptionsWood, self.wood)
self.internode = _make_dataclass(OptionsInternode, self.internode)
self.apex = _make_dataclass(OptionsApex, self.apex)
self.markov = _make_dataclass(OptionsMarkov, self.markov)
self.shoot = _make_dataclass(OptionsShoot, self.shoot)
self.fruit = _make_dataclass(OptionsFruit, self.fruit)
self.leaf = _make_dataclass(OptionsLeaf, self.leaf)

Expand Down
1 change: 0 additions & 1 deletion vmapplet/organs/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class Tree:
inflorescence_death_probability: float = 0.2

def __post_init__(self):

self.angle_unit = "radians"
self.phyllotactic_angle = self.phyllotactic_angle / 180.0 * pi
self.branching_angle = self.branching_angle / 180.0 * pi
Expand Down
12 changes: 8 additions & 4 deletions vmapplet/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,17 @@ def __init__(self, options: Union[str, Options], output_path: Optional[str] = No

self._markov = Markov(
generator=self._rng,
minimum_length=self.options.markov.minimum_length,
maximum_length=self.options.markov.maximum_length,
minimum_length=self.options.shoot.minimum_length,
maximum_length=self.options.shoot.maximum_length,
)

self._markov_models = {}
for path in os.listdir(get_shared_data_path("markov")):
path = pathlib.Path(get_shared_data_path("markov")) / path
markov_models_dir = (
pathlib.Path(get_shared_data_path("markov"))
/ self.options.input.markov_files["models"]
)
for path in os.listdir(markov_models_dir):
path = markov_models_dir / path
if path.is_file() and path.suffix == ".toml":
with io.open(path) as file:
model = MarkovModel(**toml.loads(file.read()))
Expand Down

0 comments on commit 0fa5eb1

Please sign in to comment.