Closed Sheshuk closed 2 years ago
Benchmark | Min | Max | Mean |
---|---|---|---|
python/snewpy/test/test_snowglobes.py::test_simulation_chain_benchmark | 5.76 | 6.06 | 5.93 +- 0.11 |
Hi @Sheshuk! Two high level comments right up front:
simulate
and collate
into two independent steps is not a design issue that needed to be fixed, but a feature. Detectors, smearing matrices and cross-sections don’t usually change frequently, whereas analysis code often does; so it is useful to have a “cached” version of the results on disk and just run collate
at the start of an analysis script, instead of having to re-run SNOwGLoBES every single time.I would set a high bar for any changes to the interface that are not backwards-compatible
I agree. It's not hard to make the output backward compatible, while keeping the new functionality. Will do that.
Separating simulate and collate into two independent steps is not a design issue that needed to be fixed, but a feature. Detectors, smearing matrices and cross-sections don’t usually change frequently, whereas analysis code often does; so it is useful to have a “cached” version of the results on disk and just run collate at the start of an analysis script, instead of having to re-run SNOwGLoBES every single time.
SNOwGLoBES running time is negligible, compared to the current collate
step. I agree that it's feasible to store the results of the simulation, but one needs to store collated data tables, not the individual output files of the SNOwGLoBES - and this is handled by collate
step. Then the data tables can be processed.
Here's a timing benchmark with simulate+collate
steps for the main branch (old
) and current branch (new
), processing the file, generated with generate_time_series
for a single detector (icecube
):
~/work/snews2/snewpy(main*) _ pytest-benchmark compare 0020 0019
--------------------------------------------------------------------------------------------- benchmark: 2 tests --------------------------------------------------------------------------------------------
Name (time in s) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_simulation_chain_benchmark (0019_new) 12.2361 (1.0) 12.6197 (1.0) 12.4153 (1.0) 0.1894 (1.0) 12.3697 (1.0) 0.3710 (1.24) 2;0 0.0805 (1.0) 5 1
test_simulation_chain_benchmark (0020_old) 77.6742 (6.35) 78.1286 (6.19) 77.8271 (6.27) 0.1979 (1.04) 77.7252 (6.28) 0.2999 (1.0) 1;0 0.0128 (0.16) 5 1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Legend:
Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
OPS: Operations Per Second, computed as 1 / Mean
Please have a look, any suggestions are welcome.
Many thanks for these changes!
I just checked out the branch to try it out and noticed that installing with pip install .
doesn’t currently work, since the PyTables module (used internally by pandas.HDFStore
which writes/reads the files in simulate()
and collate()
) requires installing the HDF5 C library separately.
I’ve tried using np.save
/np.load
instead and found that it not just works fine, but is also noticeably faster:
Time to write files:
HDFStore: 0.178929
np.save: 0.000516
Time to read files:
HDFStore: 0.022347
np.load: 0.004025
I’ve made a new commit with this change.
On a separate note, I’ve seen that you use removesuffix()
in the code. That’s a new feature in Python 3.9, so we’d have to require a quite new version. This seems a bit aggressive; for comparison, the policy of NumPy (and many others packets in the scientific Python ecosystem) is to support Python 3.7 until end of December and require 3.9 from April 2023.
Finally, running pytest python/snewpy/test/test_snowglobes.py
I get one error:
____________________________________________________________________ ERROR at setup of test_simulation_chain_benchmark _____________________________________________________________________
file /Users/jost/Documents/Academia/SNEWS/Software/snewpy/python/snewpy/test/test_snowglobes.py, line 48
@pytest.mark.timing
def test_simulation_chain_benchmark(benchmark):
E fixture 'benchmark' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, sng, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
/Users/jost/Documents/Academia/SNEWS/Software/snewpy/python/snewpy/test/test_snowglobes.py:48
I guess the issue is that I’m missing pytest-benchmark
, which you’ve added to the integration.yml
but not to requirements.txt
. However, since both pytest
and pytest-benchmark
are not required for using snewpy, I’d probably only add them as extras_require
in setup.py
and remove pytest
from requirements.txt
; so it’s not automatically installed with pip install snewpy
but only with e.g. pip install snewpy[dev]
. What do you think?
I’ve tried using
np.save
/np.load
instead and found that it not just works fine, but is also noticeably faster
Good catch, thanks! I didn't know numpy deals with nested dictionaries of tables. I hesitated to use PyTables in the first place (although it worked for me after pip install tables
, probably HDF5 was already installed).
On a separate note, I’ve seen that you use
removesuffix()
in the code. That’s a new feature in Python 3.9, so we’d have to require a quite new version. This seems a bit aggressive; for comparison, the policy of NumPy (and many others packets in the scientific Python ecosystem) is to support Python 3.7 until end of December and require 3.9 from April 2023.
Oh, I didn't know that. I'll get rid of it, off course (fixed in https://github.com/SNEWS2/snewpy/pull/132/commits/f87ac099a53758d2f9d46cb246c9284e9f58ad38) . I suppose we'll need to include also running snowglobes tests with [3.7, 3.8] in our CI.
I’d probably only add them as
extras_require
insetup.py
and removepytest
fromrequirements.txt
; so it’s not automatically installed withpip install snewpy
but only with e.g.pip install snewpy[dev]
. What do you think?
Yes, that's a good idea! We can also put the snewpy[doc] requirements there as an extra, instead of having a separate file in docs/.
Added them as extras in setup.py
, as discussed. Good point about the docs’ requirements, though that should probably be a separate PR. I’ve opened an issue so we don’t forget.
… and speaking of docs: I don’t think we need to update them, since these changes are behind the scenes and don’t affect the user interface; but let me know if I’m missing something?
Trying this now, I get the following:
asyncio.run() cannot be called from a running event loop
I have 300 hundred flux files in my tar ball, if that is useful. I will debug myself later, but any insight would be helpful.
@JostMigenda I've updated the docstrings, so maybe we can add it in the snowglobes
section of the documentation, as "Low-level interface" part?
@evanoconnor can you provide the code you're running? So I could debug
ok @Sheshuk re: asyncio.run() cannot be called from a running event loop
, this occurs for me with the SNOwGLoBES_usage.ipynb
file in the doc/nb
directory. So maybe something with my python/jupyter setup...
Oh, so this is because Jupyter has its own loop. I used async functions to use the time we're waiting for the SNOwGLoBES process more efficiently. Maybe I should put my calculation in a separate thread to avoid the async loops collision.
Also I'll add a separate async test case
@evanoconnor could you try again now? It should be fixed by https://github.com/SNEWS2/snewpy/pull/132/commits/972c3e2f6964644646866d9be9a7f4f3a7be9b8f.
Yes, this now works and I get the same results as in the main branch without the super long collate stage. Nice!
Is it easy to include a progress bar for the number of fluence files?
I guess the warnings can be suppressed with a log alert level or something?
Yes, this now works and I get the same results as in the main branch without the super long collate stage. Nice!
Great! Could you please measure the time for both branches? (%%time
magic command in Jupyter cell)
Is it easy to include a progress bar for the number of fluence files?
The files are being processed asynchronously, i.e. somewhat in parallel, so we only have an input and output points. I'll think of possible solutions. For example, we could run them in some smaller bunches.
I guess the warnings can be suppressed with a log alert level or something?
Looking into it. Can you paste here the warnings?
Oh, now I see the warnings. They're mostly from logging.info
, so it's possible to configure it to be less verbose by default.
all times in seconds
this branch: fluence calculation: 43 running snowglobes (wc100kt30prct): 50.2 collating (wc100kt30prct): 13.4
main branch: fluence calculation: 43.1 running snowglobes (wc100kt30prct): 55.4 collating (wc100kt30prct): 247
for the warnings, the efficiency files not found one shows up a bunch (for scint, since that one doesn't have an efficiency, it is for every fluence file I run). This is useful, but a normal snowglobes users doesn't get such a warning, so not critical for us to relay I think, it could be a fairly low level warning, maybe off by default.
What is the desired behavior? Now when we try to process a detector with undefined efficiency/smearing we write a warning, and return Exception instead of the result. IMO the user should be warned, that something went wrong while processing his input. I can reduce the number of warnings - making a check for the detector before trying each flux file.
@Sheshuk I think the "Low-level interface" section in the docs is useful; thanks! Here’s the documentation for that branch on readthedocs for proofreading; it looks like there are still a few formatting issues.
@JostMigenda fixed the docs, please check in case I missed something,
@evanoconnor I reduced the number of warning messages, so it's only one for each detector without efficiencies.
Another problem is d2O
detector - it doesn't have smearing files for the channels, so it crashes. I didn't hardcode the list of detectors if you pass detector_input="all"
, so it reads all detectors known to SNOwGLoBES. After I fix this, I think, it's ready to merge, unless you have more suggestions.
Just some minor cleanup. No more obvious issues from my end; thanks a lot for being so responsive!
Ugh, this d2O
experiment also lacks the xsec files 😞 I guess I'll just have to drop it from the definition of the detectors in snowglobes.simulate (detector_input="all")
case.
Okay, now I think it's done. It doesn't produce many warnings unless someone specifically provides incorrect input/experiment. Thanks for the feedback and corrections! Ready to merge when approved, unless there are more suggestions.
And I also have the problem with detectors and materials ending with _he
. I'll work on that tomorrow and let you know when I'm ready,
Okay, let’s wait for that (and for Evan’s confirmation).
On the administrative side: This is a pretty large PR that effectively re-writes a whole component of the software. Given that the JOSS review is currently ongoing (and one reviewer has already completed their review), it’s probably preferable to finish that before merging this PR?
(Alternatively, we could create a separate JOSSReview/v1.1
branch from the current main
branch, use that to continue the JOSS review and tag v1.1 off of it when it is finished; while merging this PR to main and continuing feature development there.)
Okaay, looks like the *_he
experiments are defined on a different energy grid - with 400 points, not 200 as others, that's why it was crashing. Now I have it hardcoded - which is fine with the current version of SNOwGLoBES, but probably we'll want to have some flexibility with it in the future.
@JostMigenda I've fixed the _he
detectors, so now everything seems to be done.
Alternatively, we could create a separate
JOSSReview/v1.1
branch from the currentmain
branch, use that to continue the JOSS review and tag v1.1 off of it when it is finished; while merging this PR to main and continuing feature development there
I like that option. Polishing the release should be decoupled from merging the new features. So, either we make a separate branch for new release, as you suggested, or make additional development
branch with the same protection rules - 1 approved PR. Whatever you prefer
Thanks! Yes, it's possible to make an async progressbar, but needs some work. It can be a separate task.
Closes #126 Closes #130
A new python interface for running SNOwGLObES implemented:
Jinja2
library to prepare the configuration files from a templatepandas
to store and manipulate data tables So this adds two dependencies, but make code much smaller and simpler.If many flux files provided, it tries to run them asynchronously. But it's not possible to parallelize running
bin/supernova
subprocess, because SNOwGLoBES always uses the same configuration filesupernova.glb
The new interface collects the output files right after the process finished, so there is no need for cleanup, and also disk i/o should be reduced. And now there's no need for a separate
simulate
andcollate
steps.Usage is simple:
The previous functions
snowglobes.simulate
andsnowglobes.collate
now use this interface and are adapted for the backward compatibility. Nowsimulate
stores the resulting tables in thehdf5
file, andcollate
aggregates thenc_*
and_e
channels like