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

Modified creation of cyclus input from PRIS data #115

Merged
merged 31 commits into from
Jan 13, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
596fa88
inputs/current_us.xml
Nov 10, 2020
89f5ca9
created notebook for analysis
Nov 10, 2020
5476d46
Pulled in templates from predicting-the-past repo
Nov 10, 2020
89108ea
getting MemoryError using 2016 data output file
Jan 6, 2021
a108494
added script to create cyclus input from raw PRIS data
Jan 8, 2021
92abc00
changed write_reactors to match unites_states.ipynb
Jan 8, 2021
0aac6ae
modified render_cyclus to match united_states.ipynb
Jan 8, 2021
4cd9c10
works with 2016 database
Jan 8, 2021
4268acd
added save_output function from merge_coordinates
Jan 8, 2021
2a2fcc5
changed reactor power cap, some path names to haleu directory
Jan 8, 2021
f419424
mostly working
Jan 8, 2021
982d2bf
fixed connection date of reactors
Jan 11, 2021
e2de78f
creates input that runs and produces non-empty sqlite file
Jan 11, 2021
8831068
pulled user specifications to beginning
Jan 11, 2021
cd81e1a
removed old input
Jan 11, 2021
34b83c8
added comment
Jan 11, 2021
6b6a9c9
updated countries in select_region
Jan 11, 2021
9d35d38
removed renaming of USA
Jan 11, 2021
8cd9940
changed not_null to '' to remove lines with country totals
Jan 11, 2021
88f9d2d
returning to current state on master branch
Jan 11, 2021
74892bc
pep8 fixes
Jan 11, 2021
c23c968
modified to include merge_coordiantes function
Jan 11, 2021
dc80ceb
added liquid format back in
Jan 11, 2021
9add92d
changed import_pris to column names instead of numbers
Jan 11, 2021
90da11c
DRY suggestion from @katyhuff
Jan 11, 2021
24f1846
pep8 fixes
Jan 11, 2021
1578509
removed magic numbers
Jan 12, 2021
1b9cd1a
reorganized variables
Jan 12, 2021
c45b0ca
modified paths, removal of magic numbers doesn't work
Jan 12, 2021
18c4938
changed intermediate reactor data containers to dataframes
Jan 12, 2021
f9b63d5
added out_file for produce_recipes, pep8 fixes
Jan 13, 2021
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
330 changes: 330 additions & 0 deletions input/haleu/analysis/current-us-analysis.ipynb

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions input/predicting-the-past/templates/recipes_template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@
</recipe>
<recipe>
<name>cool_spent_uox</name>
<basis>atom</basis>
<basis>mass</basis>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like something that should be user specified.
E.g. allow for options when running create_input.py like

python create_input.py -a  # for atom basis

pyhton create_input.py -m # for mass basis

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as the IAEA PRIS database is on a mass basis, this is fine. @abachma2 feel free to resolve this conversation if that's the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recipe data doesn't come from PRIS. It comes from the vision recipes in database/vision_recipes/. I don't know where that data came from originally.

