Skip to content

Commit

Permalink
Merge pull request #17 from PaulTalbot-INL/optz_option
Browse files Browse the repository at this point in the history
Opt mode
  • Loading branch information
abhinavg-INL authored Sep 9, 2020
2 parents 10a514b + f6b03a1 commit 30aa5fe
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 38 deletions.
18 changes: 10 additions & 8 deletions src/Cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ def get_input_specs(cls):
input_specs.addParam('name', param_type=InputTypes.StringType, required=True,
descr=r"""the name by which this analysis should be referred within HERON.""")

#mode_options = InputTypes.makeEnumType('ModeOptions', 'ModeOptionsType', ['opt', 'sweep'])
#desc_mode_options = r"""determines whether the outer RAVEN should perform optimization,
# or a parametric (``sweep'') study. \default{sweep}"""
#input_specs.addSub(InputData.parameterInputFactory('mode', contentType=mode_options,
# strictMode=True, descr=desc_mode_options))
mode_options = InputTypes.makeEnumType('ModeOptions', 'ModeOptionsType', ['opt', 'sweep'])
desc_mode_options = r"""determines whether the outer RAVEN should perform optimization,
or a parametric (``sweep'') study. \default{sweep}"""
input_specs.addSub(InputData.parameterInputFactory('mode', contentType=mode_options,
strictMode=True, descr=desc_mode_options))

# not yet implemented TODO
#econ_metrics = InputTypes.makeEnumType('EconMetrics', 'EconMetricsTypes', ['NPV', 'lcoe'])
Expand Down Expand Up @@ -130,11 +130,11 @@ def __init__(self, **kwargs):
"""
Base.__init__(self, **kwargs)
self.name = None # case name
self._mode = 'sweep' # extrema to find: min, max, sweep
self._metric = 'NPV' # economic metric to focus on: lcoe, profit, cost
self._mode = None # extrema to find: min, max, sweep
self._metric = 'NPV' # UNUSED (future work); economic metric to focus on: lcoe, profit, cost

self.dispatch_name = None # type of dispatcher to use
self.dispatcher = None # type of dispatcher to use
self.dispatcher = None # type of dispatcher to use

self._diff_study = None # is this only a differential study?
self._num_samples = 1 # number of ARMA stochastic samples to use ("denoises")
Expand Down Expand Up @@ -186,6 +186,8 @@ def read_input(self, xml):
self._increments[item.parameterValues['resource']] = item.value

# checks
if self._mode is None:
self.raiseAnError('No <mode> node was provided in the <Case> node!')
if self.dispatcher is None:
self.raiseAnError('No <dispatch> node was provided in the <Case> node!')
if self._time_discretization is None:
Expand Down
52 changes: 36 additions & 16 deletions templates/outer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
<RunInfo>
<JobName>EX19_Outer</JobName>
<WorkingDir>.</WorkingDir>
<Sequence>sweep</Sequence>
<Sequence></Sequence>
<batchSize>3</batchSize>
<!--<batchSize>20</batchSize>
<mode>mpi<runqsub/></mode>
<internalParallel>False</internalParallel>
Expand All @@ -15,11 +16,20 @@
<Input class='Files' type='raven' >inner_workflow</Input>
<Input class='Files' type='' >heron_lib</Input>
<Input class='Files' type='' >transfers</Input>
<!-- TODO model files for inner -->
<Model class='Models' type='Code' >raven</Model>
<Sampler class='Samplers' type='Grid' >grid</Sampler>
<Output class='DataObjects' type='PointSet'>grid</Output>
<Output class='OutStreams' type='Print' >sweep</Output>
<Output class='OutStreams' type='Print' >sweep</Output>
</MultiRun>
<MultiRun name="optimize">
<Input class='Files' type='raven' >inner_workflow</Input>
<Input class='Files' type='' >heron_lib</Input>
<Input class='Files' type='' >transfers</Input>
<Model class='Models' type='Code' >raven</Model>
<Optimizer class='Optimizers' type='FiniteDifference'>cap_opt</Optimizer>
<Output class='DataObjects' type='PointSet' >opt_eval</Output>
<SolutionExport class='DataObjects' type='PointSet' >opt_soln</SolutionExport>
<Output class='OutStreams' type='Print' >opt_soln</Output>
</MultiRun>
</Steps>

Expand All @@ -42,6 +52,14 @@
<Input>GRO_capacities</Input>
<Output>GRO_outer_results</Output>
</PointSet>
<PointSet name='opt_eval'>
<Input>GRO_capacities</Input>
<Output>mean_NPV</Output>
</PointSet>
<PointSet name='opt_soln'>
<Input>trajID</Input>
<Output>iteration, accepted, GRO_capacities, mean_NPV</Output>
</PointSet>
</DataObjects>

<Models>
Expand All @@ -64,38 +82,35 @@
</Grid>
</Samplers>

<!-- <Optimizers>
<Optimizers>
<GradientDescent name="cap_opt">
<objective>mean_NPV</objective>
<variable name="x">
<distribution>beale_dist</distribution>
<initial>-2</initial>
</variable>
<variable name="y">
<distribution>beale_dist</distribution>
<initial>-2</initial>
</variable>
<TargetEvaluation class="DataObjects" type="PointSet">cap_opt_eval</TargetEvaluation>
<!-- <variable> nodes filled by HERON -->
<constant name='denoises'>1</constant>
<TargetEvaluation class="DataObjects" type="PointSet">opt_eval</TargetEvaluation>
<samplerInit>
<limit>2000</limit>
<writeSteps>every</writeSteps>
<type>max</type>
</samplerInit>
<gradient>
<FiniteDifference/>
</gradient>
<stepSize>
<GradientHistory>
<growthFactor>1.25</growthFactor>
<shrinkFactor>1.5</shrinkFactor>
<growthFactor>2</growthFactor>
<shrinkFactor>2</shrinkFactor>
</GradientHistory>
</stepSize>
<acceptance>
<Strict/>
</acceptance>
<convergence>
<gradient>1e-2</gradient>
<objective>1e-2</objective>
</convergence>
</GradientDescent>
</Optimizers> -->
</Optimizers>

<Files>
<Input name="inner_workflow" type='raven'>inner.xml</Input>
Expand All @@ -108,5 +123,10 @@
<type>csv</type>
<source>grid</source>
</Print>
<Print name='opt_soln'>
<type>csv</type>
<source>opt_soln</source>
<clusterLabel>trajID</clusterLabel>
</Print>
</OutStreams>
</Simulation>
71 changes: 61 additions & 10 deletions templates/template_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ def _modify_outer(self, template, case, components, sources):
@ In, sources, list, list of HERON Placeholder instances for this run
@ Out, template, xml.etree.ElementTree.Element, modified template
"""
self._modify_outer_mode(template, case)
self._modify_outer_runinfo(template, case)
self._modify_outer_vargroups(template, components)
self._modify_outer_files(template, sources)
Expand All @@ -190,6 +191,44 @@ def _modify_outer(self, template, case, components, sources):
# TODO including the heron library file
return template

