Coder Social home page Coder Social logo

nismod / smif Goto Github PK

View Code? Open in Web Editor NEW
22.0 9.0 6.0 11.31 MB

Simulation Modelling Integration Framework

Home Page: http://www.itrc.org.uk

License: MIT License

Python 73.04% JavaScript 26.69% HTML 0.03% CSS 0.25%
model coupling simulation optimization infrastructure

smif's Introduction

smif

Simulation Modelling Integration Framework

GitHub Actions build status PyPI package conda-forge package Archive Journal of Open Research Software paper Documentation Status

smif is a framework for handling the creation, management and running of system-of-systems models.

A system-of-systems model is a collection of system simulation models that are coupled through dependencies on data produced by each other.

smif provides a user with the ability to

  • create system-of-systems models
    • add simulation models to a system-of-systems model
    • create dependencies between models by linking model inputs and outputs
    • pick from a library of data adapters which perform common data conversions across dependencies
    • create user-defined data adapters for more special cases
    • add scenario data sources and link those to model inputs within a system-of-systems
  • add a simulation model to a library of models
    • write a simulation model wrapper which allows smif to run the model
    • define multi-dimensional model inputs, outputs and parameters and appropriate metadata
  • run system-of-systems models
    • link concrete scenario data sets to a system-of-systems model
    • define one or more decision modules that operate across the system-of-systems
    • define a narrative to parameterise the contained models
    • persist intermediate data for each model output, and write results to a data store for subsequent analysis

In summary, the framework facilitates the hard coupling of complex systems models into a system-of-systems.

Should I use smif?

There are number of practical limits imposed by the implementation of smif. These are a result of a conscious design decision that stems from the requirements of coupling the infrastructure system models to create the next generation National Infrastructure System Model (NISMOD2).

The discussion below may help you determine whether smif is an appropriate tool for you.

  • smif is not a scheduler, but has been designed to make performing system-of-systems analyses with a scheduler easier
  • Geographical extent is expected to be defined explicitly by a vector geometry
    • smif is not optimised for models which simulate on a grid, though they can be accomodated
    • smif is designed for models that read and write spatial data defined over irregular grids or polygons using any spatial format readable by fiona
  • Inputs and outputs are exchanged at the ‘planning timestep’ resolution
    • smif makes a distinction between simulation of operation, which happens at a model-defined timestep resolution, and application of planning decisions which happens at a timestep which is synchronised between all models
    • smif is not focussed on tight coupling between models which need to exchange data at every simulation timestep (running in lockstep)
    • smif does accomodate individual models with different spatial and temporal (and other dimensional) resolutions, by providing data adaptors to convert from one resolution to another
  • smif has been designed to support the coupling of bottom-up, engineering simulation models built to simulate the operation of a given infrastructure system
    • smif provides a mechanism for passing information from the system-of-systems level (at planning timesteps scale) to the contained models
    • smif is appropriate for coupling large complex models that exchange resources and information at relatively course timesteps
  • smif is not appropriate for
    • discrete event system simulation models (e.g. queuing systems)
    • dynamical system models (e.g. predator/prey)
    • equilibrium models without explicit timesteps (e.g. Land-Use Transport Interaction)
    • for simulating 100s of small actor-scale entities within a system-level environment

Installation and Configuration

smif is written in Python (Python>=3.5) and has a number of dependencies. See requirements.txt for a full list.

Using conda

The recommended installation method is to use conda, which handles packages and virtual environments, along with the conda-forge channel which has a host of pre-built libraries and packages.

Create a conda environment:

conda create --name smif_env python=3.6

Activate it (run each time you switch projects):

conda activate smif_env

Add the conda-forge channel, which has smif available:

conda config --add channels conda-forge

Finally install smif:

conda install smif

Installing smif with other methods

Once the dependencies are installed on your system, a normal installation of smif can be achieved using pip on the command line:

pip install smif

Versions under development can be installed from github using pip too:

pip install git+http://github.com/nismod/smif

To install from the source code in development mode:

git clone http://github.com/nismod/smif
cd smif
python setup.py develop

Spatial libraries

smif optionally depends on fiona and shapely, which depend on the GDAL and GEOS libraries. These add support for reading and writing common spatial file formats and for spatial data conversions.

If not using conda, on Mac or Linux these can be installed with your OS package manager:

# On debian/Ubuntu:
apt-get install gdal-bin libspatialindex-dev libgeos-dev

