Skip to content

Commit

Permalink
add Sobol sensitivity analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
yalinli2 committed Jan 31, 2021
1 parent 7c415a6 commit 90c71ca
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 7 deletions.
11 changes: 9 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'manni'
# pygments_style = 'sphinx'

# -- Options for HTML output -------------------------------------------------

Expand All @@ -73,4 +72,12 @@

# -- Extension settings -------------------------------------------------------
# napoleon_custom_sections = [
# 'Reference documents']
# 'Reference documents']

# -- External mapping -------------------------------------------------------
intersphinx_mapping = {
'BioSTEAM': ('https://biosteam.readthedocs.io/en/latest', None),
'Thermosteam': ('https://thermosteam.readthedocs.io/en/latest', None),
'chemicals': ('https://chemicals.readthedocs.io/en/latest', None),
'SALib': ('https://salib.readthedocs.io/en/latest', None),
}
7 changes: 4 additions & 3 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ How does ``QSDsan`` work?

Simplified unified modeling language (UML) diagram of ``QSDsan``

``QSDsan`` follows the structure of `BioSTEAM <https://github.com/BioSTEAMDevelopmentGroup/biosteam>`_, a fast and flexible package for the design, simulation, and techno-economic analysis of biorefineries under uncertainty, but ``QSDsan`` is enhanced with features geared toward quantitative sustainable design of sanitation systems.
``QSDsan`` follows the structure of `biosteam <https://github.com/BioSTEAMDevelopmentGroup/biosteam>`_, a fast and flexible package for the design, simulation, and techno-economic analysis of biorefineries under uncertainty, but ``QSDsan`` is enhanced with features geared toward quantitative sustainable design of sanitation systems.

The above Unified Modeling Language (UML) diagram of the package shows the relationship between ``QSDsan`` and its dependencies `biosteam <https://github.com/BioSTEAMDevelopmentGroup/biosteam>`_ and `thermosteam <https://github.com/BioSTEAMDevelopmentGroup/thermosteam>`_.

In particular, ``QSDsan`` introduces:

- :class:`~.Component`, a subclass of :class:`thermosteam.Chemical`, instance of this class does not necessarily corresponds to a specific chemical, but represents commonly used/modeled component such as biodegradable colloidal substrate.
- :class:`~.WasteStream`, a sublcass of :class:`thermosteam.Stream`, instance of this class has additional composite properties such as chemical oxygen demand (COD) that are widely used in sanitation systems.
- :class:`Component`, a subclass of :class:`thermosteam.Chemical`, instance of this class does not necessarily corresponds to a specific chemical, but represents commonly used/modeled component such as biodegradable colloidal substrate.
- :class:`WasteStream`, a sublcass of :class:`thermosteam.Stream`, instance of this class has additional composite properties such as chemical oxygen demand (COD) that are widely used in sanitation systems.
- :class:`Process` (*under development*), a new class that describes a certain biological, chemical, or physical process in a unit operation, it has some similarities with :class:`thermosteam.reaction`, but has unique features and utilities.


Expand All @@ -63,6 +63,7 @@ In particular, ``QSDsan`` introduces:
LCA
SanUnit
sanunits/sanunits
sensitivity
SimpleTEA
Transportation
WasteStream
Expand Down
7 changes: 7 additions & 0 deletions docs/source/sensitivity.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Sensitivity
===========

Sobol
-----
.. automethod:: qsdsan.sensitivity.define_saltelli_problem
.. automethod:: qsdsan.sensitivity.sobol_analysis
1 change: 1 addition & 0 deletions qsdsan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
utils,
sanunits,
systems,
sensitivity,
)

