diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 06c044e42c..dd920bfcc0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -269,6 +269,9 @@ install(PROGRAMS utils/statepoint_histogram.py install(PROGRAMS utils/statepoint_meshplot.py DESTINATION bin RENAME statepoint_meshplot) +install(PROGRAMS utils/update_inputs.py + DESTINATION bin + RENAME update_inputs) install(FILES ../man/man1/openmc.1 DESTINATION share/man/man1) install(FILES ../LICENSE DESTINATION "share/doc/${program}/copyright") diff --git a/src/constants.F90 b/src/constants.F90 index de3d5b1807..527284803c 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -128,7 +128,7 @@ module constants SURF_CONE_Z = 11 ! Cone parallel to z-axis ! Flag to say that the outside of a lattice is not defined - integer, parameter :: NO_OUTER_UNIV = -22 + integer, parameter :: NO_OUTER_UNIVERSE = -22 ! Maximum number of lost particles integer, parameter :: MAX_LOST_PARTICLES = 10 diff --git a/src/geometry.F90 b/src/geometry.F90 index 54b131d626..b7116ebc57 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -312,7 +312,7 @@ contains if (.not. outside_lattice) then p % coord % next % universe = lat % universes(i_x,i_y,i_z) else - if (lat % outer == NO_OUTER_UNIV) then + if (lat % outer == NO_OUTER_UNIVERSE) then call fatal_error("A particle is outside latttice " & &// trim(to_str(lat % id)) // " but the lattice has no & &defined outer universe.") diff --git a/src/initialize.F90 b/src/initialize.F90 index 180e509427..ec64a1f19b 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -644,7 +644,7 @@ contains end do end do - if (lat % outer /= NO_OUTER_UNIV) then + if (lat % outer /= NO_OUTER_UNIVERSE) then if (universe_dict % has_key(lat % outer)) then lat % outer = universe_dict % get_key(lat % outer) else diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 27f090478b..292b32e066 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1340,7 +1340,7 @@ contains deallocate(temp_int_array) ! Read outer universe for area outside lattice. - lat % outer = NO_OUTER_UNIV + lat % outer = NO_OUTER_UNIVERSE if (check_for_node(node_lat, "outer")) then call get_node_value(node_lat, "outer", lat % outer) end if @@ -1349,8 +1349,8 @@ contains if (check_for_node(node_lat, "outside")) then call fatal_error("The use of 'outside' in lattices is no longer & &supported. Instead, use 'outer' which defines a universe rather & - &than a material. The utility openmc/src/utils/update_lattices.py& - & can be used automatically replace 'outside' with 'outer'.") + &than a material. The utility openmc/src/utils/update_inputs.py & + &can be used automatically replace 'outside' with 'outer'.") end if ! Add lattice to dictionary diff --git a/src/utils/update_lattices.py b/src/utils/update_inputs.py similarity index 56% rename from src/utils/update_lattices.py rename to src/utils/update_inputs.py index efcf8c631b..cd6f98b63c 100755 --- a/src/utils/update_lattices.py +++ b/src/utils/update_inputs.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -"""Update lattices in geometry .xml files to the latest format. +"""Update OpenMC's input XML files to the latest format. -Usage information can be obtained by running 'update_lattices.py --help': +Usage information can be obtained by running 'update_inputs.py --help': usage: update_lattices.py [-h] IN [IN ...] @@ -26,14 +26,27 @@ from shutil import move import xml.etree.ElementTree as ET +description = "Update OpenMC's input XML files to the latest format." +epilog = """\ +If any of the given files do not match the most up-to-date formatting, then they +will be automatically rewritten. The old out-of-date files will not be deleted; +they will be moved to a new file with '.original' appended to their name. + +Formatting changes that will be made: + +geometry.xml: Lattices containing 'outside' attributes/tags will be replaced + with lattices containing 'outer' attributes, and the appropriate + cells/universes will be added. +""" + + def parse_args(): """Read the input files from the commandline.""" # Create argument parser. - parser = argparse.ArgumentParser(description="Update lattices in " - "geometry.xml files to the latest format. This will remove 'outside' " - "attributes/elements and replace them with 'outer' attributes. Note " - "that this script will not delete the given files; it will append " - "'.original' to the given files and write new ones.") + parser = argparse.ArgumentParser( + description=description, + epilog=epilog, + formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('input', metavar='IN', type=str, nargs='+', help='Input geometry.xml file(s).') @@ -123,10 +136,10 @@ def find_new_id(current_ids, preferred=None): def get_lat_id(lattice_element): """Return the id integer of the lattice_element.""" assert isinstance(lattice_element, ET.Element) - if 'id' in lat.attrib: - return int(lat.attrib['id'].strip()) - elif any([child.tag == 'id' for child in lat]): - elem = lat.find('id') + if 'id' in lattice_element.attrib: + return int(lattice_element.attrib['id'].strip()) + elif any([child.tag == 'id' for child in lattice_element]): + elem = lattice_element.find('id') return int(elem.text.strip()) else: raise RuntimeError('Could not find the id for a lattice.') @@ -137,15 +150,15 @@ def pop_lat_outside(lattice_element): assert isinstance(lattice_element, ET.Element) # Check attributes. - if 'outside' in lat.attrib: - material = lat.attrib['outside'].strip() - del lat.attrib['outside'] + if 'outside' in lattice_element.attrib: + material = lattice_element.attrib['outside'].strip() + del lattice_element.attrib['outside'] # Check subelements. - elif any([child.tag == 'outside' for child in lat]): - elem = lat.find('outside') + elif any([child.tag == 'outside' for child in lattice_element]): + elem = lattice_element.find('outside') material = elem.text.strip() - lat.remove(elem) + lattice_element.remove(elem) # No 'outside' specified. This means the outside is a void. else: @@ -154,48 +167,66 @@ def pop_lat_outside(lattice_element): return material +def update_geometry(geometry_root): + """Update the given XML geometry tree. Return True if changes were made.""" + root = geometry_root + was_updated = False + + # Ignore files that do not contain lattices. + if all([child.tag != 'lattice' for child in root]): return False + + # Get a set of already-used universe and cell ids. + uids = get_universe_ids(root) + cids = get_cell_ids(root) + taken_ids = uids.union(cids) + + # Update the definitions of each lattice + for lat in root.iter('lattice'): + # Get the lattice's id. + lat_id = get_lat_id(lat) + + # Ignore lattices that have 'outer' specified. + if any([child.tag == 'outer' for child in lat]): continue + + # Pop the 'outside' material. + material = pop_lat_outside(lat) + + # Get an id number for a new outer universe. Ideally, the id should + # be close to the lattice's id. + new_uid = find_new_id(taken_ids, preferred=lat_id) + assert new_uid not in taken_ids + + # Add the new universe filled with the old 'outside' material to the + # geometry. + new_cell = ET.Element('cell') + new_cell.attrib['id'] = str(new_uid) + new_cell.attrib['universe'] = str(new_uid) + new_cell.attrib['material'] = material + root.append(new_cell) + taken_ids.add(new_uid) + + # Add the new universe to the lattice's 'outer' attribute. + lat.attrib['outer'] = str(new_uid) + + was_updated = True + + return was_updated + + if __name__ == '__main__': args = parse_args() for fname in args.input: # Parse the XML data. tree = ET.parse(fname) root = tree.getroot() + was_updated = False - # Ignore files that do not contain lattices. - if all([child.tag != 'lattice' for child in root]): continue + if root.tag == 'geometry': + was_updated = update_geometry(root) - # Get a set of already-used universe and cell ids. - uids = get_universe_ids(root) - cids = get_cell_ids(root) - taken_ids = uids.union(cids) + if was_updated: + # Move the original geometry file to preserve it. + move(fname, fname + '.original') - # Update the definitions of each lattice - for lat in root.iter('lattice'): - # Get the lattice's id. - lat_id = get_lat_id(lat) - - # Pop the 'outside' material. - material = pop_lat_outside(lat) - - # Get an id number for a new outer universe. Ideally, the id should - # be close to the lattice's id. - new_uid = find_new_id(taken_ids, preferred=lat_id) - assert new_uid not in taken_ids - - # Add the new universe filled with the old 'outside' material to the - # geometry. - new_cell = ET.Element('cell') - new_cell.attrib['id'] = str(new_uid) - new_cell.attrib['universe'] = str(new_uid) - new_cell.attrib['material'] = material - root.append(new_cell) - taken_ids.add(new_uid) - - # Add the new universe to the lattice's 'outer' attribute. - lat.attrib['outer'] = str(new_uid) - - # Move the original geometry file to preserve it. - move(fname, ''.join((fname, '.original'))) - - # Write a new geometry file. - tree.write(fname) + # Write a new geometry file. + tree.write(fname)