Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opt mode #17

Merged
3 commits merged into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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