utils.secondary_importing()
Expand Down
2 changes: 1 addition & 1 deletion qsdsan/_lca.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ def save_report(self, file=None, sheet_name='LCA',
with pd.ExcelWriter(file) as writer:
for table in tables:
table.to_excel(writer, sheet_name=sheet_name, startrow=n_row)
n_row += table.shape[0] + row_space + 1 # one extra line for the heading
n_row += table.shape[0] + row_space + len(table.columns.names) # extra lines for the heading

@property
def system(self):
Expand Down
23 changes: 23 additions & 0 deletions qsdsan/sensitivity/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
QSDsan: Quantitative Sustainable Design for sanitation and resource recovery systems
This module is developed by:
Yalin Li <zoe.yalin.li@gmail.com>
This module is under the University of Illinois/NCSA Open Source License.
Please refer to https://github.com/QSD-Group/QSDsan/blob/master/LICENSE.txt
for license details.
'''

from .sobol import *

from . import (
sobol,
)

__all__ = (
*sobol.__all__,
)
121 changes: 121 additions & 0 deletions qsdsan/sensitivity/sobol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
QSDsan: Quantitative Sustainable Design for sanitation and resource recovery systems
This module is developed by:
Yalin Li <zoe.yalin.li@gmail.com>
This module is under the University of Illinois/NCSA Open Source License.
Please refer to https://github.com/QSD-Group/QSDsan/blob/master/LICENSE.txt
for license details.
'''


# %%

# =============================================================================
# Sobol analysis with Saltelli sampling
# =============================================================================

__all__ = ('define_saltelli_problem', 'sobol_analysis')

import pandas as pd
# #!!! Can potentially change the sampling method
# from SALib.sample.saltelli import sample
from SALib.analyze.sobol import analyze

def define_saltelli_problem(model):
'''
Define the problem to be used in Saltelli sampling for ``SALib``.
Parameters
----------
model : :class:`biosteam.Model`
Uncertainty model with defined metrics and parameters.
See Also
--------
`SALib.sample.saltelli.sample <https://salib.readthedocs.io/en/latest/api.html#sobol-sensitivity-analysis>`_
'''
params = model.get_parameters()
problem = {
'num_vars': len(params),
'names': [i.name for i in params],
'bounds': [i.bounds if i.bounds
else (i.distribution.lower[0], i.distribution.upper[0])
for i in params]
}
return problem

def sobol_analysis(model, samples, problem, metrics, fill_nan_with_mean=False,
calc_second_order=True, conf_level=0.95, print_to_console=False,
file='', **sobol_kwargs):
'''
Run Sobol sensitivity analysis using ``SALib``.
Parameters
----------
model : :class:`biosteam.Model`
Uncertainty model with defined metrics and parameters.
samples : :class:`numpy.array`
Samples for Sobol analysis.
problem : dict
Keys including "num_vars", "names", and "bounds".
metrics : iterable
Metrics to be included for Sobol analysis, must be a subset of
(i.e., included in the `metrics` attribute of the given model).
fill_nan_with_mean : bool
Whether to use the mean value to replace the "NaN" values in the metric results.
calc_second_order : bool
Whether to calculate second-order interaction effects.
conf_level : float
Confidence level of results.
print_to_console : float
Whether to show results in the console.
file : str
If provided, the results will be saved as an Excel file.
Returns
-------
si_dct : dict
A dict of Sobol analysis results.
See Also
--------
`SALib.analyze.sobol.analyze <https://salib.readthedocs.io/en/latest/api.html#sobol-sensitivity-analysis>`_
'''
si_dct = {}
for metric in metrics:
results = model.table[metric.index]
if results.isna().values.any():
if fill_nan_with_mean:
results.fillna(results.mean(), inplace=True)
else:
raise ValueError('"NaN" values in metrics, cannot run analysis.')
si = analyze(problem, results.to_numpy(),
calc_second_order=calc_second_order,
conf_level=conf_level, print_to_console=print_to_console,
**sobol_kwargs)
si_dct[metric.name] = si
if file:
writer = pd.ExcelWriter(file)
for name, si in si_dct.items():
n_row = 0
for df in si.to_df():
df.to_excel(writer, sheet_name=name, startrow=n_row)
n_row += len(df.index) + 2 + len(df.columns.names)
writer.save()
return si_dct









3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ biosteam
sphinx
sphinx_rtd_theme
nbsphinx
scikit-learn
scikit-learn
salib

0 comments on commit 90c71ca

Please sign in to comment.