# or on Mac
brew install gdal
brew install spatialindex
brew install geos

Then to install the python packages, run:

pip install smif[spatial]

Running smif from the command line

Follow the getting started guide to help set up the necessary configuration.

To set up an sample project in the current directory, run:

$ smif setup

To list available model runs:

$ smif list
demo_model_run
...

To start the smif app, a user-interface that helps to display, create and edit a configuration, run:

$ smif app

To run a system-of-systems model run:

$ smif run demo_model_run
...
Model run complete

By default, results will be stored in a results directory, grouped by model run and simulation model.

To see all options and flags:

$ smif --help
usage: smif [-h] [-V] {setup,list,run} ...

Command line tools for smif

positional arguments:
{setup,list,app,run}  available commands
    setup               Setup the project folder
    list                List available model runs
    app                 Open smif app
    run                 Run a model

optional arguments:
-h, --help        show this help message and exit
-V, --version     show the current version of smif

Citation

If you use smif for research, please cite the software directly:

  • Will Usher, Tom Russell, Roald Schoenmakers, Craig Robson, Fergus Cooper, Thibault Lestang & Rose Dickinson. (2019). nismod/smif vX.Y.Z (Version vX.Y.Z). Zenodo. http://doi.org/10.5281/zenodo.1309336

Here's an example BibTeX entry:

