Skip to content

Commit

Permalink
add progress bar for unit evalution
Browse files Browse the repository at this point in the history
  • Loading branch information
adumasphi committed Jan 18, 2024
1 parent 3009e4b commit f3b6a56
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on top of `OpenTURNS <http://www.openturns.org>`_, with its users as the target
audience. Documentation is available
`here <http://openturns.github.io/otwrapy/master>`_. The module provides :

- An integrated progress bar for unit evaluation of a sample without parallelization.
- A `Parallelizer` class that converts any
`ot.Function <http://openturns.github.io/openturns/master/user_manual/_generated/openturns.Function.html>`_
into a parallel wrapper using either
Expand Down
45 changes: 39 additions & 6 deletions otwrapy/_otwrapy.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import logging
import openturns as ot
import numpy as np
from tqdm import tqdm

__author__ = "Felipe Aguirre Martinez"
__copyright__ = "Copyright 2015-2019 Phimeca"
Expand Down Expand Up @@ -338,6 +339,36 @@ def __exit__(self, type, value, traceback):
shutil.rmtree(self.dirname)


def _exec_sample_serial(func, verbosity):
"""Return a function that evaluate the sample and provide a progress bar.
Parameters
----------
func : Function or callable
A callable python object, usually a function. The function should take
an input vector as argument and return an output vector.
verbosity : int
If value greater than 0, the progress bar is displayed.
Returns
-------
_exec_sample : Function or callable
The function with the progress bar.
"""

def _exec_sample(X):
X = ot.Sample(X)
if verbosity > 0 and X.getSize() > 1:
Y = ot.Sample(0, func.getOutputDimension())
for x in tqdm(X):
Y.add(func(x))
else:
Y = func(X)
return ot.Sample(Y)

return _exec_sample


def _exec_sample_joblib(func, n_cpus, verbosity):
"""Return a function that executes a sample in parallel using joblib.
Expand Down Expand Up @@ -508,15 +539,17 @@ class Parallelizer(ot.OpenTURNSPythonFunction):
openturns wrapper to be distributed
backend : string (Optional)
Whether to parallelize using 'ipyparallel', 'joblib', pathos, or
'multiprocessing'.
Whether to parallelize using 'ipyparallel', 'joblib', 'pathos', 'multiprocessing' or
'serial'. Serial backend means unit evaluation, with a progress bar if verbosity > 0.
n_cpus : int (Optional)
Number of CPUs on which the simulations will be distributed. Needed Only
if using 'joblib', pathos or 'multiprocessing' as backend.
If n_cpus = 1, the behavior is the same as 'serial'.
verbosity : int (Optional)
verbose parameter when using 'joblib' or 'dask'. Default is 10.
verbose parameter when using 'joblib', 'dask' or without parallelization. Default is 10.
For 'serial', if verbosity > 0, a progress bar is displayed using tqdm module.
When 'dask' is used, 0 means no progress bar, whereas other value activate the progress bar.
dask_args : dict (Optional)
Expand Down Expand Up @@ -566,13 +599,13 @@ def __init__(self, wrapper, backend='multiprocessing', n_cpus=-1, verbosity=10,
self.setInputDescription(self.wrapper.getInputDescription())
self.setOutputDescription(self.wrapper.getOutputDescription())

assert backend in ['ipython', 'ipyparallel',
assert backend in ['serial', 'ipython', 'ipyparallel',
'multiprocessing', 'pathos',
'joblib', 'dask'], "Unknown backend"

# This configures how to run samples on the model :
if self.n_cpus == 1:
self._exec_sample = self.wrapper
if backend == 'serial' or self.n_cpus == 1:
self._exec_sample = _exec_sample_serial(self.wrapper, verbosity)

elif (backend == 'ipython') or (backend == 'ipyparallel'):
# Check that ipyparallel is installed
Expand Down
9 changes: 5 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@
name='otwrapy',
version=version,
packages=find_packages(),
extras_require = {
extras_require={
'joblib': ["joblib>=0.9.3"],
'ipyparallel': ["ipyparallel>=5.0.1"],
'pathos': ["pathos>=0.2.0"],
'dask': ["dask>=2021.01.0", "asyncssh"]
'dask': ["dask>=2021.01.0", "asyncssh"],
'tqdm': ["tqdm>=4.0.0"]
},
author="Felipe Aguirre Martinez",
author_email="aguirre@phimeca.com",
description="General purpose OpenTURNS python wrapper tools",
long_description=long_description,
setup_requires=['pytest-runner'],
tests_require=['pytest'],
include_package_data = True,
package_data = {'otwrapy': ['examples/beam/*']},
include_package_data=True,
package_data={'otwrapy': ['examples/beam/*']},
scripts=['otwrapy/examples/beam/beam_wrapper'],
zip_safe=False
)
5 changes: 4 additions & 1 deletion tests/test_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ def backendtest(backend):
dask_args = {'scheduler': 'localhost', 'workers': {'localhost': n_cpu}}
else:
dask_args = None
model_parallel = otw.Parallelizer(model, backend=backend, dask_args=dask_args)
model_parallel = otw.Parallelizer(model, backend=backend, n_cpus=n_cpu, dask_args=dask_args)
for size in sizes:
X_sample = X_distribution.getSample(size)
Y_ref = model(X_sample)
Y_sample = ot.Sample(model_parallel(X_sample))
assert Y_ref == Y_sample, 'samples do not match'

def test_serial():
backendtest('serial')

def test_joblib():
backendtest('joblib')

Expand Down

0 comments on commit f3b6a56

Please sign in to comment.