Skip to content

Commit ba9d883

Browse files
authored
Merge pull request NHERI-SimCenter#401 from bsaakash/master
abs - surrogate-aided Bayesian calibration
2 parents 1b46b71 + a636aff commit ba9d883

20 files changed

Lines changed: 4939 additions & 1164 deletions

modules/performFEM/OpenSees/createOpenSeesDriver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ int main(int argc, const char **argv) {
229229

230230
dpreproCommand = remoteDir + std::string("/applications/performUQ/templateSub/simCenterSub");
231231
openSeesCommand = std::string("/home1/00477/tg457427/bin/OpenSees");
232+
// openSeesCommand = std::string("/opt/apps/intel24/impi21/opensees/3.7.1/bin/OpenSees");
232233
pythonCommand = std::string("python3");
233234

234235
}

modules/performUQ/UCSD_UQ/UCSD_UQ.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,28 @@ def main(args): # noqa: D103
3030
else:
3131
pythonCommand = 'python3' # noqa: N806
3232

33-
mainScriptDir = os.path.dirname(os.path.realpath(__file__)) # noqa: PTH120, N806
34-
mainScript = os.path.join(mainScriptDir, 'mainscript.py') # noqa: PTH118, N806
35-
templateDir = os.getcwd() # noqa: PTH109, N806
36-
tmpSimCenterDir = str(Path(templateDir).parents[0]) # noqa: N806
37-
3833
# Change permission of driver file
3934
os.chmod(driverFile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IXOTH) # noqa: PTH101
4035
st = os.stat(driverFile) # noqa: PTH116
4136
os.chmod(driverFile, st.st_mode | stat.S_IEXEC) # noqa: PTH101
4237
driverFile = './' + driverFile # noqa: N806
43-
print('WORKFLOW: ' + driverFile) # noqa: T201
38+
39+
template_dir = Path.cwd()
40+
tmp_simcenter_dir = template_dir.parent
41+
42+
main_script_dir = Path(__file__).parent
43+
main_script = main_script_dir / 'mainscript.py'
4444

4545
command = (
46-
f'"{pythonCommand}" "{mainScript}" "{tmpSimCenterDir}"'
47-
f' "{templateDir}" {runType} {driverFile} {workflowInput}'
46+
f'"{pythonCommand}" "{main_script!s}" "{tmp_simcenter_dir!s}"'
47+
f' "{template_dir!s}" {runType} {driverFile} {workflowInput}'
4848
)
49+
4950
print(command) # noqa: T201
5051

5152
command_list = shlex.split(command)
5253

53-
err_file = Path(tmpSimCenterDir) / 'UCSD_UQ.err'
54+
err_file = tmp_simcenter_dir / 'UCSD_UQ.err'
5455
err_file.touch()
5556

5657
try:
Lines changed: 115 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,139 @@
1-
"""authors: Mukesh Kumar Ramancha, Maitreya Manoj Kurumbhati, Prof. J.P. Conte, Aakash Bangalore Satish*
2-
affiliation: University of California, San Diego, *SimCenter, University of California, Berkeley
3-
4-
""" # noqa: INP001, D205, D400
5-
6-
# ======================================================================================================================
1+
"""
2+
module: mainscript.py.
3+
4+
This script executes an uncertainty quantification (UQ) analysis based on an input JSON file.
5+
It dynamically selects the appropriate UQ method in the UCSD_UQ engine and executes the corresponding script.
6+
7+
### Functionality:
8+
- Adds the `common` directory to `sys.path` to allow importing necessary modules.
9+
- Parses command-line arguments for necessary paths and parameters.
10+
- Reads and validates the JSON input file.
11+
- Determines the appropriate UQ script to run based on `uqType` and `useApproximation` flags.
12+
- Constructs the command and executes the selected script.
13+
- Captures errors and logs them to `UCSD_UQ.err`.
14+
15+
### Usage:
16+
```sh
17+
python script.py /path/to/working /path/to/template runningLocal driver input.json
18+
```
19+
20+
### Arguments:
21+
1. `working_dir` (Path): Path to the working directory where computations are performed.
22+
2. `template_dir` (Path): Path to the template directory containing the input JSON file.
23+
3. `run_type` (str): Execution mode (`runningLocal` or `runningRemote`).
24+
4. `driver_file` (str): Name of the driver file.
25+
5. `input_file` (Path): Name of the JSON input file.
26+
27+
### Error Handling:
28+
- If an invalid JSON file is provided, the script exits with an error.
29+
- If an unknown UQ type is encountered, the script exits with an error.
30+
- If an exception occurs during execution, the error is logged in `UCSD_UQ.err`.
31+
32+
"""
33+
34+
import argparse
735
import json
8-
import shlex
936
import sys
1037
import traceback
1138
from pathlib import Path
1239

