Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Defining the CoreComponents, LayerStructure and ModelTiming classes #374

Merged
merged 40 commits into from
Feb 5, 2024
Merged
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
685e42b
Draft implementation of CoreComponents
davidorme Jan 24, 2024
f5f6a20
Doc fixes
davidorme Jan 24, 2024
4a70211
Forgot to add new tests file
davidorme Jan 24, 2024
01fc628
Extending and fixing tests
davidorme Jan 24, 2024
9513801
Updating callable signatures to use CoreComponents - not unpacked yet.
davidorme Jan 25, 2024
45ac49a
Updating main to use CoreComponents
davidorme Jan 25, 2024
9a76bba
Unpacking core components into new BaseModel attributes
davidorme Jan 25, 2024
548c849
Revising docstrings
davidorme Jan 25, 2024
adaf95b
MoarRevising docstrings
davidorme Jan 25, 2024
b96e68e
Updating Plants Model
davidorme Jan 25, 2024
be73d57
Updating soils model
davidorme Jan 25, 2024
9f2c892
Updating litter model
davidorme Jan 25, 2024
42d8bbc
Updated hydrology_model
davidorme Jan 25, 2024
53153fd
Updated abiotic_simple_model
davidorme Jan 25, 2024
a5cd8bd
Added n_layers to LayerStructure
davidorme Jan 25, 2024
4359c6e
Use n_layers in models
davidorme Jan 25, 2024
03b5a81
Updated animal model
davidorme Jan 25, 2024
e17e368
Converted layer_roles from tuple to list - incompatible with xarray c…
davidorme Jan 25, 2024
f862264
AnimalModel loads wrong constants
davidorme Jan 25, 2024
b02d14a
Added Config and CoreComponents fixtures, updated fixtures using prev…
davidorme Jan 25, 2024
242fe2f
Removing test for deprecated extract_timing_details
davidorme Jan 25, 2024
e3c33a7
Updating plants tests to new BaseModel structure
davidorme Jan 25, 2024
086e53f
Potential solution to BaseModel._repr issue
davidorme Jan 25, 2024
a705be0
Updating soil tests
davidorme Jan 25, 2024
5d55541
Update litter model tests
davidorme Jan 25, 2024
388fc9f
Updating hydrology model tests
davidorme Jan 26, 2024
86c4c93
Updated abiotic_simple model tests
davidorme Jan 26, 2024
cb048e8
Restored BaseModel._check_update_speed functionality
davidorme Jan 26, 2024
e3181e9
Fixing core tests, log message tweaks
davidorme Jan 26, 2024
663d3c4
Deprecated input file location in tests
davidorme Jan 26, 2024
ce3396b
Updating animal model tests
davidorme Jan 26, 2024
127423e
Last test fixes
davidorme Jan 26, 2024
b1c9339
Cleaner start_time setting
davidorme Jan 26, 2024
53d820f
add _validate_canopy_layer function
davidorme Jan 26, 2024
849e651
add _validate_soil_layers function
davidorme Jan 26, 2024
162daa4
Updating core_component.py validators and adding unit tests for valid…
davidorme Jan 26, 2024
20fe796
Merge pull request #375 from ImperialCollegeLondon/369-adopting-new-core
davidorme Feb 2, 2024
42bd787
Indenting issue in RST
davidorme Feb 2, 2024
7443127
Fixing docstring issues
davidorme Feb 5, 2024
b4fb178
Merge branch 'develop' into 369-simplifying-the-model-creation-setup
davidorme Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Updating main to use CoreComponents
  • Loading branch information
davidorme committed Jan 25, 2024
commit 45ac49a03eb9098b14ae9b42fb7328dcab87808c
103 changes: 9 additions & 94 deletions virtual_rainforest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
from collections.abc import Sequence
from graphlib import CycleError, TopologicalSorter
from itertools import chain
from math import ceil
from pathlib import Path
from typing import Any

import pint
from numpy import datetime64, timedelta64