def _modify_outer_mode(self, template, case):
"""
Defines modifications throughout outer.xml RAVEN input file due to "sweep" or "opt" mode.
@ In, template, xml.etree.ElementTree.Element, root of XML to modify
@ In, case, HERON Case, defining Case instance
@ Out, None
"""
if case._mode == 'opt':
# RunInfo
template.find('RunInfo').find('Sequence').text = 'optimize'
# Steps
sweep = template.find('Steps').findall('MultiRun')[0]
template.find('Steps').remove(sweep)
# DataObjects
grid = template.find('DataObjects').findall('PointSet')[0]
template.find('DataObjects').remove(grid)
# Samplers
template.remove(template.find('Samplers'))
# OutStreams
sweep = template.find('OutStreams').findall('Print')[0]
template.find('OutStreams').remove(sweep)
else: # mode is 'sweep'
# RunInfo
template.find('RunInfo').find('Sequence').text = 'sweep'
# Steps
opt = template.find('Steps').findall('MultiRun')[1]
template.find('Steps').remove(opt)
# DataObjects
opt_eval = template.find('DataObjects').findall('PointSet')[1]
opt_soln = template.find('DataObjects').findall('PointSet')[2]
template.find('DataObjects').remove(opt_eval)
template.find('DataObjects').remove(opt_soln)
# Optimizers
template.remove(template.find('Optimizers'))
# OutStreams
opt_soln = template.find('OutStreams').findall('Print')[1]
template.find('OutStreams').remove(opt_soln)