13-
path_to_common_uq = Path(__file__).parent.parent / 'common'
14-
sys.path.append(str(path_to_common_uq))
40+
# Dynamically add 'common' directory to sys.path
41+
path_to_common_uq = Path(__file__).resolve().parent.parent / 'common'
42+
if path_to_common_uq not in sys.path:
43+
sys.path.insert(0, str(path_to_common_uq))
1544

1645

17-
# ======================================================================================================================
18-
def main(input_args): # noqa: D103
19-
# # Initialize analysis
20-
# path_to_UCSD_UQ_directory = Path(input_args[2]).resolve().parent
21-
# path_to_working_directory = Path(input_args[3]).resolve()
22-
# path_to_template_directory = Path(input_args[4]).resolve()
23-
# run_type = input_args[5] # either "runningLocal" or "runningRemote"
24-
# driver_file_name = input_args[6]
25-
# input_file_name = input_args[7]
46+
def parse_args():
47+
"""Parse command-line arguments."""
48+
parser = argparse.ArgumentParser(description='Run UQ analysis.')
49+
parser.add_argument('working_dir', type=Path, help='Path to working directory')
50+
parser.add_argument('template_dir', type=Path, help='Path to template directory')
51+
parser.add_argument(
52+
'run_type', choices=['runningLocal', 'runningRemote'], help='Run type'
53+
)
54+
parser.add_argument('driver_file', help='Driver file name')
55+
parser.add_argument('input_file', type=Path, help='Input JSON file')
56+
return parser.parse_args()
57+
2658

27-
# Initialize analysis
28-
path_to_UCSD_UQ_directory = Path(input_args[0]).resolve().parent # noqa: N806, F841
29-
path_to_working_directory = Path(input_args[1]).resolve()
30-
path_to_template_directory = Path(input_args[2]).resolve()
31-
run_type = input_args[3] # either "runningLocal" or "runningRemote"
32-
driver_file_name = input_args[4]
33-
input_file_name = input_args[5]
59+
def load_json(file_path):
60+
"""Load and validate JSON input."""
61+
try:
62+
with file_path.open(encoding='utf-8') as f:
63+
data = json.load(f)
64+
except json.JSONDecodeError as e:
65+
sys.stderr.write(f'ERROR: Invalid JSON format in {file_path}:\n{e}\n')
66+
sys.exit(1)
3467

35-
Path('dakotaTab.out').unlink(missing_ok=True)
36-
Path('dakotaTabPrior.out').unlink(missing_ok=True)
68+
if 'UQ' not in data:
69+
sys.stderr.write(f"ERROR: Missing 'UQ' key in input JSON: {file_path}\n")
70+
sys.exit(1)
3771

38-
input_file_full_path = path_to_template_directory / input_file_name
72+
return data
3973

40-
with open(input_file_full_path, encoding='utf-8') as f: # noqa: PTH123
41-
inputs = json.load(f)
4274

43-
uq_inputs = inputs['UQ']
44-
if uq_inputs['uqType'] == 'Metropolis Within Gibbs Sampler':
45-
import mainscript_hierarchical_bayesian
75+
def select_uq_script(uq_inputs):
76+
"""Determine which UQ script to run."""
77+
uq_methods = {
78+
'Metropolis Within Gibbs Sampler': 'mainscript_hierarchical_bayesian',
79+
}
4680

