Skip to content

Commit f93d867

Browse files
Merge pull request #143 from rosswhitfield/dakota
Get IPS dakota working again
2 parents b47d2ef + 124233d commit f93d867

File tree

11 files changed

+251
-28
lines changed

11 files changed

+251
-28
lines changed

ipsframework/ips.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,30 @@ def run(self):
539539
self.event_service._print_stats()
540540
return True
541541

542+
def initiate_new_simulation(self, sim_name):
543+
'''
544+
This is to be called by the configuration manager as part of dynamically creating
545+
a new simulation. The purpose here is to initiate the method invocations for the
546+
framework-visible components in the new simulation
547+
'''
548+
comp_list = self.config_manager.get_simulation_components(sim_name)
549+
msg_list = []
550+
self._send_monitor_event(sim_name, 'IPS_START', 'Starting IPS Simulation', ok=True)
551+
self._send_dynamic_sim_event(sim_name=sim_name, event_type='IPS_START')
552+
for comp_id in comp_list:
553+
for method in ['init', 'step', 'finalize']:
554+
req_msg = ServiceRequestMessage(self.component_id,
555+
self.component_id, comp_id,
556+
'init_call', method, 0)
557+
msg_list.append(req_msg)
558+
559+
# send off first round of invocations...
560+
msg = msg_list.pop(0)
561+
self.debug('Framework sending message %s ', msg.__dict__)
562+
call_id = self.task_manager.init_call(msg, manage_return=False)
563+
self.call_queue_map[call_id] = msg_list
564+
self.outstanding_calls_list.append(call_id)
565+
542566
def _send_monitor_event(self, sim_name='', eventType='', comment='', ok='True'):
543567
"""
544568
Publish a portal monitor event to the *_IPS_MONITOR* event topic.

ipsframework/ips_dakota_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ def run(self):
101101

102102

103103
def main(argv=None):
104-
in_file = argv[1]
105-
out_file = argv[2]
104+
in_file = sys.argv[1]
105+
out_file = sys.argv[2]
106106
debug = False
107107
log_file_name = None
108108
try:
@@ -126,4 +126,4 @@ def main(argv=None):
126126

127127
if __name__ == "__main__":
128128
sys.stdout.flush()
129-
sys.exit(main(sys.argv))
129+
sys.exit(main())

ipsframework/ips_dakota_dynamic.py

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#! /usr/bin/env python
1+
#!/usr/bin/env python
22
# -------------------------------------------------------------------------------
33
# Copyright 2006-2021 UT-Battelle, LLC. See LICENSE for more information.
44
# -------------------------------------------------------------------------------
@@ -89,10 +89,6 @@ def run(self): # noqa: C901
8989
if k not in list(self.template_conf.keys()) and not any(x in v for x in '{}()$'):
9090
self.template_conf[k] = v
9191

92-
alt_paths.append(self.template_conf['IPS_ROOT'])
93-
alt_paths.append(os.path.join(self.template_conf['IPS_ROOT'], 'bin'))
94-
alt_paths.append(os.path.join(self.template_conf['IPS_ROOT'], 'framework/src'))
95-
9692
new_dakota_config = self.dakota_cfg + '.resolved'
9793
comp_vars = {}
9894
for line in self.dakota_conf:
@@ -113,7 +109,7 @@ def run(self): # noqa: C901
113109
elif tokens[0] == 'analysis_driver':
114110
raw_prog = line.split('=')[1]
115111
prog = raw_prog.strip(' "\'')
116-
exec_prog = which(prog, alt_paths)
112+
exec_prog = which(prog)
117113
if not exec_prog:
118114
raise Exception('Error: analysis driver %s not found in path' % prog)
119115
line.replace(prog, exec_prog)
@@ -136,23 +132,13 @@ def run(self): # noqa: C901
136132
driver_conf['SUB_CLASS'] = 'BRIDGE'
137133
driver_conf['NAME'] = 'Driver'
138134
driver_conf['NPROC'] = 1
139-
driver_conf['BIN_PATH'] = os.path.join(self.template_conf['IPS_ROOT'], 'bin')
135+
driver_conf['BIN_PATH'] = ''
140136
driver_conf['BIN_DIR'] = driver_conf['BIN_PATH']
141137
driver_conf['INPUT_DIR'] = '/dev/null'
142138
driver_conf['INPUT_FILES'] = ''
143139
driver_conf['OUTPUT_FILES'] = ''
144-
script = os.path.join(self.template_conf['IPS_ROOT'],
145-
'bin', 'dakota_bridge.py')
146-
if os.path.isfile(script):
147-
driver_conf['SCRIPT'] = script
148-
else:
149-
script = os.path.join(self.template_conf['IPS_ROOT'], 'framework',
150-
'src', 'dakota_bridge.py')
151-
if os.path.isfile(script):
152-
driver_conf['SCRIPT'] = script
153-
else:
154-
raise Exception('Error: unable to locate dakota_bridge.py in \
155-
IPS_ROOT/bin or IPS_ROOT/framework/src')
140+
driver_conf['SCRIPT'] = ""
141+
driver_conf['MODULE'] = 'ipsframework.dakota_bridge'
156142
self.master_conf['DAKOTA_BRIDGE'] = driver_conf
157143

158144
for comp in comp_vars:
@@ -200,16 +186,16 @@ def run(self): # noqa: C901
200186
if not os.path.isfile(self.restart_file):
201187
raise Exception("Error accessing DAKOTA restart file %s" % (self.restart_file))
202188

203-
cmd = '%s --all --simulation=%s --platform=%s --verbose' % (ips, self.master_conf.filename,
204-
os.environ['IPS_DAKOTA_platform'])
189+
cmd = '%s --simulation=%s --platform=%s --verbose' % (ips, self.master_conf.filename,
190+
os.environ['IPS_DAKOTA_platform'])
205191
if self.log_file:
206192
cmd += ' --log=' + self.log_file
207193

208194
if self.debug:
209195
cmd += ' --debug'
210196

211197
print('cmd =', cmd)
212-
ips_server_proc = subprocess.Popen(cmd)
198+
ips_server_proc = subprocess.Popen(cmd.split())
213199
print('%s Launched IPS' % (time.strftime("%b %d %Y %H:%M:%S", time.localtime())))
214200
sys.stdout.flush()
215201
msg = {'SIMSTATUS': 'START'}
@@ -240,7 +226,7 @@ def run(self): # noqa: C901
240226
else:
241227
command = 'dakota %s ' % new_dakota_config
242228
dakota_logfile = open('dakota_%s.log' % (str(os.getpid())), 'w')
243-
proc = subprocess.Popen(command, stdout=dakota_logfile, stderr=subprocess.STDOUT)
229+
proc = subprocess.Popen(command.split(), stdout=dakota_logfile, stderr=subprocess.STDOUT)
244230
print('%s Launched DAKOTA' % (time.strftime("%b %d %Y %H:%M:%S", time.localtime())))
245231
sys.stdout.flush()
246232
proc.wait()

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ omit =
2222
*/configobj.py
2323
*/six.py
2424
*/_version.py
25-
*/*dakota*
2625
*/utils/HTML.py
2726

2827
[versioneer]

setup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
packages=find_packages(),
4545
entry_points={
4646
'console_scripts': [
47-
'ips.py = ipsframework.ips:main'
47+
'ips.py = ipsframework.ips:main',
48+
'ips_dakota_dynamic.py = ipsframework.ips_dakota_dynamic:main',
49+
'ips_dakota_client.py = ipsframework.ips_dakota_client:main'
4850
]
4951
},
5052
classifiers=[

tests/dakota/README

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
To run this test manually do:
2+
ips_dakota_dynamic.py --dakotaconfig=dakota_test_Rosenbrock.in --simulation=dakota_test_Rosenbrock.ips --platform=workstation.conf
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# DAKOTA INPUT FILE - dakota_rosenbrock_syscall.in
2+
3+
strategy
4+
single_method
5+
graphics
6+
tabular_graphics_data
7+
8+
method
9+
conmin_frcg
10+
max_iterations = 100
11+
convergence_tolerance = 1e-4
12+
speculative
13+
14+
model
15+
single
16+
17+
variables
18+
continuous_design = 2
19+
initial_point 0.5 1.0
20+
lower_bounds 0.0 0.0
21+
upper_bounds 2.0 2.0
22+
descriptors 'ROSE__X1' "ROSE__X2"
23+
24+
interface
25+
fork asynchronous evaluation_concurrency = 10, file_tag, file_save
26+
analysis_driver = 'ips_dakota_client.py'
27+
parameters_file = 'params.in'
28+
results_file = 'results.out'
29+
30+
responses
31+
num_objective_functions = 1
32+
numerical_gradients
33+
method_source dakota
34+
interval_type forward
35+
fd_gradient_step_size = 1.e-5
36+
no_hessians
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
RUN_ID = DAKOTA_Rosenbrock # Identifier for this simulation run
2+
TOKAMAK_ID = TEST
3+
SHOT_NUMBER = 1 # Numerical identifier for specific case
4+
5+
SIM_NAME = ${RUN_ID}_${TOKAMAK_ID}_${SHOT_NUMBER} # Name of current simulation
6+
SIM_ROOT = $PWD/${SIM_NAME} # Where to put results from this simulation
7+
8+
LOG_FILE = $SIM_ROOT/${RUN_ID}.log
9+
LOG_LEVEL = DEBUG
10+
11+
SIMULATION_MODE = NORMAL
12+
13+
# A run comment picked up by the portal
14+
RUN_COMMENT = Testing dakota
15+
16+
# Specification of plasma state files
17+
18+
# Where to put plasma state files as the simulation evolves
19+
PLASMA_STATE_WORK_DIR = $SIM_ROOT/work/plasma_state
20+
21+
# Specify what files constitute the plasma state - N.B. not all components need all files
22+
PLASMA_STATE_FILES =
23+
24+
# Names of ports to be used. An implementation and configuration must be specified for
25+
# each port
26+
27+
[PORTS]
28+
NAMES = DRIVER
29+
30+
# DRIVER port is called by the framework. It is required, causes exception.
31+
32+
[[DRIVER]] # REQUIRED Port section
33+
IMPLEMENTATION = ROSE
34+
35+
# INIT port is called by the framework. It typically produces the very first set of
36+
# plasma state files for SIMULATION_MODE = NORMAL. It does not raise and exception
37+
# if missing.
38+
39+
[[INIT]]
40+
IMPLEMENTATION =
41+
42+
# Specification of IMPLEMENTATION for each physics port called out in PORTS list.
43+
# Additional specifications may be present that are not in the PORTS list
44+
45+
# Specification of configuration for each port called out in PORTS list.
46+
# Additional specifications may be present that are not in the PORTS list
47+
# NAME variable MUST match the name of the python class that implements the component
48+
49+
[ROSE]
50+
CLASS = DAKOTA
51+
SUB_CLASS = TEST
52+
NAME = ResenbrockDriver
53+
NPROC = 1
54+
BIN_PATH =
55+
INPUT_DIR =
56+
INPUT_FILES =
57+
OUTPUT_FILES =
58+
SCRIPT = $PWD/dakota_test_Rosenbrock.py
59+
60+
# Time loop specification (two modes for now) EXPLICIT | REGULAR
61+
# For MODE = REGULAR, the framework uses the variables START, FINISH, and NSTEP
62+
# For MODE = EXPLICIT, the frame work uses the variable VALUES (space separated list of time values)
63+
64+
[TIME_LOOP]
65+
MODE = REGULAR
66+
START = 0
67+
FINISH = 10
68+
NSTEP = 10
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# -------------------------------------------------------------------------------
2+
# Copyright 2006-2012 UT-Battelle, LLC. See LICENSE for more information.
3+
# -------------------------------------------------------------------------------
4+
import os
5+
from ipsframework import Component
6+
7+
8+
class ResenbrockDriver(Component):
9+
10+
def __init__(self, services, config):
11+
Component.__init__(self, services, config)
12+
13+
def init(self, timestamp=0):
14+
print('init from dakota test driver')
15+
16+
def step(self, timestamp=0):
17+
print('step from dakota test driver')
18+
services = self.services
19+
services.stage_input_files(self.INPUT_FILES)
20+
x1 = float(self.X1)
21+
x2 = float(self.X2)
22+
sim_root = services.get_config_param('SIM_ROOT')
23+
result = 100.0 * (x2 - x1 * x1) * (x2 - x1 * x1) + (1. - x1) * (1. - x1)
24+
out_file = os.path.join(sim_root, 'RESULT')
25+
open(out_file, 'w').write('%.9f f' % (result))
26+
return
27+
28+
def finalize(self, timestamp=0):
29+
print('finalize from dakota test driver')

tests/dakota/test_dakota.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from ipsframework.ips_dakota_dynamic import DakotaDynamic
2+
import os
3+
import shutil
4+
import pytest
5+
import glob
6+
7+
8+
def copy_config_and_replace(infile, outfile, tmpdir):
9+
with open(infile, "r") as fin:
10+
with open(outfile, "w") as fout:
11+
for line in fin:
12+
if "SCRIPT" in line:
13+
fout.write(line.replace("$PWD", str(tmpdir)))
14+
elif line.startswith("SIM_ROOT"):
15+
fout.write(f"SIM_ROOT = {tmpdir}/$SIM_NAME\n")
16+
else:
17+
fout.write(line)
18+
19+
20+
@pytest.mark.skipif(shutil.which('dakota') is None,
21+
reason="Requires dakota to run this test")
22+
def test_dakota(tmpdir):
23+
data_dir = os.path.dirname(__file__)
24+
copy_config_and_replace(os.path.join(data_dir, "dakota_test_Rosenbrock.ips"), tmpdir.join("dakota_test_Rosenbrock.ips"), tmpdir)
25+
shutil.copy(os.path.join(data_dir, "workstation.conf"), tmpdir)
26+
shutil.copy(os.path.join(data_dir, "dakota_test_Rosenbrock.in"), tmpdir)
27+
shutil.copy(os.path.join(data_dir, "dakota_test_Rosenbrock.py"), tmpdir)
28+
29+
os.chdir(tmpdir)
30+
31+
sweep = DakotaDynamic(dakota_cfg=os.path.join(tmpdir, "dakota_test_Rosenbrock.in"),
32+
log_file=str(tmpdir.join('test.log')),
33+
platform_filename=os.path.join(tmpdir, "workstation.conf"),
34+
debug=False,
35+
ips_config_template=os.path.join(tmpdir, "dakota_test_Rosenbrock.ips"),
36+
restart_file=None)
37+
sweep.run()
38+
39+
# check dakota log
40+
log_file = glob.glob(str(tmpdir.join("dakota_*.log")))[0]
41+
with open(log_file, 'r') as f:
42+
lines = f.readlines()
43+
44+
X1, X2 = lines[-22].split()[1:]
45+
46+
assert float(X1) == pytest.approx(1, rel=1e-3)
47+
assert float(X2) == pytest.approx(1, rel=1e-3)

0 commit comments

Comments
 (0)