@misc{smif_software,
      author       = {Will Usher and Tom Russell and Roald Schoenmakers and Craig Robson and Fergus Cooper and Thibault Lestang and Rose Dickinson},
      title        = {nismod/smif vX.Y.Z},
      month        = Aug,
      year         = 2018,
      doi          = {10.5281/zenodo.1309336},
      url          = {https://doi.org/10.5281/zenodo.1309336}
}

Please also cite the software description paper:

  • Will Usher and Tom Russell. (2019) A Software Framework for the Integration of Infrastructure Simulation Models. Journal of Open Research Software, 7: 16 DOI: https://doi.org/10.5334/jors.265

Here's an example BibTeX entry:

@misc{smif_paper,
      author       = {Will Usher and Tom Russell},
      title        = {A Software Framework for the Integration of Infrastructure Simulation Models},
      journal      = {Journal of Open Research Software},
      volume       = {7},
      number       = {16},
      pages        = {1--5},
      month        = May,
      year         = {2019},
      doi          = {10.5334/jors.265},
      url          = {https://doi.org/10.5334/jors.265}
}

A word from our sponsors

smif was written and developed at the Environmental Change Institute, University of Oxford within the EPSRC sponsored MISTRAL programme, as part of the Infrastructure Transition Research Consortium.

smif's People

Contributors

craig-robson avatar dependabot[bot] avatar fcooper8472 avatar roaldl avatar rosedickinson avatar tlestang avatar tomalrussell avatar willu47 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

smif's Issues

'DataHandle' object has no attribute 'read_coefficients'

Adaptors expect data_handle to have method read_coefficients. The store has read and write methods for coefficients, but this isn't exposed at the data_handle level.

Traceback (most recent call last):
  File "/vagrant/smif/src/smif/controller/scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id)
  File "/vagrant/smif/src/smif/controller/scheduler.py", line 249, in _run
    model.simulate(data_handle)
  File "/vagrant/smif/src/smif/convert/adaptor.py", line 27, in simulate
    coefficients = self.get_coefficients(data, from_spec, to_spec)
  File "/vagrant/smif/src/smif/convert/adaptor.py", line 46, in get_coefficients
    coefficients = data_handle.read_coefficients(from_spec, to_spec)
AttributeError: 'DataHandle' object has no attribute 'read_coefficients'

Incomprehensible error when reading a scenario file which doesn't match dimensions

When using the following dimension configuration:

name: population
description: UK population, total people
provides:
  - name: population
    description: ''
    dims:
      - lad_uk_2016
    dtype: float
    unit: people
variants:
  - name: pop_baseline
    description: Baseline population for the UK
    data:
      population: population__lad.csv
  - name: pop_high
    description: High population for the UK
    data:
      population: tbd

where population__lad.csv contains the incorrect header such as timestep, region, value instead of timestep, lad_uk_2016, value the following error is raised:

Traceback (most recent call last):
  File "/home/vagrant/nismod/lib/python3.5/site-packages/pandas/core/indexes/base.py", line 2656, in get_loc
    return self._engine.get_loc(key)
  File "pandas/_libs/index.pyx", line 108, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 132, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1601, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1608, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'lad_uk_2016'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 246, in _run
    model.before_model_run(data_handle)
  File "models/energy_demand/run.py", line 282, in before_model_run
    pop_array_by = data_handle.get_base_timestep_data('population')
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 430, in get_base_timestep_data
    return self.get_data(input_name, RelativeTimestep.BASE)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 298, in get_data
    data = self._get_scenario(dep, timestep)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 372, in _get_scenario
    timestep
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/store.py", line 502, in read_scenario_variant_data
    return self.data_store.read_scenario_variant_data(key, spec, timestep)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/file/file_data_store.py", line 85, in read_scenario_variant_data
    data = self._read_data_array(path, spec, timestep)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/file/file_data_store.py", line 387, in _read_data_array
    dataframe.set_index(spec.dims, inplace=True)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/pandas/core/frame.py", line 4178, in set_index
    level = frame[col]._values
  File "/home/vagrant/nismod/lib/python3.5/site-packages/pandas/core/frame.py", line 2927, in __getitem__
    indexer = self.columns.get_loc(key)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/pandas/core/indexes/base.py", line 2658, in get_loc
    return self._engine.get_loc(self._maybe_cast_indexer(key))
  File "pandas/_libs/index.pyx", line 108, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 132, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1601, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1608, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'lad_uk_2016'

cli verbose usage hides tracebacks

smif -vv run digital_comms_test is not equal to smif run -vv digital_comms_test

In the former, tracebacks are always hidden, in the latter, then the traceback functionality works as intended.

Built in adaptors call ndim on DataArray

This causes the following error:

AttributeError: 'DataArray' object has no attribute 'ndim'

Reported by @LahiruJayasuriya

The problem is caused by Adaptor.simulate passing a DataArray to Adaptor.convert where convert is expecting an ndarray.

Need to fix the tests, which currently pass in numpy ndarray rather than smif DataArray objects.

smif DataArray name doesn't always match input name

E.g. in the transport_full_test model in nismod2, in the transport wrapper, with input gva:

current_da = data_handle.get_data("gva")
# current_da.name == 'gva_per_head'

The name matches the source_output name as specified in the dependency, should match the sink_input.

Refactor module run scheduling to be almost-plugin based

Module run scheduling is currently done inside scheduler.py and it is slightly awkward for users to add a new way of scheduling model runs. To make this process slightly easier the scheduling will be refactored into an almost-plugin architecture. The schedulers will be stored in the codebase and a command line argument will be provided to allow switching between scheduling implementations.

  • Refactor JobScheduler out of scheduler.py
  • Add command line argument switching of schedulers
  • Add DAFNI scheduler

Add section on raising errors from failing model runs

Add guidance to nismod.github.io and follow up in each of the models:

If the e.g. transport and energy models fail, then errors are not caught in the runtime
environment and the programme exits silently. Errors should be raised, with messages passed to
stderr so that our subprocess recognises that the programme has exited abnormally.

We need to decide on what to do in the following cases:

  • model is infeasible - it hasn't been possible to solve the problem
  • data is missing so the model cannot run
  • inputs are out of range or invalid (e.g. negative efficiency or cost)

Bug: AttributeError when running smif

File "C:\Miniconda2\envs\envNISMOD36\Scripts\smif-script.py", line 11, in <module> load_entry_point('smif==0.5.0.post0.dev43+ngdca12b0', 'console_scripts', 'smif')() File "C:\Miniconda2\envs\envNISMOD36\lib\site-packages\smif\cli\__init__.py", line 486, in main args.func(args) File "C:\Miniconda2\envs\envNISMOD36\lib\site-packages\smif\cli\__init__.py", line 366, in execute_model_run modelrun.run() File "C:\Miniconda2\envs\envNISMOD36\lib\site-packages\smif\modelrun.py", line 111, in run modelrunner.solve_model(self) File "C:\Miniconda2\envs\envNISMOD36\lib\site-packages\smif\modelrun.py", line 145, in solve_model data) File "C:\Miniconda2\envs\envNISMOD36\lib\site-packages\smif\model\sos_model.py", line 150, in simulate for model_name, model_results in sim_results.items(): AttributeError: 'EnergyModel' object has no attribute 'items'

Add command line argument for smif app port

It would be useful to override the default port for the smif app.

Suggest adding a command line argument --port - should be a quick addition to the existing argument parser.

smif app --port 1234

Improve reporting when model subprocess fails

Example run:

$ smif run energy_supply_minimal
smif\data_layer\file\file_metadata_store.py:135: FionaDeprecationWarning: Use fiona.Env() instead.
  with fiona.drivers():
pandas\core\frame.py:3697: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  errors=errors)
Traceback (most recent call last):
  File "smif\controller\scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id)
  File "smif\controller\scheduler.py", line 249, in _run
    model.simulate(data_handle)
  File "models\energy_supply\energy_supply.py", line 31, in simulate
    self.run_the_model()
  File "models\energy_supply\energy_supply.py", line 209, in run_the_model
    self.logger.debug(check_output([model_path]))
  File "lib\subprocess.py", line 336, in check_output
    **kwargs).stdout
  File "lib\subprocess.py", line 418, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['models\\energy_supply\\..\\..\\install\\energy_supply\\Energy_Supply_Master.exe']' returned non-zero exit status 3221225595.