from virtual_rainforest.core.config import Config
from virtual_rainforest.core.core_components import CoreComponents
from virtual_rainforest.core.data import Data, merge_continuous_data_files
from virtual_rainforest.core.exceptions import ConfigurationError, InitialisationError
from virtual_rainforest.core.grid import Grid
Expand All @@ -24,16 +21,16 @@
def initialise_models(
config: Config,
data: Data,
core_components: CoreComponents,
models: dict[str, Any], # FIXME -> dict[str, Type[BaseModel]]
update_interval: pint.Quantity,
) -> dict[str, Any]: # FIXME -> dict[str, Type[BaseModel]]
"""Initialise a set of models for use in a `virtual_rainforest` simulation.

Args:
config: A validated Virtual Rainforest model configuration object.
data: A Data instance.
core_components: A CoreComponents instance.
modules: A dictionary of models to be configured.
update_interval: The interval with which each model is updated

Raises:
InitialisationError: If one or more models cannot be properly configured
Expand All @@ -46,7 +43,7 @@ def initialise_models(
models_cfd = {}
for model_name, model_class in models.items():
try:
this_model = model_class.from_config(data, config, update_interval)
this_model = model_class.from_config(data, core_components, config)
models_cfd[model_name] = this_model
except (InitialisationError, ConfigurationError):
failed_models.append(model_name)
Expand All @@ -62,82 +59,6 @@ def initialise_models(
return models_cfd


def extract_timing_details(
config: Config,
) -> tuple[datetime64, timedelta64, pint.Quantity, datetime64]:
"""Extract timing details for main loop from the model configuration.

The start time, run length and update interval are all extracted from the
configuration. Sanity checks are carried out on these extracted values. The end time
is then generated from the previously extracted timing information. This end time
will always be a multiple of the update interval, with the convention that the
simulation should always run for at least as long as the user specified run
length.

Args:
config: A validated Virtual Rainforest model configuration object.

Raises:
InitialisationError: If the run length is too short for the model to update, or
the units of update interval or run length aren't valid.
"""

# First extract start and end times
start_time = datetime64(config["core"]["timing"]["start_date"])

# Catch bad time dimensions
try:
raw_length = pint.Quantity(config["core"]["timing"]["run_length"]).to("seconds")
except (pint.errors.DimensionalityError, pint.errors.UndefinedUnitError):
to_raise = InitialisationError(
"Units for core.timing.run_length are not valid time units: %s"
% config["core"]["timing"]["run_length"]
)
LOGGER.critical(to_raise)
raise to_raise
else:
# Round raw time interval to nearest second
run_length = timedelta64(round(raw_length.magnitude), "s")

# Catch bad time dimensions
try:
# This averages across months and years (i.e. 1 month => 30.4375 days)
raw_interval = pint.Quantity(config["core"]["timing"]["update_interval"]).to(
"seconds"
)
except (pint.errors.DimensionalityError, pint.errors.UndefinedUnitError):
to_raise = InitialisationError(
"Units for core.timing.update_interval are not valid time units: %s"
% config["core"]["timing"]["update_interval"]
)
LOGGER.critical(to_raise)
raise to_raise
else:
# Round raw time interval to nearest second
update_interval = timedelta64(round(raw_interval.magnitude), "s")

if run_length < update_interval:
to_raise = InitialisationError(
f"Models will never update as the update interval ({update_interval}) is "
f"larger than the run length ({run_length})"
)
LOGGER.critical(to_raise)
raise to_raise

# Calculate when the simulation should stop based on principle that it should run at
# least as long as the user requests rather than shorter
end_time = start_time + ceil(run_length / update_interval) * update_interval

# Then inform the user how long it will run for
LOGGER.info(
"Virtual Rainforest simulation will run from %s until %s. This is a run length "
"of %s, the user requested %s"
% (start_time, end_time, end_time - start_time, run_length)
)

return start_time, update_interval, raw_interval, end_time


def _get_model_sequence(
config: Config, models: dict[str, Any], method: str
) -> dict[str, Any]: # FIXME dict[str, Any]-> dict[str, Type[BaseModel]]
Expand Down Expand Up @@ -251,28 +172,21 @@ def vr_run(

# Build core elements
grid = Grid.from_config(config)
core_components = CoreComponents(config=config)
data = Data(grid)
data.load_data_config(config)

LOGGER.info("All models found in the registry, now attempting to configure them.")

# Extract all the relevant timing details
(
current_time,
update_interval,
update_interval_as_quantity,
end_time,
) = extract_timing_details(config)

# Get the model initialisation sequence and initialise
init_sequence = _get_model_sequence(
config=config, models=config.model_classes, method="init"
)
models_init = initialise_models(
config=config,
data=data,
core_components=core_components,
models=init_sequence,
update_interval=update_interval_as_quantity,
)

LOGGER.info("All models successfully intialised.")
Expand Down Expand Up @@ -315,10 +229,11 @@ def vr_run(

# Setup the timing loop
time_index = 0
while current_time < end_time:
current_time = core_components.model_timing.start_time
while current_time < core_components.model_timing.end_time:
LOGGER.info(f"Starting update {time_index}: {current_time}")

current_time += update_interval
current_time += core_components.model_timing.update_interval

# Run update() method for every model
for model in models_update.values():
Expand Down