47-
main_function = mainscript_hierarchical_bayesian.main
48-
else:
49-
import mainscript_tmcmc
81+
module_name = uq_methods.get(uq_inputs['uqType'], 'mainscript_tmcmc')
82+
if uq_inputs.get('useApproximation'):
83+
module_name = 'gp_ab_algorithm'
5084

51-
main_function = mainscript_tmcmc.main
85+
try:
86+
module = __import__(module_name)
87+
except ImportError:
88+
sys.stderr.write(
89+
f'ERROR: Could not import {module_name}. Ensure the script exists.\n'
90+
)
91+
sys.exit(1)
5292

53-
command = (
54-
f'"{path_to_working_directory}" "{path_to_template_directory}" '
55-
f'{run_type} "{driver_file_name}" "{input_file_full_path}"'
56-
)
57-
command_list = shlex.split(command)
93+
return module.main
5894

59-
# Check if 'UCSD_UQ.err' exists, and create it if not
60-
err_file = path_to_working_directory / 'UCSD_UQ.err'
6195

62-
if not err_file.exists():
63-
err_file.touch() # Create the file
96+
def main():
97+
"""Run UQ analysis."""
98+
args = parse_args()
99+
100+
# Ensure output error file exists
101+
err_file = args.working_dir / 'UCSD_UQ.err'
102+
err_file.touch(exist_ok=True)
103+
104+
# Remove any previous output files
105+
(args.working_dir / 'dakotaTab.out').unlink(missing_ok=True)
106+
(args.working_dir / 'dakotaTabPrior.out').unlink(missing_ok=True)
107+
108+
# Load JSON input file
109+
inputs = load_json(args.template_dir / args.input_file)
110+
uq_inputs = inputs['UQ']
111+
112+
# Select the appropriate UQ script
113+
main_function = select_uq_script(uq_inputs)
114+
115+
# Construct the command
116+
command = [
117+
str(args.working_dir),
118+
str(args.template_dir),
119+
args.run_type,
120+
args.driver_file,
121+
str(args.template_dir / args.input_file),
122+
]
64123

65-
# Try running the main_function and catch any exceptions
66124
try:
67-
main_function(command_list)
68-
except Exception: # noqa: BLE001
69-
# Write the exception message to the .err file
125+
main_function(command)
126+
except Exception:
127+
err_msg = f'ERROR: An exception occurred:\n{traceback.format_exc()}\n'
70128
with err_file.open('a') as f:
71-
f.write('ERROR: An exception occurred:\n')
72-
f.write(f'{traceback.format_exc()}\n')
129+
f.write(err_msg)
130+
sys.stderr.write(err_msg)
73131

132+
if args.run_type == 'runningRemote':
133+
from mpi4py import MPI
74134

75-
# ======================================================================================================================
135+
MPI.COMM_WORLD.Abort(1)
76136

77-
if __name__ == '__main__':
78-
input_args = sys.argv
79-
main(input_args)
80137

81-
# ======================================================================================================================
138+
if __name__ == '__main__':
139+
main()

modules/performUQ/common/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ simcenter_add_python_script(SCRIPT gp_ab_algorithm.py)
2323
simcenter_add_python_script(SCRIPT gp_model.py)
2424
simcenter_add_python_script(SCRIPT principal_component_analysis.py)
2525
simcenter_add_python_script(SCRIPT space_filling_doe.py)
26-
simcenter_add_python_script(SCRIPT tmcmc.py)
26+
simcenter_add_python_script(SCRIPT tmcmc.py)
27+
simcenter_add_python_script(SCRIPT safer_cholesky.py)
28+
simcenter_add_python_script(SCRIPT kernel_density_estimation.py)
29+
simcenter_add_python_script(SCRIPT config_utilities.py)
30+
simcenter_add_python_script(SCRIPT logging_utilities.py)
31+
simcenter_add_python_script(SCRIPT log_likelihood_functions.py)

0 commit comments

Comments
 (0)