CalledProcessError: Command '['models\\energy_supply\\..\\..\\install\\energy_supply\\Energy_Supply_Master.exe']' returned non-zero exit status 3221225595.
  • should be clearer that this is a model-running failure
  • could avoid or suppress warnings (these add noise, make things less clear)
  • could add a message to suggest running with -vv for debugging output
  • could do more to capture/report stderr/out from subprocess if possible and helpful

decisions: decision module should have access to parameters

Update - PR #339 implements a results_handle.get_state() method.

Call to get_parameter() is still outstanding.

  • A call to results_handle.get_data() should enable access to scenario data from a decision module.

Blocks nismod/nismod2#53 as digital comms decision module requires access to adoption scenario data, based on strategy chosen.

Above no longer correct as get_results can be used to obtain information from output of model, but it would be very useful if the decision module has access to parameters though a result_handle.get_parameter() method

See also #333

smif app fails to render some pages some of the time

With nismod/nismod2 config, flushes out some fragile assumptions:

  • sos_model scenarios should be lists (not objects)
  • scenario description should be empty string - this might be coming back as a list

Probabe fixes for these with:
a) stronger guarantees that the API returns well-formed data structures
b) stronger error boundaries on the client (at least avoid total white-screen failure)

Refactor module run scheduling to be almost-plugin based

Module run scheduling is currently done inside scheduler.py and it is slightly awkward for users to add a new way of scheduling model runs. To make this process slightly easier the scheduling will be refactored into an almost-plugin architecture. The schedulers will be stored in the codebase and a command line argument will be provided to allow switching between scheduling implementations.

  • Refactor JobScheduler out of scheduler.py
  • Add command line argument switching of schedulers
  • Add DAFNI scheduler

DecisionModule does not accumulate state

We are dealing with system state in an inconsistent manner, which means that while pre-specified planning decisions are included in every year of the state file, outputs from previous years of a decision module are not rewritten to a state file.

Solutions:

TLDR; either write separately and read in a bundle, or read separately and write in a bundle;

  1. only write pre-specified planning in base timestep state file and accumulate state through successive years for each decision iteration/timestep path followed, rewriting only the current decisions in each state file, reading them all in through the data_handle.get_state method
  2. the statefile in each timestep holds the complete history, so only the most recent statefile is needed to see a history of all the interventions that took place in a particular timestep/iteration path.

Fail to read input data when source/sink names don't match

Manifests as a data reading error (thanks @LahiruJayasuriya for the pointers):

FileNotFoundError: 
Fileb'.\\results\\energy_supply_demand\\energy_demand_constrained\\decision_0\\output_service_gas_district_heating_gas_timestep_2050.csv' does not exist

However, there is output_service_gas_district_heating_CHP_gas_timestep_2050.csv in ./results/energy_demand_constrained/decision_0

The dependency in this case has a mismatch in the names:

- sink: convert_regions_ed_to_es
  source: energy_demand_constrained
  sink_input: service_gas_district_heating_gas
  source_output: service_gas_district_heating_CHP_gas

in sos_models/energy_supply_demand_update.yml

May be related to #316 (both to do with Spec/DataArray names)

smif app throws TemplateNotFound when run from fresh source checkout

The fix is documented - it's missing the template because we need to npm i; npm run build - but this exception should be caught and a clearer message shown.

Details:

