From 6547891aa41d42bb057f31c47ecd76bb41d0e31d Mon Sep 17 00:00:00 2001 From: Ryan Swanson Date: Thu, 2 Dec 2021 19:22:18 -0500 Subject: [PATCH 1/4] change MCNP importance regex for issue #38 and #29 --- csg2csg/MCNPCellCard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csg2csg/MCNPCellCard.py b/csg2csg/MCNPCellCard.py index 568e432..0843167 100644 --- a/csg2csg/MCNPCellCard.py +++ b/csg2csg/MCNPCellCard.py @@ -268,7 +268,7 @@ def __detect_keywords(self, keywords, string): if posi == -1: self.cell_importance = 1. else: - self.cell_importance = float(self.__get_keyword_value('imp:n',end_of_string)) + self.cell_importance = float(self.__get_keyword_value("imp:[npe|quvfhl+-xyo!<>g/zk%^b_~cw@dtsa*?#,]+",end_of_string)) # return the string upto the posisiotn of the first detected keyword return string[:m] From 24832baa90fc3b79621b08961ffd33181ac33594 Mon Sep 17 00:00:00 2001 From: Ryan Swanson Date: Thu, 2 Dec 2021 20:03:26 -0500 Subject: [PATCH 2/4] extend MCNP to support 'read' cards and '&' line continuation --- csg2csg/MCNPInput.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/csg2csg/MCNPInput.py b/csg2csg/MCNPInput.py index 6e47066..5005feb 100644 --- a/csg2csg/MCNPInput.py +++ b/csg2csg/MCNPInput.py @@ -23,6 +23,7 @@ import warnings import logging +import os import sys import re @@ -39,6 +40,35 @@ def __init__(self, filename =""): # TODO - maybe make a function that aribitrarily extract text # between one keyword until another keyword is found + # extend read method to process "read" cards in MCNP input file + def read(self): + with open(self.filename, 'rU', errors="replace") as f: + file_content = f.read() + + # look for and swap read cards + read_cards = re.findall("^read .*?\n", file_content, re.DOTALL|re.MULTILINE) + for read_card in read_cards: + filepath = read_card.split("=")[1].strip().split()[0] + # if file exists, read it in and replace + if os.path.isfile(filepath): + with open(filepath, 'rU', errors="replace") as i: + read_input = i.read() + i.close() + + file_content = re.sub(read_card, read_input, file_content) + + # else, print error and comment out + else: + print("WARNING: read file {} does not exist.".format(filepath)) + file_content = re.sub(read_card, "c " + read_card, file_content) + + self.file_lines = file_content.splitlines(keepends=True) + + # split into lines and count total lines + self.file_lines = [x.lower() for x in self.file_lines] + + self.total_num_lines = len(self.file_lines) + def __set_title(self): # set the title card if "message" in self.file_lines[0]: @@ -825,6 +855,11 @@ def __get_cell_cards(self): # mcnp continue line is indicated by 5 spaces if cell_line.startswith(" ") and not cell_line.isspace(): card_line += cell_line + # if & continuation + elif self.file_lines[jdx-1].rstrip().endswith("&"): + card_line += cell_line + # strip any & + card_line = re.sub("&", "", card_line) else: # else we have found a new cell card logging.debug("%s\n", "Found new cell card " + card_line) cellcard = MCNPCellCard(card_line) From 5fdb2445aad42d945b8174cc0669ae75228ce241 Mon Sep 17 00:00:00 2001 From: Ryan Swanson Date: Thu, 2 Dec 2021 20:24:54 -0500 Subject: [PATCH 3/4] edits in MCNP to process lattices, cell tmp, cell vol cards --- csg2csg/CellCard.py | 4 ++ csg2csg/Input.py | 2 + csg2csg/MCNPCellCard.py | 78 +++++++++++++++++++++++++++++-------- csg2csg/MCNPInput.py | 85 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 152 insertions(+), 17 deletions(-) diff --git a/csg2csg/CellCard.py b/csg2csg/CellCard.py index 89af5dd..0920df3 100644 --- a/csg2csg/CellCard.py +++ b/csg2csg/CellCard.py @@ -35,6 +35,10 @@ def __init__(self,card_string): self.cell_universe_transformation_id = "0" # if there is a cell_universe tr number it should be purged # and converted into an offset and rotation self.cell_surface_list = set() # list of surfaces used in the cell definition + self.cell_lattice = None + self.cell_lattice_type = None + self.cell_volume = None + self.cell_temperature = None Card.__init__(self,card_string) diff --git a/csg2csg/Input.py b/csg2csg/Input.py index 6291040..e7d015b 100644 --- a/csg2csg/Input.py +++ b/csg2csg/Input.py @@ -17,6 +17,7 @@ def __init__(self, filename): # TODO maybe these should be dictionaries by index self.cell_list = [] self.surface_list = [] + self.lattice_list = [] self.last_free_surface_index = 0 self.importance_list = {} # dictionary of importances self.material_list = {} @@ -70,6 +71,7 @@ def from_input(self,InputDeckClass): self.title = InputDeckClass.title self.cell_list = InputDeckClass.cell_list self.surface_list = InputDeckClass.surface_list + self.lattice_list = InputDeckClass.lattice_list self.material_list = InputDeckClass.material_list return diff --git a/csg2csg/MCNPCellCard.py b/csg2csg/MCNPCellCard.py index 0843167..d335fdd 100644 --- a/csg2csg/MCNPCellCard.py +++ b/csg2csg/MCNPCellCard.py @@ -10,8 +10,14 @@ import logging +import numpy +import scipy.constants + +# define constants +k_Mev = scipy.constants.physical_constants.get("Boltzmann constant in eV/K")[0]/1.e6 + # to support more keywords for cells add them here -mcnp_cell_keywords = ["imp","u","fill","vol", "tmp"] +mcnp_cell_keywords = ["imp","u","fill","vol", "tmp", "lat"] # if the string is a cell card or not def is_cell_card(line): @@ -86,6 +92,12 @@ def write_mcnp_cell(filestream, CellCard, print_importances = True): if CellCard.cell_universe != 0: string += " u=" + CellCard.cell_universe + if CellCard.cell_volume is not None: + string += " vol=" + CellCard.cell_volume + + if CellCard.cell_temperature is not None: + string += " tmp=" + str(CellCard.cell_temperature*k_Mev) + if CellCard.cell_fill != 0: string += " fill="+CellCard.cell_fill + " " if CellCard.cell_universe_offset != 0 or CellCard.cell_universe_rotation != 0: @@ -143,7 +155,10 @@ def generalise(self): # print(cell_description) # cell_description = [ s = "" for item in cell_description if item == "+"] cell_description = list(cell_description) - + + # need to reset cell surface list, to exclude removed macrobody, etc. + self.cell_surface_list = set() + idx = 0 while True: s = cell_description[idx] @@ -158,7 +173,7 @@ def generalise(self): elif s == ("(" or ")"): idx += 1 continue - elif isinstance(s,str) and cell_description[idx-1] != "(" and cell_description[idx] != ")": + elif isinstance(s,str) and cell_description[idx] != "(" and cell_description[idx] != ")": cell_description.insert(idx,CellCard.OperationType["AND"]) idx += 1 try: @@ -187,7 +202,7 @@ def __sanitise(self): # keyword def __get_keyword_value(self,keyword,string): #regex = re.regex=re.compile("("+keyword+") ?= ?[1-9][0-9]*") - regex = re.regex=re.compile("("+keyword+") ?= ?(?=.)([+-]?([0-9]*)(\.([0-9]+))?)") + regex = re.compile("("+keyword+") ?= ?(?=.)([+-]?([0-9]*)(\.([0-9]+))?)") result = regex.search(string)[0] return result.split(" ")[2] #string[offset:end] @@ -232,10 +247,11 @@ def __detect_keywords(self, keywords, string): posi = string.find("imp") posv = string.find("vol") + posl = string.find("lat") # find the posititon of the first match - positions = [posu, posf, posi, posv, post] - if posu != -1 or posf != -1 or posi != -1 or posv != -1 or post != -1: + positions = [posu, posf, posi, posv, post, posl] + if posu != -1 or posf != -1 or posi != -1 or posv != -1 or post != -1 or posl != -1: m = min(i for i in positions if i > 0) else: return string @@ -252,24 +268,56 @@ def __detect_keywords(self, keywords, string): else: self.cell_universe = self.__get_keyword_value('u',end_of_string) + if posv != -1: + self.cell_volume = self.__get_keyword_value('vol',end_of_string) + + if post != -1: + regex = re.compile("tmp ?= \d+\.\d+(?:[eE][+\-]?\d+)?") + result = regex.search(end_of_string)[0].split("=")[-1].strip() + self.cell_temperature = float(result)/k_Mev + if posf == -1: self.cell_fill = 0 else: - self.cell_fill = self.__get_keyword_value('fill',end_of_string).strip() - # if we have found fill, there may also be a rotation and translation - # associated with the universe of the form (0 0 0) - if '(' in string[posf:]: - rot_trans = self.__extract_string_between(string[posf:],'(',')') - else: - rot_trans = "0" - - self.__set_universe_transform(rot_trans,rot_angle_degrees) + # if lattice, assume fully specified fill cell card + if posl != -1: + # get the lattice element bounds + regex = re.compile("fill ?= ([+-]?([0-9]*)):([+-]?([0-9]*)) ([+-]?([0-9]*)):([+-]?([0-9]*)) ([+-]?([0-9]*)):([+-]?([0-9]*))") + result = regex.search(end_of_string)[0] + + self.cell_fill = result.split("=")[-1].strip() + + # process the bounds + i, j, k = self.cell_fill.split() + i_coords = list(range(int(i.split(":")[0]),int(i.split(":")[1])+1)) + j_coords = list(range(int(j.split(":")[0]),int(j.split(":")[1])+1)) + k_coords = list(range(int(k.split(":")[0]),int(k.split(":")[1])+1)) + total_cells = len(i_coords)*len(j_coords)*len(k_coords) + + # now read in the lattice + lattice = string[posf + len(result):].strip().split()[:total_cells] + # note this is reshaped in to z,x,y due to how numpy tiles/reshapes the data + self.cell_lattice = numpy.array(lattice).reshape(len(k_coords),len(i_coords),len(j_coords)).astype(int) + else: + self.cell_fill = self.__get_keyword_value('fill',end_of_string).strip() + # if we have found fill, there may also be a rotation and translation + # associated with the universe of the form (0 0 0) + if '(' in string[posf:]: + rot_trans = self.__extract_string_between(string[posf:],'(',')') + else: + rot_trans = "0" + + self.__set_universe_transform(rot_trans,rot_angle_degrees) + if posi == -1: self.cell_importance = 1. else: self.cell_importance = float(self.__get_keyword_value("imp:[npe|quvfhl+-xyo!<>g/zk%^b_~cw@dtsa*?#,]+",end_of_string)) + if posl != -1: + self.cell_lattice_type = int(self.__get_keyword_value("lat",end_of_string)) + # return the string upto the posisiotn of the first detected keyword return string[:m] diff --git a/csg2csg/MCNPInput.py b/csg2csg/MCNPInput.py index 5005feb..3450d83 100644 --- a/csg2csg/MCNPInput.py +++ b/csg2csg/MCNPInput.py @@ -700,6 +700,42 @@ def __flatten_macrobodies(self): text_string = ' '.join(cell.cell_text_description) self.cell_list[jdx].update(text_string) + # update the lattice definition (cell in mcnp) - loop over all cells + for jdx, cell in enumerate(self.lattice_list): + while True: + # cell text description is contually updated + cell_text_description = cell.cell_text_description + + # if we find the surface id of the macrobdy in the text description + sub = str(surf.surface_id) + regex = re.compile("^-?("+str(surf.surface_id)+")(\.+[1-9])?$") + matches = [m.group(0) for l in cell_text_description for m in [regex.search(l)] if m] + #if str(surf.surface_id) in cell_text_description or str(surf.surface_id)+"." in cell_text_description: + + if matches: + # loop over each component and find the macrobody + for idx, surface in enumerate(cell.cell_text_description): + # if it matches we have the simmple form + if str(surf.surface_id) == surface: + # replace it + cell.cell_text_description[idx] = cell_description[1] + elif "-"+str(surf.surface_id) == surface: + cell.cell_text_description[idx] = cell_description[0] + + # else we have the facet form + if str(surf.surface_id)+"." in surface: + surface_index = int(surface.split(".")[1]) # get just the mcnp surface index + new_surface_id = new_surfaces[surface_index-1].surface_id # mcnp numbers them 1->n + if "-" in surface: # need to take care of the -sign + cell.cell_text_description[idx] = "-"+str(new_surface_id) + else: + cell.cell_text_description[idx] = str(new_surface_id) + else: + break + # update the text description + text_string = ' '.join(cell.cell_text_description) + self.lattice_list[jdx].update(text_string) + # clear up removed surfaces logging.debug("%s", "Deleting macrobody surfaces") for surf in to_remove: @@ -863,8 +899,11 @@ def __get_cell_cards(self): else: # else we have found a new cell card logging.debug("%s\n", "Found new cell card " + card_line) cellcard = MCNPCellCard(card_line) - # we should set the comment here - self.cell_list.append(cellcard) + if cellcard.cell_lattice_type is not None: + self.lattice_list.append(cellcard) + else: + # we should set the comment here + self.cell_list.append(cellcard) break jdx += 1 idx = jdx @@ -888,6 +927,7 @@ def __apply_boundary_conditions(self): for cell in self.cell_list: if cell.cell_importance == 0: for surf in cell.cell_surface_list: + if self.get_surface_with_id(surf) is None: continue self.get_surface_with_id(surf).boundary_condition = SurfaceCard.BoundaryCondition["VACUUM"] return @@ -919,6 +959,44 @@ def __get_surface_cards(self,idx): idx = jdx return idx + # return specific surface card + def __get_surface_card(self, surface_id): + for surface in self.surface_list: + if surface.surface_id == surface_id: + return surface + + # update lattices + def __update_lattices(self): + # todo - note, this is not very robust + # "orientation" is only used for hex lattice + for lattice in self.lattice_list: + # initialize data + heights = [] + + # determine orientation, flat-to-flat, and height + for surface_id in lattice.cell_surface_list: + surface = self.__get_surface_card(surface_id) + + # if z + if surface.surface_type == SurfaceCard.SurfaceType["PLANE_Z"]: + heights.append( surface.surface_coefficients[3] ) + elif (surface.surface_type == SurfaceCard.SurfaceType["PLANE_GENERAL"] and + surface.surface_coefficients[0] == 0 and + surface.surface_coefficients[1] == 0 and + surface.surface_coefficients[2] == -1): + heights.append( -surface.surface_coefficients[3] ) + # if px, py + elif surface.surface_type == SurfaceCard.SurfaceType["PLANE_X"]: + orientation = "x" + pitch = abs(2.*surface.surface_coefficients[3]) + elif surface.surface_type == SurfaceCard.SurfaceType["PLANE_Y"]: + orientation = "y" + pitch = abs(2.*surface.surface_coefficients[3]) + + height = abs(heights[0] - heights[1]) + + lattice.pitch = [pitch, height] + lattice.orientation = orientation # process the mcnp input deck and read into a generic datastructure # that we can translate to other formats def process(self): @@ -983,6 +1061,9 @@ def process(self): # update the bounding coordinates of surfaces that need it # cones for example self.__update_surfaces() + + # process lattices, to get geometric information, now that surfaces are defined + self.__update_lattices() self.split_unions() From 464da63f596e8486cc4ffc87e2ce444a6c16ff85 Mon Sep 17 00:00:00 2001 From: Ryan Swanson Date: Thu, 2 Dec 2021 20:32:52 -0500 Subject: [PATCH 4/4] add initial support for reading thermal scattering in MCNP --- csg2csg/MCNPInput.py | 28 +++++--- csg2csg/MCNPMaterialCard.py | 32 +++++++++ csg2csg/MaterialCard.py | 2 + csg2csg/MaterialData.py | 132 +++++++++++++++++++++++++++++++++++- 4 files changed, 185 insertions(+), 9 deletions(-) diff --git a/csg2csg/MCNPInput.py b/csg2csg/MCNPInput.py index 3450d83..4d26357 100644 --- a/csg2csg/MCNPInput.py +++ b/csg2csg/MCNPInput.py @@ -9,7 +9,7 @@ from csg2csg.MCNPCellCard import MCNPCellCard, is_cell_card, write_mcnp_cell from csg2csg.MCNPSurfaceCard import MCNPSurfaceCard, is_surface_card, write_mcnp_surface from csg2csg.MCNPDataCard import MCNPTransformCard -from csg2csg.MCNPMaterialCard import MCNPMaterialCard, write_mcnp_material +from csg2csg.MCNPMaterialCard import MCNPMaterialCard, MCNPSABCard, write_mcnp_material from collections import Counter @@ -219,12 +219,24 @@ def __get_material_card(self, start_line): idx += 1 break - material = MCNPMaterialCard(mat_num, material_string) - # set the colour based on the number of colours - # but only if its really used rather than a tally - # multiplier material - material.material_colour = get_material_colour(len(self.material_list)) - self.material_list[material.material_number] = material + # process s(alpha, beta) + # assumes that all s(alpha, beta) are input after corresponding material cards in the input file + if "t" in mat_num: + mat_num = mat_num.replace("t","") + material = MCNPSABCard(mat_num, material_string) + + # update the previous material card to include thermal scattering + self.material_list[material.material_number].thermal_scattering = material.thermal_scattering + + return + + else: + material = MCNPMaterialCard(mat_num, material_string) + # set the colour based on the number of colours + # but only if its really used rather than a tally + # multiplier material + material.material_colour = get_material_colour(len(self.material_list)) + self.material_list[material.material_number] = material return @@ -239,7 +251,7 @@ def __get_material_cards(self, start_line): # this crazy makes sure that we find an "m" in the line but that we dont # find another keyword with an m in it like prdmp - if re.match(" *m[0-9]/*",self.file_lines[idx]): + if re.match(" *m(t)?[0-9]/*",self.file_lines[idx]): # if "m" in self.file_lines[idx] and not any(x in self.file_lines[idx] for x in mcnp_keywords): logging.debug("%s", "material found on line " + str(idx)) self.__get_material_card(idx) diff --git a/csg2csg/MCNPMaterialCard.py b/csg2csg/MCNPMaterialCard.py index cd0f6d1..0094363 100644 --- a/csg2csg/MCNPMaterialCard.py +++ b/csg2csg/MCNPMaterialCard.py @@ -1,6 +1,7 @@ #!/usr/env/python3 from csg2csg.MaterialCard import MaterialCard +from csg2csg.MaterialData import ThermalScattering from csg2csg.MCNPFormatter import get_fortran_formatted_number import sys @@ -68,3 +69,34 @@ def __process_string(self): self.composition_dictionary[nucid] = frac self.xsid_dictionary[nucid] = xsid return + + +class MCNPSABCard(MaterialCard): + + def __init__(self, material_number, card_string): + MaterialCard.__init__(self, material_number, card_string) + self.material_name = "MT"+str(material_number) + self.material_number = material_number + self.__process_string() + + # populate the MCNP Material Card + def __process_string(self): + # need to reset the list + # otherwise state seems to linger - weird + self.thermal_scattering = [] + + mat_string = self.text_string + mat_string = mat_string.replace("\n","") + + # split string + tokens = mat_string.split() + + while len(tokens) != 0: + sab = tokens[0].split(".")[0] + + tokens.pop(0) + + scattering = ThermalScattering() + + self.thermal_scattering.append( scattering.generalise[sab] ) + return \ No newline at end of file diff --git a/csg2csg/MaterialCard.py b/csg2csg/MaterialCard.py index e279422..5b4ae99 100644 --- a/csg2csg/MaterialCard.py +++ b/csg2csg/MaterialCard.py @@ -99,6 +99,8 @@ class MaterialCard(Card): density = 0 mat_data = 0 material_colour = 0 + thermal_scattering = [] + temperature = None # constructor def __init__(self, material_number = 0, card_string = ""): diff --git a/csg2csg/MaterialData.py b/csg2csg/MaterialData.py index 1022b19..eeaf231 100644 --- a/csg2csg/MaterialData.py +++ b/csg2csg/MaterialData.py @@ -3685,4 +3685,134 @@ def atomic_mass(self,element): for nuclide in self.natural_abund_map.keys(): if nuclide - nucid > 0 and nuclide - nucid < nucid / 100 : mass += self.natural_abund_map[nuclide]/100 * self.atomic_mass_map[nuclide] #return the zaid - return mass \ No newline at end of file + return mass + + +class ThermalScattering(): + + generalise = { + "al27": "Al27", + "be": "Be", + "be-o": "Be_in_BeO", + "benz": "C6H6", + "dortho": "ortho_D", + "dpara": "para_D", + "fe56": "Fe56", + "grph": "Graphite", + "hortho": "ortho_H", + "hpara": "para_H", + "hwtr": "D_in_D2O", + "h-zr": "H_in_ZrH", + "lmeth": "H_in_CH4_liquid", + "lwtr": "H_in_H2O", + "o-be": "O_in_BeO", + "o2-u": "O_in_UO2", + "poly": "H_in_CH2", + "sio2": "SiO2_alpha", + "smeth": "H_in_CH4_solid", + "u-o2": "U_in_UO2", + "zr-h": "Zr_in_ZrH", + + "al-27": "Al27", + "be-met": "Be", + "be-beo": "Be_in_BeO", + "benz": "C6H6", + "c-sic": "C_in_SiC", + "d-d2o": "D_in_D2O", + "fe-56": "Fe56", + "grph": "Graphite", + "grph10": "Graphite_10p", + "grph30": "Graphite_30p", + "h-h2o": "H_in_H2O", + "h-ice": "H_in_H2O_solid", + "h-luci": "H_in_C5O2H8", + "h-poly": "H_in_CH2", + "h-yh2": "H_in_YH2", + "h-zrh": "H_in_ZrH", + "lmeth": "H_in_CH4_liquid", + "n-un": "N_in_UN", + "o-beo": "O_in_BeO", + "o-d2o": "O_in_D2O", + "o-ice": "O_in_H2O_ice", + "o-uo2": "O_in_UO2", + "orthod": "ortho_D", + "orthoh": "ortho_H", + "parad": "para_D", + "parah": "para_H", + "si-sic": "Si_in_SiC", + "sio2": "SiO2_alpha", + "smeth": "H_in_CH4_solid", + "u-un": "U_in_UN", + "u-uo2": "U_in_UO2", + "y-yh2": "Y_in_YH2", + "zr-zrh": "Zr_in_ZrH", + + "c_Al27": "Al27", + "c_Be": "Be", + "c_Be_in_BeO": "Be_in_BeO", + "c_C6H6": "C6H6", + "c_C_in_SiC": "C_in_SiC", + "c_D_in_D2O": "D_in_D2O", + "c_Fe56": "Fe56", + "c_Graphite": "Graphite", + "c_Graphite_10p": "Graphite_10p", + "c_Graphite_30p": "Graphite_30p", + "c_H_in_H2O": "H_in_H2O", + "c_H_in_H2O_solid": "H_in_H2O_solid", + "c_H_in_C5O2H8": "H_in_C5O2H8", + "c_H_in_CH2": "H_in_CH2", + "c_H_in_YH2": "H_in_YH2", + "c_H_in_ZrH": "H_in_ZrH", + "c_H_in_CH4_liquid":"H_in_CH4_liquid", + "c_N_in_UN": "N_in_UN", + "c_O_in_BeO": "O_in_BeO", + "c_O_in_D2O": "O_in_D2O", + "c_O_in_H2O_ice": "O_in_H2O_ice", + "c_O_in_UO2": "O_in_UO2", + "c_ortho_D": "ortho_D", + "c_ortho_H": "ortho_H", + "c_para_D": "para_D", + "c_para_H": "para_H", + "c_Si_in_SiC": "Si_in_SiC", + "c_SiO2_alpha": "SiO2_alpha", + "c_H_in_CH4_solid": "H_in_CH4_solid", + "c_U_in_UN": "U_in_UN", + "c_U_in_UO2": "U_in_UO2", + "c_Y_in_YH2": "Y_in_YH2", + "c_Zr_in_ZrH": "Zr_in_ZrH" } + + specialize = { + "openmc" : { "Al27": "c_Al27", + "Be": "c_Be", + "Be_in_BeO": "c_Be_in_BeO", + "C6H6": "c_C6H6", + "C_in_SiC": "c_C_in_SiC", + "D_in_D2O": "c_D_in_D2O", + "Fe56": "c_Fe56", + "Graphite": "c_Graphite", + "Graphite_10p": "c_Graphite_10p", + "Graphite_30p": "c_Graphite_30p", + "H_in_H2O": "c_H_in_H2O", + "H_in_H2O_solid": "c_H_in_H2O_solid", + "H_in_C5O2H8": "c_H_in_C5O2H8", + "H_in_CH2": "c_H_in_CH2", + "H_in_YH2": "c_H_in_YH2", + "H_in_ZrH": "c_H_in_ZrH", + "H_in_CH4_liquid": "c_H_in_CH4_liquid", + "N_in_UN": "c_N_in_UN", + "O_in_BeO": "c_O_in_BeO", + "O_in_D2O": "c_O_in_D2O", + "O_in_H2O_ice": "c_O_in_H2O_ice", + "O_in_UO2": "c_O_in_UO2", + "ortho_D": "c_ortho_D", + "ortho_H": "c_ortho_H", + "para_D": "c_para_D", + "para_H": "c_para_H", + "Si_in_SiC": "c_Si_in_SiC", + "SiO2_alpha": "c_SiO2_alpha", + "H_in_CH4_solid": "c_H_in_CH4_solid", + "U_in_UN": "c_U_in_UN", + "U_in_UO2": "c_U_in_UO2", + "Y_in_YH2": "c_Y_in_YH2", + "Zr_in_ZrH": "c_Zr_in_ZrH"} + }