mirror of
https://github.com/gsi-upm/soil
synced 2024-11-22 03:02:28 +00:00
Clean up exporters
This commit is contained in:
parent
b0add8552e
commit
97835b3d10
@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.14.2]
|
||||||
|
### Fixed
|
||||||
|
* Output path for exporters is now soil_output
|
||||||
|
### Changed
|
||||||
|
* CSV output to stdout in dry_run mode
|
||||||
|
## [0.14.1]
|
||||||
|
### Changed
|
||||||
|
* Exporter names in lower case
|
||||||
|
* Add default exporter in runs
|
||||||
## [0.14.0]
|
## [0.14.0]
|
||||||
### Added
|
### Added
|
||||||
* Loading configuration from template definitions in the yaml, in preparation for SALib support.
|
* Loading configuration from template definitions in the yaml, in preparation for SALib support.
|
||||||
|
@ -323,7 +323,7 @@ Let's run our simulation:
|
|||||||
|
|
||||||
.. code:: ipython3
|
.. code:: ipython3
|
||||||
|
|
||||||
soil.simulation.run_from_config(config, dump=False)
|
soil.simulation.run_from_config(config)
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
@ -1 +1 @@
|
|||||||
0.14.0
|
0.14.2
|
||||||
|
@ -57,11 +57,11 @@ def main():
|
|||||||
logging.info('Loading config file: {}'.format(args.file))
|
logging.info('Loading config file: {}'.format(args.file))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exporters = list(args.exporter or [])
|
exporters = list(args.exporter or ['default', ])
|
||||||
if args.csv:
|
if args.csv:
|
||||||
exporters.append('CSV')
|
exporters.append('csv')
|
||||||
if args.graph:
|
if args.graph:
|
||||||
exporters.append('Gexf')
|
exporters.append('gexf')
|
||||||
exp_params = {}
|
exp_params = {}
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
exp_params['copy_to'] = sys.stdout
|
exp_params['copy_to'] = sys.stdout
|
||||||
|
@ -50,7 +50,7 @@ class Exporter:
|
|||||||
|
|
||||||
def __init__(self, simulation, outdir=None, dry_run=None, copy_to=None):
|
def __init__(self, simulation, outdir=None, dry_run=None, copy_to=None):
|
||||||
self.sim = simulation
|
self.sim = simulation
|
||||||
outdir = outdir or os.getcwd()
|
outdir = outdir or os.path.join(os.getcwd(), 'soil_output')
|
||||||
self.outdir = os.path.join(outdir,
|
self.outdir = os.path.join(outdir,
|
||||||
simulation.group or '',
|
simulation.group or '',
|
||||||
simulation.name)
|
simulation.name)
|
||||||
@ -78,8 +78,8 @@ class Exporter:
|
|||||||
return open_or_reuse(f, mode=mode, **kwargs)
|
return open_or_reuse(f, mode=mode, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Default(Exporter):
|
class default(Exporter):
|
||||||
'''Default exporter. Writes CSV and sqlite results, as well as the simulation YAML'''
|
'''Default exporter. Writes sqlite results, as well as the simulation YAML'''
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
@ -96,25 +96,29 @@ class Default(Exporter):
|
|||||||
env.dump_sqlite(f)
|
env.dump_sqlite(f)
|
||||||
|
|
||||||
|
|
||||||
class CSV(Exporter):
|
class csv(Exporter):
|
||||||
|
'''Export the state of each environment (and its agents) in a separate CSV file'''
|
||||||
def trial_end(self, env):
|
def trial_end(self, env):
|
||||||
if not self.dry_run:
|
with timer('[CSV] Dumping simulation {} trial {} @ dir {}'.format(self.sim.name,
|
||||||
with timer('[CSV] Dumping simulation {} trial {}'.format(self.sim.name,
|
env.name,
|
||||||
env.name)):
|
self.outdir)):
|
||||||
with self.output('{}.csv'.format(env.name)) as f:
|
with self.output('{}.csv'.format(env.name)) as f:
|
||||||
env.dump_csv(f)
|
env.dump_csv(f)
|
||||||
|
|
||||||
|
|
||||||
class Gexf(Exporter):
|
class gexf(Exporter):
|
||||||
def trial_end(self, env):
|
def trial_end(self, env):
|
||||||
if not self.dry_run:
|
if self.dry_run:
|
||||||
with timer('[CSV] Dumping simulation {} trial {}'.format(self.sim.name,
|
logger.info('Not dumping GEXF in dry_run mode')
|
||||||
env.name)):
|
return
|
||||||
with self.output('{}.gexf'.format(env.name), mode='wb') as f:
|
|
||||||
env.dump_gexf(f)
|
with timer('[GEXF] Dumping simulation {} trial {}'.format(self.sim.name,
|
||||||
|
env.name)):
|
||||||
|
with self.output('{}.gexf'.format(env.name), mode='wb') as f:
|
||||||
|
env.dump_gexf(f)
|
||||||
|
|
||||||
|
|
||||||
class Dummy(Exporter):
|
class dummy(Exporter):
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
with self.output('dummy', 'w') as f:
|
with self.output('dummy', 'w') as f:
|
||||||
@ -131,7 +135,7 @@ class Dummy(Exporter):
|
|||||||
f.write('simulation ended @ {}\n'.format(time.time()))
|
f.write('simulation ended @ {}\n'.format(time.time()))
|
||||||
|
|
||||||
|
|
||||||
class Distribution(Exporter):
|
class distribution(Exporter):
|
||||||
'''
|
'''
|
||||||
Write the distribution of agent states at the end of each trial,
|
Write the distribution of agent states at the end of each trial,
|
||||||
the mean value, and its deviation.
|
the mean value, and its deviation.
|
||||||
@ -165,7 +169,7 @@ class Distribution(Exporter):
|
|||||||
with self.output('metrics.csv') as f:
|
with self.output('metrics.csv') as f:
|
||||||
dfm.to_csv(f)
|
dfm.to_csv(f)
|
||||||
|
|
||||||
class GraphDrawing(Exporter):
|
class graphdrawing(Exporter):
|
||||||
|
|
||||||
def trial_end(self, env):
|
def trial_end(self, env):
|
||||||
# Outside effects
|
# Outside effects
|
||||||
|
@ -11,6 +11,7 @@ logger = logging.getLogger(__name__)
|
|||||||
from collections import UserDict, namedtuple
|
from collections import UserDict, namedtuple
|
||||||
|
|
||||||
from . import serialization
|
from . import serialization
|
||||||
|
from .utils import open_or_reuse
|
||||||
|
|
||||||
|
|
||||||
class History:
|
class History:
|
||||||
@ -236,7 +237,7 @@ class History:
|
|||||||
|
|
||||||
def dump(self, f):
|
def dump(self, f):
|
||||||
self._close()
|
self._close()
|
||||||
for line in open(self.db_path, 'rb'):
|
for line in open_or_reuse(self.db_path, 'rb'):
|
||||||
f.write(line)
|
f.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,11 +153,11 @@ class Simulation(NetworkSimulation):
|
|||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def _run_simulation_gen(self, *args, parallel=False, dry_run=False,
|
def _run_simulation_gen(self, *args, parallel=False, dry_run=False,
|
||||||
exporters=None, outdir=None, exporter_params={}, **kwargs):
|
exporters=['default', ], outdir=None, exporter_params={}, **kwargs):
|
||||||
logger.info('Using exporters: %s', exporters or [])
|
logger.info('Using exporters: %s', exporters or [])
|
||||||
logger.info('Output directory: %s', outdir)
|
logger.info('Output directory: %s', outdir)
|
||||||
exporters = exporters_for_sim(self,
|
exporters = exporters_for_sim(self,
|
||||||
exporters or [],
|
exporters,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
outdir=outdir,
|
outdir=outdir,
|
||||||
**exporter_params)
|
**exporter_params)
|
||||||
|
@ -2,6 +2,8 @@ import logging
|
|||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from shutil import copyfile
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
logger = logging.getLogger('soil')
|
logger = logging.getLogger('soil')
|
||||||
@ -23,11 +25,22 @@ def timer(name='task', pre="", function=logger.info, to_object=None):
|
|||||||
to_object.end = end
|
to_object.end = end
|
||||||
|
|
||||||
|
|
||||||
def safe_open(path, *args, **kwargs):
|
def safe_open(path, mode='r', backup=True, **kwargs):
|
||||||
outdir = os.path.dirname(path)
|
outdir = os.path.dirname(path)
|
||||||
if outdir and not os.path.exists(outdir):
|
if outdir and not os.path.exists(outdir):
|
||||||
os.makedirs(outdir)
|
os.makedirs(outdir)
|
||||||
return open(path, *args, **kwargs)
|
if backup and 'w' in mode and os.path.exists(path):
|
||||||
|
creation = os.path.getctime(path)
|
||||||
|
stamp = time.strftime('%Y-%m-%d_%H:%M', time.localtime(creation))
|
||||||
|
|
||||||
|
backup_dir = os.path.join(outdir, stamp)
|
||||||
|
if not os.path.exists(backup_dir):
|
||||||
|
os.makedirs(backup_dir)
|
||||||
|
newpath = os.path.join(backup_dir, os.path.basename(path))
|
||||||
|
if os.path.exists(newpath):
|
||||||
|
newpath = '{}@{}'.format(newpath, time.time())
|
||||||
|
copyfile(path, newpath)
|
||||||
|
return open(path, mode=mode, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def open_or_reuse(f, *args, **kwargs):
|
def open_or_reuse(f, *args, **kwargs):
|
||||||
|
@ -60,7 +60,7 @@ class Exporters(TestCase):
|
|||||||
}
|
}
|
||||||
output = io.StringIO()
|
output = io.StringIO()
|
||||||
s = simulation.from_config(config)
|
s = simulation.from_config(config)
|
||||||
s.run_simulation(exporters=[exporters.Distribution], dry_run=True, exporter_params={'copy_to': output})
|
s.run_simulation(exporters=[exporters.distribution], dry_run=True, exporter_params={'copy_to': output})
|
||||||
result = output.getvalue()
|
result = output.getvalue()
|
||||||
assert 'count' in result
|
assert 'count' in result
|
||||||
assert 'SEED,Noneexporter_sim_trial_3,1,,1,1,1,1' in result
|
assert 'SEED,Noneexporter_sim_trial_3,1,,1,1,1,1' in result
|
||||||
@ -83,10 +83,10 @@ class Exporters(TestCase):
|
|||||||
s = simulation.from_config(config)
|
s = simulation.from_config(config)
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp()
|
||||||
envs = s.run_simulation(exporters=[
|
envs = s.run_simulation(exporters=[
|
||||||
exporters.Default,
|
exporters.default,
|
||||||
exporters.CSV,
|
exporters.csv,
|
||||||
exporters.Gexf,
|
exporters.gexf,
|
||||||
exporters.Distribution,
|
exporters.distribution,
|
||||||
],
|
],
|
||||||
outdir=tmpdir,
|
outdir=tmpdir,
|
||||||
exporter_params={'copy_to': output})
|
exporter_params={'copy_to': output})
|
||||||
|
Loading…
Reference in New Issue
Block a user