ERROR    Exception on / [GET]
Traceback (most recent call last):
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\_compat.py", line 35, in reraise
    raise value
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "\projects\mistral\smif\src\smif\http_api\register.py", line 19, in home
    return render_template('index.html')
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\templating.py", line 134, in render_template
    return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
  File "\miniconda3\envs\testenv\lib\site-packages\jinja2-2.10-py3.5.egg\jinja2\environment.py", line 869, in get_or_select_template
    return self.get_template(template_name_or_list, parent, globals)
  File "\miniconda3\envs\testenv\lib\site-packages\jinja2-2.10-py3.5.egg\jinja2\environment.py", line 830, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "\miniconda3\envs\testenv\lib\site-packages\jinja2-2.10-py3.5.egg\jinja2\environment.py", line 804, in _load_template
    template = self.loader.load(self, name, globals)
  File "\miniconda3\envs\testenv\lib\site-packages\jinja2-2.10-py3.5.egg\jinja2\loaders.py", line 113, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\templating.py", line 58, in get_source
    return self._get_source_fast(environment, template)
  File "\miniconda3\envs\testenv\lib\site-packages\flask-1.0.2-py3.5.egg\flask\templating.py", line 86, in _get_source_fast
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: index.html

Parent issue for variability support

Goal

We want to propagate an ensemble of e.g. weather scenarios through a system-of-systems model to assess the resilience of the system-of-systems

Ideally, this could be available to the user at the command-line, with the subcommand smif prepare and arguments [modelrun_template] [scenario_name] [variant range], or perhaps some useful helpers for specifying a range of scenario variant names like --start weather_001 --end weather_100

Related goal

We want to perform a global sensitivity analysis, and have generated a sample of input data we wish to propagate through the system-of-systems to assess sensitivity of one or more model outputs to the inputs.

Core functionality

  • Write a script which generates one scenario variant for each replicate in the ensemble #362
  • Write a script which generates one model run for each scenario variant in the ensemble #363
  • Perform the batch model run #179
  • Obtain and collate results (extension of #350)
  • Add command line argument (#364)

Alternatively, the steps could be:

  • Add the ensemble as a dimension within a smif scenario
  • Autogenerate a batch of model runs, one for each ensemble realisation
  • perform batch model run
  • obtain and collate results

Make data-reading error comprehensible

Error triggered by reading in narrative data with accidentally-duplicate rows:

enduses_service_switch,sector,tech,end_yr,switches_service
rs_lighting,,LED,2030,1.0
rs_lighting,,LED,2030,1.0
ss_lighting,,LED,2050,1.0
ss_lighting,,LED,2050,1.0

Was:

Traceback (most recent call last):
  File "c:\miniconda2\envs\ed\lib\site-packages\smif\controller\scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id) File
    "c:\miniconda2\envs\ed\lib\site-packages\smif\controller\scheduler.py", line 237, in _run
    decision_iteration=job['decision_iteration'] File
    "c:\miniconda2\envs\ed\lib\site-packages\smif\data_layer\data_handle.py", line 62, in
    __init__ self._load_parameters(sos_model, modelrun['narratives']) File
    "c:\miniconda2\envs\ed\lib\site-packages\smif\data_layer\data_handle.py", line 129, in
    _load_parameters narrative_name, variant_name, parameter File
    "c:\miniconda2\envs\ed\lib\site-packages\smif\data_layer\store.py", line 551, in
    read_narrative_variant                     _data return
    self.data_store.read_narrative_variant_data(key, spec, timestep) File
    "c:\miniconda2\envs\ed\lib\site-packages\smif\data_layer\file\file_data_store.py", line 95,
    in read_nar                     rative_variant_data return self._read_data_array(path,
    spec, timestep) File
    "c:\miniconda2\envs\ed\lib\site-packages\smif\data_layer\file\file_data_store.py", line
    376, in _read_d                     ata_array data_array = DataArray.from_df(spec,
    dataframe) File "c:\miniconda2\envs\ed\lib\site-packages\smif\data_layer\data_array.py",
    line 153, in from_df xr_dataset = dataframe.to_xarray()  # convert to dataset File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\core\generic.py",
    lin                     e 1690, in to_xarray return xarray.Dataset.from_dataframe(self)
    File "c:\miniconda2\envs\ed\lib\site-packages\xarray\core\dataset.py", line 3092, in
    from_dataframe dataframe = dataframe.reindex(full_idx) File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\util\_decorators.py",
    line 127, in wrapper return func(*args, **kwargs) File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\core\frame.py",
    line                      2935, in reindex return super(DataFrame, self).reindex(**kwargs)
    File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\core\generic.py",
    lin                     e 3023, in reindex fill_value, copy).__finalize__(self) File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\core\frame.py",
    line                      2870, in _reindex_axes fill_value, limit, tolerance) File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\core\frame.py",
    line                      2878, in _reindex_index tolerance=tolerance) File
    "c:\miniconda2\envs\ed\lib\site-packages\pandas-0.22.0-py3.6-win-amd64.egg\pandas\core\indexes\multi.py
    ", line 1903, in reindex raise Exception("cannot handle a non-unique multi-index!")
    Exception: cannot handle a non-unique multi-index! Exception: cannot handle a non-unique
    multi-index!

