Tech Meeting 2024 Q1 - Run with(out) ini files#

The technical meeting that took place on 2024.04.03 related to the Q1 sprints covered the following topics:

  1. Running an analysis whilst modifying the .ini configuration files.

  2. Usage of enumerations within ra2ce.

  3. Discussion on long term views for ra2ce subprojects.

  4. Walk-through, on how to add new analyses to the current solution.

This jupyter notebook will covers the first point.

1. Running an analysis whilst modifying the .ini configuration files#

It is entirely possible to generate a ra2ce analysis (or just a network) without having to generate .ini files. However, most of the times we will only want to modify a few properties of a given network.ini or analysis.ini file. At the current version v0.8.1 we can solve both options as follows:

  1. Load the .ini files and then modify them at our own choice.

  2. Fully creating a Ra2ceHandler instance based on python objects ( NetworkConfigData and AnalysisConfigData).

1.1. Modify existing configurations from code#

Given our most common use case, we want to load a network and analysis and potentially modifying some of its properties. This was already accomplished in the “ra2ce hackathon 2024 Q1”.

To achieve it, simply use the regular Ra2ceHandler with your desired ini files and then access the corresponding NetworkConfigData and AnalysisConfigData properties. See the example below.

  1. Initialize the Ra2ce handler with valid .ini files.

[ ]:
from pathlib import Path

from ra2ce.ra2ce_handler import Ra2ceHandler

# Define the location of our example test data.
_root_dir = Path("...", "data", "damages_analysis")
assert _root_dir.exists()

_network_file = _root_dir.joinpath("network.ini")
assert _network_file.exists()

_analysis_file = _root_dir.joinpath("analysis.ini")
assert _analysis_file.exists()

# Initialize handler
_handler = Ra2ceHandler(_network_file, _analysis_file)
  1. In addition, we can verify if the analysis and network are correctly set.

[ ]:
from ra2ce.network.network_config_data.network_config_data import NetworkConfigData
from ra2ce.analysis.analysis_config_data.analysis_config_data import AnalysisConfigData

assert isinstance(_handler.input_config.network_config.config_data, NetworkConfigData)
assert isinstance(_handler.input_config.analysis_config.config_data, AnalysisConfigData)
  1. Configure the network and analyses

[ ]:
_handler.configure()
  1. Run the analysis.

[ ]:
_handler.run_analysis()

1.2. Create Ra2ce Handler without ini files#

DISCLAIMER! This functionality will be streamlined as resolution of issue #389

This step, however longer than required, will demonstrate how to emulate the usage of ini files. We relate the .ini files as:

  • network.ini to NetworkConfigData,

  • analysis.ini to AnalysisConfigData.

Both ConfigData items are python objects (dataclasses) as such, it is entirely possible to manually manipulate them via code, therefore avoiding the need of definition and usage of their related ini files.

  1. Initialize the objects representing the .ini files.

[ ]:
from ra2ce.network.network_config_data.network_config_data import NetworkConfigData
from ra2ce.analysis.analysis_config_data.analysis_config_data import AnalysisConfigData

_network_config_data = NetworkConfigData()
_analysis_config_data = AnalysisConfigData()
  1. (Optional) Initialize logger.

[ ]:
from ra2ce.ra2ce_logging import Ra2ceLogger

# Initialize logger.
_output_logger_path = Path("..", "data", "logging")
if _output_logger_path.exists():
    import shutil
    shutil.rmtree(_output_logger_path)
_output_logger_path.mkdir(parents=True)

Ra2ceLogger(logging_dir=_output_logger_path, logger_name="RA2CE")
  1. Put said objects together in the config wrapper.

[ ]:
# Define network config wrapper
from ra2ce.network.network_config_wrapper import NetworkConfigWrapper

_network_config_wrapper = NetworkConfigWrapper()
_network_config_wrapper.config_data = _network_config_data
_network_config_wrapper.configure()

# Define analysis config wrapper
from ra2ce.analysis.analysis_config_wrapper import AnalysisConfigWrapper

_analysis_config_wrapper = AnalysisConfigWrapper()
_analysis_config_wrapper.config_data = _analysis_config_data
_analysis_config_wrapper.config_data.network = _network_config_wrapper.config_data.network
_analysis_config_wrapper.config_data.origins_destinations = (
    _network_config_wrapper.config_data.origins_destinations
)
_analysis_config_wrapper.graph_files = _network_config_wrapper.graph_files
_analysis_config_wrapper.configure()

# Initialize wrapper
from ra2ce.configuration.config_wrapper import ConfigWrapper

