Skip to content

Commit

Permalink
Add unit tests for sobol & sensitivity baseclass
Browse files Browse the repository at this point in the history
  • Loading branch information
Prateek Bhustali committed May 7, 2022
1 parent a0ddbed commit 18ed2f2
Show file tree
Hide file tree
Showing 4 changed files with 685 additions and 0 deletions.
17 changes: 17 additions & 0 deletions tests/unit_tests/sensitivity/ishigami.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Auxiliary file
==============================================
"""

import numpy as np

def evaluate(X, params=[7, 0.1]):
"""Non-monotonic Ishigami-Homma three parameter test function"""

a = params[0]
b = params[1]

Y = np.sin(X[:, 0]) + a * np.power(np.sin(X[:, 1]), 2) + \
b * np.power(X[:, 2], 4) * np.sin(X[:, 0])

return Y
35 changes: 35 additions & 0 deletions tests/unit_tests/sensitivity/sobol_func.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import numpy as np
import copy


def evaluate(X, a_values):

dims = len(a_values)
g = 1

for i in range(dims):
g_i = (np.abs(4 * X[:, i] - 2) + a_values[i]) / (1 + a_values[i])
g *= g_i

return g


def sensitivities(a_values):

dims = len(a_values)

Total_order = np.zeros((dims, 1))

V_i = (3 * (1 + a_values) ** 2) ** (-1)

total_variance = np.prod(1 + V_i) - 1

First_order = V_i / total_variance

for i in range(dims):

rem_First_order = copy.deepcopy(V_i)
rem_First_order[i] = 0
Total_order[i] = V_i[i] * np.prod(rem_First_order + 1) / total_variance

return First_order.reshape(-1, 1), Total_order
234 changes: 234 additions & 0 deletions tests/unit_tests/sensitivity/test_baseclass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
"""
This module is used to test the functionalities of the baseclass.
- test_pick_and_freeze_sampling:
Test the `generate_pick_and_test_samples` function.
- test_bootstrap_for_vector:
Test the bootstrap sampling for a vector.
- test_bootstrap_for_matrix:
Test the bootstrap sampling for a matrix.
"""

import numpy as np
import pytest

from UQpy.run_model.RunModel import RunModel
from UQpy.run_model.model_execution.PythonModel import PythonModel
from UQpy.distributions import Uniform
from UQpy.distributions.collection.JointIndependent import JointIndependent
from UQpy.sensitivity.sobol import Sobol
from UQpy.sensitivity.baseclass.pickfreeze import generate_pick_freeze_samples

# Prepare
###############################################################################

# Prepare the input distribution
@pytest.fixture()
def ishigami_input_dist_object():
"""
This function returns the input distribution for the Ishigami function.
X1 ~ Uniform(-pi, pi)
X2 ~ Uniform(-pi, pi)
X3 ~ Uniform(-pi, pi)
"""
return JointIndependent([Uniform(-np.pi, 2 * np.pi)] * 3)


@pytest.fixture()
def ishigami_model_object():
"""This function creates the Ishigami run_model_object"""
model = PythonModel(
model_script="ishigami.py",
model_object_name="evaluate",
var_names=[r"$X_1$", "$X_2$", "$X_3$"],
delete_files=True,
params=[7, 0.1],
)

runmodel_obj = RunModel(model=model)

return runmodel_obj


@pytest.fixture()
def sobol_object(ishigami_model_object, ishigami_input_dist_object):
"""This function returns the Sobol object."""

return Sobol(ishigami_model_object, ishigami_input_dist_object)


@pytest.fixture()
def sobol_object_input_samples_small(sobol_object):
"""This creates the Sobol object."""

SA = sobol_object

np.random.seed(12345) # set seed for reproducibility

SA.n_samples = 2

return generate_pick_freeze_samples(SA.dist_object, SA.n_samples)


# Generate N pick and free samples
@pytest.fixture()
def pick_and_freeze_samples_small():
"""
This function returns input matrices A, B and C_i with a small number
of samples for the Ishigami input distribution.
This is used to test the `generate_pick_and_freeze_samples` function.
The samples are generated as follows:
dist_1 = JointInd([Uniform(-np.pi, 2*np.pi)]*3)
np.random.seed(12345) #! set seed for reproducibility
n_samples = 2
n_vars = 3
samples = dist_1.rvs(n_samples*2)
# Split samples
A_samples = samples[:n_samples, :]
B_samples = samples[n_samples:, :]
def _get_C_i(i, A, B):
C_i = copy.deepcopy(B)
C_i[:, i] = A[:, i]
return C_i
C_samples = np.zeros((n_vars, n_samples, n_vars))
for i in range(3):
C_samples[i, :, :] = _get_C_i(i, A_samples, B_samples)
print(np.around(A_samples,3))
print(np.around(B_samples,3))
print(np.around(C_samples,3))
"""

A_samples = np.array([[2.699, 0.426, 1.564], [-1.154, 0.600, 0.965]])

B_samples = np.array([[-1.986, 2.919, 1.556], [-1.856, 0.962, 2.898]])

C_samples = np.array(
[
[[2.699, 2.919, 1.556], [-1.154, 0.962, 2.898]],
[[-1.986, 0.426, 1.556], [-1.856, 0.6, 2.898]],
[[-1.986, 2.919, 1.564], [-1.856, 0.962, 0.965]],
]
)

return A_samples, B_samples, C_samples


@pytest.fixture()
def random_f_A():
"""This function returns an A-like vector"""

rand_f_A = np.array([[100], [101], [102], [103], [104]])

return rand_f_A


@pytest.fixture()
def random_f_C_i():
"""This function returns a C_i-like vector"""

rand_f_C_i = np.array([[100, 200], [101, 201], [102, 202], [103, 203], [104, 204]])
return rand_f_C_i


@pytest.fixture()
def manual_bootstrap_samples_f_A():
"""This function bootstraps the A-like vector using random indices"""

# Genrated using np.random.randint(low=0, high=5, size=(5,1))
# with np.random.seed(12345)
# rand_indices_f_A = np.array([ [2],
# [1],
# [4],
# [1],
# [2]])

# bootstrap_f_A = rand_f_A[rand_indices_A]
bootstrap_sample_A = np.array([[102], [101], [104], [101], [102]])

return bootstrap_sample_A


@pytest.fixture()
def manual_bootstrap_samples_f_C_i():
"""This function bootstraps the C_i-like vector using random indices"""

# Genrated using np.random.randint(low=0, high=5, size=(5,2))
# with np.random.seed(12345)
# rand_indices_C_i = np.array([ [2, 1],
# [4, 1],
# [2, 1],
# [1, 3],
# [1, 3]])

bootstrap_f_C_i = np.array(
[[102, 201], [104, 201], [102, 201], [101, 203], [101, 203]]
)

return bootstrap_f_C_i


# Unit tests
###############################################################################


def test_pick_and_freeze_sampling(
pick_and_freeze_samples_small, sobol_object_input_samples_small
):

"""Test the `generate_pick_and_test_samples` function."""

# Prepare
A_samples, B_samples, C_samples = pick_and_freeze_samples_small
A_test, B_test, C_test_generator, _ = sobol_object_input_samples_small

# Act
assert np.allclose(A_samples, np.around(A_test, 3))
assert np.allclose(B_samples, np.around(B_test, 3))

for i in range(3):
C_test = next(C_test_generator)
assert np.allclose(C_samples[i, :, :], np.around(C_test, 3))


def test_bootstrap_for_vector(random_f_A, manual_bootstrap_samples_f_A):

"""Test the bootstrap sampling for a vector."""

# Prepare
np.random.seed(12345) #! set seed for reproducibility

gen_f_A = Sobol.bootstrap_sample_generator_1D(random_f_A)

bootstrap_samples_f_A = next(gen_f_A)

# Act
assert np.array_equal(manual_bootstrap_samples_f_A, bootstrap_samples_f_A)


def test_bootstrap_for_matrix(random_f_C_i, manual_bootstrap_samples_f_C_i):

"""Test the bootstrap sampling for a matrix."""

# Prepare
np.random.seed(12345) #! set seed for reproducibility

gen_f_C_i = Sobol.bootstrap_sample_generator_2D(random_f_C_i)

bootstrap_samples_C_i = next(gen_f_C_i)

# Act
assert np.array_equal(manual_bootstrap_samples_f_C_i, bootstrap_samples_C_i)
Loading

0 comments on commit 18ed2f2

Please sign in to comment.