Should be SmifDataMismatch or similar, with message that filename (for narrative, variant,
parameter..) had some row (include details) duplicated.

Check also the case where the value might be different:

enduses_service_switch,sector,tech,end_yr,switches_service
rs_lighting,,LED,2030,1.0
rs_lighting,,LED,2030,1.1

is self-contradictory.

Performance: Trying to read model parameter default from key <*>.csv seems slow

With the large number of parameters in the digital comms model, reading from multiple columns of a single default.csv file is very slow.

DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv
DEBUG    Trying to read model parameter default from key ../digital_comms/parameters/defaults.csv```

Add a 'When should I use smif?' section to the docs

Prompted by an email query - "Specifically, I have followed the documentation and understood how to use SMIF and what all the different config files do, but I could do with knowing about SMIF’s limits. Are there any limits on the inputs, outputs or types of model that can be run?"

First notes on an answer:

There are practical limits imposed by smif’s current implementation:

  • Models are run serially by a single python process - smif can identify but do not yet exploit opportunities to run models in parallel, so there’s a speed-up not yet being used (work in progress).
  • Geographical extent is expected to be defined explicitly by a vector geometry - smif is not set up ideally for models which simulate on a grid, though they could be shoehorned into the framework.
  • Inputs and outputs are exchanged at the ‘planning timestep’ resolution - smif makes a distinction between simulation of operation (which happens at some model-defined timestep resolution) and application of planning decisions (which happens at a timestep which is synchronised between all models, currently assumed to be annual), so smif is not focussed on tight coupling between models which need to exchange data at every simulation timestep.

There are conceptual assumptions that relate to the style of model we’re developing for NISMOD (the National Infrastructure Simulation Model). These are:

  • bottom-up, engineering simulation models built to simulate the operation of a given infrastructure system
  • which give up responsibility for dynamic changes to the system to some planning model or models (more generically, some process that produces a series of planning decisions which determine the state of the system to be simulated)

This means that we’ve not thought so much about:

  • discrete event system simulation models (e.g. queuing systems)
  • dynamical system models (e.g. predator/prey)
  • equilibrium models without explicit timesteps (e.g. Land-Use Transport Interaction)

Suggestion from @willu47 - looks like this could go under a "When should I use smif?" bit in the docs, linking to future development and encouraging contributions.

data_handle.set_results() function

  • I would recommend using np.result() and np.load() instead of writing to CSV for the set_result() function
  • If we go for CSV there needs to be removed the extra lines which are generated when writing to file
  • I would also recommend deleting previous model runs if the same model run is run twice

Consolidate sample project into consistent set of valid fixtures

Fixtures should act as a single source of truth for a valid project.

  • Write a script to update the src/smif/sample_project folder using the write_* methods on
    DatafileInterface.
  • Also include option to generate DatabaseInterface version of sample_project (and also
    MemoryInterface) from same fixtures.

Missing narrative results in incomprehensible error

The following error is difficult to understand.

Traceback (most recent call last):
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 240, in _run
    decision_iteration=job['decision_iteration']
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 62, in __init__
    self._load_parameters(sos_model, modelrun['narratives'])
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 114, in _load_parameters
    narrative = [x for x in sos_model['narratives'] if x['name'] == narrative_name][0]
IndexError: list index out of range

Fix saving a new SoS model

  • create a new SoS model
  • add a scenario, model, dependency
  • save > hangs on loading, KeyError 'dims' on server side

Parent issue for results API

Goal

Improve the ability to query results from model runs within smif by developing a suitable API.

Problem

  • At present, results are stored using the file store in a logical, but granular, folder structure
  • Results can be accessed using the methods in smif.data_layer.store such as
    • read_results, write_results, available_results
  • The aim of this parent issue is to provide more usable access to the results. Practically, this involves accessing, exposing, collating, aggregating and filtering the results and serving them to the user

Core functionality

  • Find out for which model runs results are available #351

  • Check that the results for a model run are complete, and if not, which are missing #352

  • Programmatically query the available model results (#359) across various levels in the hierarchy of

    • modelrun
    • timestep <- these are defined in a model run
    • decision_iteration <- iterations exist or not depending on the decision module and may change from run to run. Note also that the numbers of iterations per timestep may change.
    • model_name <- this is a model within a system of systems
    • output_name <- these are defined in the model_name configuration
    • dimensions within the output_name <- these are defined in an output's Spec, also in config
  • Users should be able to fix one or more of the above levels and receive a multi-dimensional array of data that represents the unfixed data. For example given:

modelruns: ['first_model_run', 'test_model_run', 'ensemble_0000', 'ensemble_0001', 'ensemble_0002']
timesteps: [2010, 2015, 2020]
iterations: [0]

models

name: 'water_supply'
outputs:
- name: cost
  dims:
  - local_authority_districts
  dtype: float
  unit: million GBP
- name: energy_demand
  dims:
  - local_authority_districts
  dtype: float
  unit: kWh

Something like:

  • get_results(timestep=[2010], models=['water_supply']) should return results for both outputs (cost and energy_demand) for the year 2010 for the single iteration 0
  • get_results(models['water_supply'], outputs=['cost']) should return a timeseries of costs for the output cost for the single iteration 0

Find out for which model runs results are available

  • Add a --results subcommand (or equivalent) to the smif list command which indicates which model runs have results and...
  • whether the results are complete or not (i.e has been run successfully so that the results have a similar timestamp and all results files are present for all outputs listed in config)
  • note that this raises the issue of having an incomplete implementation of a smif wrapper which fails to call the set_results method for a particular output, despite that output being listed in the config

Parent issue #350

Add examples to data_handle methods

Extending the existing data_handle doc strings with examples, return types etc. would assist
users in using the SectorModel class and wrapping their models. Use material in the
getting_started.rst file

Unhelpful error message when incorrect narrative variant provided

Adding a new narrative results in the following error message which is unhelpful to diagnose what the issue is. Replacing the narrative construct with an empty dict in the yaml configuration file removes the source of the error.

Traceback (most recent call last):
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 240, in _run
    decision_iteration=job['decision_iteration']
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 66, in __init__
    self._load_parameters(sos_model, modelrun['narratives'])
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 138, in _load_parameters
    narrative_name, variant_name, parameter
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/store.py", line 545, in read_narrative_variant_data
    key = self._key_from_data(variant['data'][parameter_name], narrative_name,
TypeError: 'NoneType' object is not subscriptable
Traceback (most recent call last):
  File "/home/vagrant/nismod/bin/smif", line 10, in <module>
    sys.exit(main())
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/cli/__init__.py", line 345, in main
    args.func(args)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/cli/__init__.py", line 129, in run_model_runs
    execute_model_run(model_run_ids, store, args.warm)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/execute.py", line 32, in execute_model_run
    modelrun.run(store)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/modelrun.py", line 137, in run
    modelrunner.solve_model(self, store)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/modelrun.py", line 190, in solve_model
    raise err
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 178, in add
    self._run(job_graph, job_graph_id)
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/controller/scheduler.py", line 240, in _run
    decision_iteration=job['decision_iteration']
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 66, in __init__
    self._load_parameters(sos_model, modelrun['narratives'])
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/data_handle.py", line 138, in _load_parameters
    narrative_name, variant_name, parameter
  File "/home/vagrant/nismod/lib/python3.5/site-packages/smif/data_layer/store.py", line 545, in read_narrative_variant_data
    key = self._key_from_data(variant['data'][parameter_name], narrative_name,
TypeError: 'NoneType' object is not subscriptable

Scenario dependency validation in sosmodel form doesn't allow editing of sink

Validation message provides me with the following information:

(Dependency 1) Source `ev_trip_start` has different dimensions than sink `ev_trips` (['lad_uk_2016', 'annual_day'] != ['lad_uk_2016', 'daily']). Dependencies must have matching dimensions.

I wish to edit the dimension of the sink (ev_trips), but the form won't allow me to do this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.