_config_wrapper = ConfigWrapper()
_config_wrapper.analysis_config = _analysis_config_wrapper
_config_wrapper.network_config = _network_config_wrapper

_config_wrapper.configure()
  1. Run analysis

[ ]:
# Run analysis
from ra2ce.runners import AnalysisRunnerFactory

_runner = AnalysisRunnerFactory.get_runner(_config_wrapper)
_runner.run(_config_wrapper.analysis_config)

1.3. Create Ra2ce Handler without ini files - after #389#

In this example the network and analysis configuration are read from file before creation of the Ra2ceHandler. This can be replaced by any other way of creating your configuration, e.g. by creating it from scratch by NetworkConfigWData() and AnalysisConfigData(). The handler doesn’t need file at creation time. The analysis should yield the same results as example_damages.ipynb. Note that the logfile isn’t created.

[ ]:
from pathlib import Path

from ra2ce.analysis.analysis_config_data.analysis_config_data_reader import AnalysisConfigDataReader
from ra2ce.network.network_config_data.network_config_data_reader import NetworkConfigDataReader
from ra2ce.ra2ce_handler import Ra2ceHandler
from ra2ce.runners import AnalysisRunnerFactory

# Initialize configuration (replace this with your own configuration)
_data_dir = Path("..", "data", "damages_analysis")
_network_ini = _data_dir.joinpath("network.ini")
_network = NetworkConfigDataReader().read(_network_ini)
_network.root_path = _data_dir.parent
_network.input_path = _data_dir.joinpath("input")
_network.static_path = _data_dir.joinpath("static")
_network.output_path = _data_dir.joinpath("output")
_analysis_ini = _data_dir.joinpath("analysis.ini")
_analysis = AnalysisConfigDataReader().read(_analysis_ini)

# Initialize handler from configuration
_handler = Ra2ceHandler.from_config(_network, _analysis)

# Configure handler
_handler.configure()

# Run analysis
_runner = AnalysisRunnerFactory.get_runner(_handler.input_config)
_runner.run(_handler.input_config.analysis_config)

1.4. Run an analysis with one line of code!#

From issue #460 it is possible to simply run an anlysis without having to do the two extra steps .configure() and .run_analysis().

We can now chose to: - 1. Run directly an analysis providing two files with (Ra2ceHandler.run_with_ini_files(Path, Path)). - 2. Run an analysis by providing two configuration files (Ra2ceHandler.run_with_config_data(NetworkConfigData, AnalysisConfigData)).

1.4.1. Run an analysis providing two files.#

[ ]:
from pathlib import Path

from ra2ce.ra2ce_handler import Ra2ceHandler, AnalysisResultWrapper
from ra2ce.analysis.analysis_config_data.analysis_config_data_reader import AnalysisConfigDataReader
from ra2ce.network.network_config_data.network_config_data_reader import NetworkConfigDataReader

# Initialize configuration (replace this with your own configuration)
_data_dir = Path("..", "data", "single_link_redun")

# Network file
_network_ini = _data_dir.joinpath("network.ini")
assert _network_ini.exists()

# Analysis file
_analysis_ini = _data_dir.joinpath("analyses.ini")
assert _analysis_ini.exists()

# Get directly the results without extra steps.
_results = Ra2ceHandler.run_with_ini_files(_network_ini, _analysis_ini)

assert any(_results)
assert all(isinstance(_result_wrapper, AnalysisResultWrapper) for _result_wrapper in _results)

1.4.2. Run an anlysis providing NetworkConfigData and AnalysisConfigData#

[ ]:
from pathlib import Path

from ra2ce.ra2ce_handler import Ra2ceHandler, AnalysisResultWrapper
from ra2ce.analysis.analysis_config_data.analysis_config_data_reader import AnalysisConfigDataReader, AnalysisConfigData
from ra2ce.network.network_config_data.network_config_data_reader import NetworkConfigDataReader, NetworkConfigData

# Initialize configuration (replace this with your own configuration)
_data_dir = Path("..", "data", "single_link_redun")

# NOTE! For simplicity we just load "valid" ini files instead of generating our own
# config data.

# Network file
_network_config_data = NetworkConfigDataReader().read(_data_dir.joinpath("network.ini"))
assert isinstance(_network_config_data, NetworkConfigData)

# Analysis file
_analysis_config_data = AnalysisConfigDataReader().read(_data_dir.joinpath("analyses.ini"))
assert isinstance(_analysis_config_data, AnalysisConfigData)

# Get directly the results without extra steps.
_results = Ra2ceHandler.run_with_config_data(_network_config_data, _analysis_config_data)

assert any(_results)
assert all(isinstance(_result_wrapper, AnalysisResultWrapper) for _result_wrapper in _results)