def _modify_outer_runinfo(self, template, case):
"""
Defines modifications to the RunInfo of outer.xml RAVEN input file.
Expand Down Expand Up @@ -265,7 +304,10 @@ def _modify_outer_samplers(self, template, case, components):
"""
""" TODO """
dists_node = template.find('Distributions')
samps_node = template.find('Samplers').find('Grid')
if case._mode == 'sweep':
samps_node = template.find('Samplers').find('Grid')
else:
samps_node = template.find('Optimizers').find('GradientDescent')
# number of denoisings
## assumption: first node is the denoises node
samps_node.find('constant').text = str(case._num_samples)
Expand All @@ -285,9 +327,12 @@ def _modify_outer_samplers(self, template, case, components):
# is the capacity variable being swept over?
if isinstance(vals, list):
# make new Distribution, Sampler.Grid.variable
dist, samp = self._create_new_sweep_capacity(name, var_name, vals)
dist, for_grid, for_opt = self._create_new_sweep_capacity(name, var_name, vals)
dists_node.append(dist)
samps_node.append(samp)
if case._mode == 'sweep':
samps_node.append(for_grid)
else:
samps_node.append(for_opt)
# NOTE assumption (input checked): only one interaction per component
# if not being swept, then it's just a fixed value.
else:
Expand All @@ -303,20 +348,26 @@ def _create_new_sweep_capacity(self, comp_name, var_name, capacities):
@ In, var_name, str, name of capacity variable
@ In, capacities, list, float list of capacities to sweep/opt over
@ Out, dist, xml.etree.ElementTree,Element, XML for distribution
@ Out, samp, xml.etree.ElementTree,Element, XML for sampler variable
@ Out, grid, xml.etree.ElementTree,Element, XML for grid sampler variable
@ Out, opt, xml.etree.ElementTree,Element, XML for optimizer variable
"""
# distribution
dist_name = self.namingTemplates['distribution'].format(unit=comp_name, feature='capacity')
dist = copy.deepcopy(self.dist_template)
dist.attrib['name'] = dist_name
dist.find('lowerBound').text = str(min(capacities))
dist.find('upperBound').text = str(max(capacities))
# sampler variable
samp = copy.deepcopy(self.var_template)
samp.attrib['name'] = var_name
samp.find('distribution').text = dist_name
samp.find('grid').text = ' '.join(str(x) for x in sorted(capacities))
return dist, samp
# sampler variable, for Grid case
grid = copy.deepcopy(self.var_template)
grid.attrib['name'] = var_name
grid.find('distribution').text = dist_name
grid.find('grid').text = ' '.join(str(x) for x in sorted(capacities))
# optimizer variable, for opt case
opt = copy.deepcopy(grid)
opt.remove(opt.find('grid'))
initial = np.average(capacities)
opt.append(xmlUtils.newNode('initial', text=initial))
return dist, grid, opt

##### INNER #####
def _modify_inner(self, template, case, components, sources):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

<Case name="Sweep_Runs">
<!--
<mode>sweep</mode>
<metric>NPV</metric>
-->
<mode>sweep</mode>
<num_arma_samples>2</num_arma_samples>
<time_discretization>
<time_variable>Time</time_variable>
Expand Down
1 change: 1 addition & 0 deletions tests/integration_tests/production_flex/heron_input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</TestInfo>

<Case name="Sweep_Runs">
<mode>sweep</mode>
<num_arma_samples>10</num_arma_samples>
<time_discretization>
<time_variable>Time</time_variable>
Expand Down
2 changes: 1 addition & 1 deletion tests/integration_tests/production_flex/tests
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Tests]
[./Production_Flex]
[./ProductionFlex]
type = HeronIntegration
input = heron_input.xml
# prereq = SineArma
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
trajID,filename
0,opt_soln_0.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
iteration,accepted,steamer_capacity,generator_capacity,electr_market_capacity,electr_flex_capacity,mean_NPV
0.0,first,5.5,-100.0,-2.0,-2025.0,56.8233159522
1.0,accepted,4.86360389693,-100.0,-2.0,-2025.0,58.4129319302
2.0,accepted,4.22720779386,-100.0,-2.0,-2025.0,60.002548875
3.0,rejected,2.95441558773,-100.0,-2.0,-2025.0,44.7372957613
4.0,rerun,4.22720779386,-100.0,-2.0,-2025.0,60.002548875
5.0,rejected,3.5908116908,-100.0,-2.0,-2025.0,54.3739345853
6.0,rerun,4.22720779386,-100.0,-2.0,-2025.0,60.002548875
7.0,rejected,3.90900974233,-100.0,-2.0,-2025.0,59.1922570259
8.0,rerun,4.22720779386,-100.0,-2.0,-2025.0,60.002548875
9.0,accepted,4.0681087681,-100.0,-2.0,-2025.0,60.3999531626
10.0,rejected,3.74991071656,-100.0,-2.0,-2025.0,56.7830973199
11.0,rerun,4.0681087681,-100.0,-2.0,-2025.0,60.3999531626
12.0,rejected,3.90900974233,-100.0,-2.0,-2025.0,59.1922570259
13.0,rerun,4.0681087681,-100.0,-2.0,-2025.0,60.3999531626
14.0,rejected,3.98855925521,-100.0,-2.0,-2025.0,60.3968353646
15.0,rerun,4.0681087681,-100.0,-2.0,-2025.0,60.3999531626
Loading

0 comments on commit 30aa5fe

Please sign in to comment.