{% for key, value in spent.items() -%}
<nuclide> <id>{{ key }}</id> <comp>{{ value }}</comp> </nuclide>
{% endfor -%}
</recipe>
<recipe>
<name>casked_spent_uox</name>
<basis>atom</basis>
<basis>mass</basis>
{% for key, value in spent.items() -%}
<nuclide> <id>{{ key }}</id> <comp>{{ value }}</comp> </nuclide>
{% endfor -%}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,4 @@
<xi:include href="united_states/buildtimes/{{country}}/deployinst.xml"/></config>
</institution>{% endfor %}</region>
<xi:include href="united_states/recipes/uox_{{burnup}}.xml#xpointer(/recipes/child::*)"/>
</simulation>
</simulation>
2 changes: 1 addition & 1 deletion input/predicting-the-past/united_states.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1640,7 +1640,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
"version": "3.6.11"
},
"varInspector": {
"cols": {
Expand Down
55 changes: 55 additions & 0 deletions scripts/create_input.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import pandas as pd
import sys

import predicting_the_past_import as import_data

# user defined characteristics of cyclus simulation
data_year = 2020
start_year = 1965
region = 'united_states'
project = 'haleu'
katyhuff marked this conversation as resolved.
Show resolved Hide resolved

import_data.merge_coordinates('../database/Year-end Reactor Status_' + str(data_year) + '.csv',
'../database/coordinates.sqlite', data_year)

pris_file = '../database/reactors_pris_' + str(data_year) + '.csv'
deployinst_tmpl = '../input/predicting-the-past/templates/' + \
region + '/deployinst_template.xml'
inclusions_tmpl = '../input/predicting-the-past/templates/inclusions_template.xml'
deployment_path = '../input/' + project + '/inputs/' + region + '/buildtimes'
reactor_path = '../input/' + project + '/inputs/' + region + '/reactors'
reactor_template = '../input/predicting-the-past/templates/reactors_template.xml'


pris = import_data.import_csv(pris_file)


recipes = import_data.import_csv('../database/vision_recipes/uox.csv', ',')
recipe_template = import_data.load_template(
'../input/predicting-the-past/templates/recipes_template.xml')
burnups = [33, 51, 100]
for bu in burnups:
fresh = import_data.get_composition_fresh(recipes, bu)
spent = import_data.get_composition_spent(recipes, bu)
import_data.write_recipes(fresh, spent, recipe_template, bu, region)

reactor_list = import_data.select_region(pris, region)
import_data.write_reactors(
reactor_list,
reactor_path,
reactor_template,
18,
1) # change cycle and refuel time
buildtime = import_data.deploy_reactors(pris_file, region, start_year, deployinst_tmpl,
inclusions_tmpl, reactor_path, deployment_path)

cyclus_tmpl = ('../input/predicting-the-past/templates/' +
region + '/' + region + '_template.xml')
import_data.render_cyclus(
cyclus_tmpl,
region,
buildtime,
'../input/' +
project +
'/inputs/',
51) # change burn up
114 changes: 82 additions & 32 deletions scripts/predicting_the_past_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ def import_pris(pris_link):
"""
pris = pd.read_csv(pris_link,
delimiter=',',
encoding='iso-8859-1'
encoding='iso-8859-1',
skiprows=20,
)
pris.insert(13, 'Latitude', np.nan)
pris.insert(14, 'Longitude', np.nan)

pris = pris.rename(columns={pris.columns[2]: 'Country'})
pris = pris[['Country', 'Unit', 'Current Status', 'Type',
abachma2 marked this conversation as resolved.
Show resolved Hide resolved
'Model', 'Operator', 'Reactor Supplier', 'Const. Date',
'Grid Date', 'Shutdown Date', 'RUP [MWe]']]
pris.insert(11, 'Latitude', np.nan)
pris.insert(12, 'Longitude', np.nan)
pris = pris[pris.Unit.notnull()]
pris = pris[pris.Unit != 'Unit']
pris = pris.replace(np.nan, '')
return pris

Expand Down Expand Up @@ -172,7 +180,7 @@ def is_int(str):
return answer


def merge_coordinates(pris_link, scrape_link):
def merge_coordinates(pris_link, scrape_link, data_year):
""" Obtains coordinates from webscrape.sqlite and
writes them to matching reactors in PRIS reactor file.

Expand All @@ -182,6 +190,8 @@ def merge_coordinates(pris_link, scrape_link):
path and name of pris reactor text file
scrape: str
path and name of webscrape sqlite file
data_year: int
year the data is pulled from

Returns
-------
Expand All @@ -196,20 +206,45 @@ def merge_coordinates(pris_link, scrape_link):
webscrape_name = sanitize_webscrape_name(web['name'])
pris_name = sanitize_pris_name(prs[1])
if fuzz.ratio(webscrape_name, pris_name) > 78:
prs[13] = web['lat']
prs[14] = web['long']
prs[11] = web['lat']
prs[12] = web['long']
else:
for other in others.keys():
edge_case_key = other.lower()
edge_case_value = others[other].lower()
if fuzz.ratio(pris_name, edge_case_key) > 80:
if fuzz.ratio(webscrape_name, edge_case_value) > 75:
prs[13] = web['lat']
prs[14] = web['long']
pris.to_csv('reactors_pris_2016.csv', index=False, sep=',')
prs[11] = web['lat']
prs[12] = web['long']
pris.to_csv(
'../database/reactors_pris_' +
str(data_year) +
'.csv',
index=False,
sep=',')


def save_output(pris, data_year):
""" Saves updated PRIS database as 'reactors_pris_2016.csv'

Parameters
----------
pris: pd.DataFrame
updated PRIS database with latitude and longitude info
data_year: int
year the data is pulled from

Returns
-------

"""
pris.to_csv('../database/reactors_pris_' + str(data_year) + '.csv',
index=False,
sep=',',
)


def import_csv(in_csv, delimit):
def import_csv(in_csv, delimit=','):
""" Imports contents of a csv text file to a list of
lists.

Expand Down Expand Up @@ -314,7 +349,8 @@ def get_composition_spent(in_list, burnup):
return data_dict


def write_recipes(fresh_dict, spent_dict, in_template, burnup, region):
def write_recipes(fresh_dict, spent_dict, in_template,
burnup, region='united_states'):
""" Renders jinja template using fresh and spent fuel composition.

Parameters
Expand All @@ -335,7 +371,7 @@ def write_recipes(fresh_dict, spent_dict, in_template, burnup, region):
null
generates recipe files for cyclus.
"""
out_path = 'cyclus/input/' + region + '/recipes/'
out_path = '../input/haleu/inputs/' + region + '/recipes/'
pathlib.Path(out_path).mkdir(parents=True, exist_ok=True)
rendered = in_template.render(fresh=fresh_dict,
spent=spent_dict)
Expand Down Expand Up @@ -389,7 +425,7 @@ def confirm_deployment(date_str, capacity):
try:
date.parse(date_str)
is_deployed = True
except:
except BaseException:
pass
return is_deployed

Expand All @@ -410,21 +446,24 @@ def select_region(in_list, region):
reactor_list: list
list of reactors from PRIS
"""
ASIA = {'IRAN', 'JAPAN', 'KAZAKHSTAN',
ASIA = {'IRAN, ISLAMIC REPUBLIC OF', 'JAPAN',
'KAZAKHSTAN',
'BANGLADESH', 'CHINA', 'INDIA',
'UNITED ARAB EMIRATES', 'VIETNAM',
'PAKISTAN', 'PHILIPPINES', 'SOUTH KOREA'
'PAKISTAN', 'PHILIPPINES', 'KOREA, REPUBLIC OF',
'KAZAKHSTAN', 'ARMENIA', 'TAIWAM. CHINA'
}
UNITED_STATES = {'UNITED STATES'}
UNITED_STATES = {'UNITED STATES OF AMERICA'}
SOUTH_AMERICA = {'ARGENTINA', 'BRAZIL'}
NORTH_AMERICA = {'CANADA', 'MEXICO', 'UNITED STATES'}
NORTH_AMERICA = {'CANADA', 'MEXICO', 'UNITED STATES OF AMERICA'}
EUROPE = {'UKRAINE', 'UNITED KINGDOM',
'POLAND', 'ROMANIA', 'RUSSIA',
'BELARUS', 'BELGIUM', 'BULGARIA',
'GERMANY', 'ITALY', 'NETHERLANDS',
'SWEDEN', 'SWITZERLAND', 'TURKEY',
'SLOVENIA', 'SOVIET UNION', 'SPAIN',
'CZECHOSLOVAKIA', 'FINLAND', 'FRANCE'
'CZECH REPUBLIC', 'FINLAND', 'FRANCE',
'SLOVAKIA', 'HUNGARY', 'LITHUANIA'
}
AFRICA = {'EGYPT', 'MOROCCO', 'SOUTH AFRICA', 'TUNISIA'}
ALL = (SOUTH_AMERICA | NORTH_AMERICA |
Expand All @@ -442,8 +481,8 @@ def select_region(in_list, region):
for row in in_list:
country = row[0]
if country.upper() in regions[region.upper()]:
capacity = row[3]
start_date = row[10]
capacity = row[10]
start_date = row[8]
abachma2 marked this conversation as resolved.
Show resolved Hide resolved
if confirm_deployment(start_date, capacity):
reactor_list.append(row)
return reactor_list
Expand All @@ -465,8 +504,8 @@ def get_lifetime(in_row):
lifetime: int
lifetime of reactor
"""
comm_date = in_row[10]
shutdown_date = in_row[11]
comm_date = in_row[8]
shutdown_date = in_row[9]
if not shutdown_date.strip():
return 720
else:
Expand All @@ -475,7 +514,8 @@ def get_lifetime(in_row):
return int(delta / n_days_month)


def write_reactors(in_list, out_path, reactor_template):
def write_reactors(in_list, out_path, reactor_template,
cycle_time=18, refuel_time=1):
""" Renders CYCAMORE::reactor specifications using jinja2.

Parameters
Expand All @@ -486,6 +526,10 @@ def write_reactors(in_list, out_path, reactor_template):
output path for reactor files
reactor_template: str
path to reactor template
cycle_time: int
cycle length of reactors in months
refuel_time: int
average refuel time in months

Returns
-------
Expand All @@ -497,15 +541,15 @@ def write_reactors(in_list, out_path, reactor_template):
pathlib.Path(out_path).mkdir(parents=True, exist_ok=True)
reactor_template = load_template(reactor_template)
for row in in_list:
capacity = float(row[3])
capacity = float(row[10])
if capacity >= 400:
name = row[1].replace(' ', '_')
assem_per_batch = 0
assem_no = 0
assem_size = 0
reactor_type = row[2]
latitude = row[13] if row[13] != '' else 0
longitude = row[14] if row[14] != '' else 0
reactor_type = row[3]
latitude = row[11] if row[11] != '' else 0
longitude = row[12] if row[12] != '' else 0
if reactor_type in ['BWR', 'ESBWR']:
assem_no = 732
assem_per_batch = int(assem_no / 3)
Expand Down Expand Up @@ -536,10 +580,12 @@ def write_reactors(in_list, out_path, reactor_template):
assem_size = 103000 / assem_no
config = reactor_template.render(name=name,
lifetime=get_lifetime(row),
cycletime=cycle_time,
refueltime=refuel_time,
assem_size=assem_size,
n_assem_core=assem_no,
n_assem_batch=assem_per_batch,
power_cap=row[3],
power_cap=row[10],
lon=longitude,
lat=latitude)
with open(out_path + name.replace(' ', '_') + '.xml',
Expand Down Expand Up @@ -636,7 +682,7 @@ def get_buildtime(in_list, start_year, path_list):
"""
buildtime_dict = {}
for row in in_list:
comm_date = date.parse(row[10])
comm_date = date.parse(row[8])
start_date = [comm_date.year, comm_date.month, comm_date.day]
delta = ((start_date[0] - int(start_year)) * 12 +
(start_date[1]) +
Expand Down Expand Up @@ -692,7 +738,7 @@ def deploy_reactors(in_csv, region, start_year, deployinst_template,
return buildtime


def render_cyclus(cyclus_template, region, in_dict, out_path):
def render_cyclus(cyclus_template, region, in_dict, out_path, burn_up=50):
""" Renders final CYCLUS input file with xml base, and institutions
for each country

Expand All @@ -706,7 +752,10 @@ def render_cyclus(cyclus_template, region, in_dict, out_path):
in_dict should be buildtime_dict from get_buildtime function
out_path: str
output path for CYCLUS input file
output_name:
data_year: int
year the data was pulled from
burn_up: int
burnup in GWd/MTU

Returns
-------
Expand All @@ -717,7 +766,8 @@ def render_cyclus(cyclus_template, region, in_dict, out_path):
out_path += '/'
cyclus_template = load_template(cyclus_template)
country_list = {value[0].replace(' ', '_') for value in in_dict.values()}
rendered = cyclus_template.render(countries=country_list,
rendered = cyclus_template.render(burnup=burn_up,
countries=country_list,
base_dir=os.path.abspath(out_path) + '/')
with open(out_path + region + '.xml', 'w') as output:
output.write(rendered)