From ac1bb5795dc617154fad99dc1ebfe51fe4845bba Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Sat, 14 Feb 2015 15:10:19 -0500 Subject: [PATCH 01/12] removed groups in filter from tallies rnc file --- src/relaxng/tallies.rnc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/relaxng/tallies.rnc b/src/relaxng/tallies.rnc index 06959276bc..92c002ee5b 100644 --- a/src/relaxng/tallies.rnc +++ b/src/relaxng/tallies.rnc @@ -27,9 +27,7 @@ element tallies { attribute type { ( "cell" | "cellborn" | "material" | "universe" | "surface" | "mesh" | "energy" | "energyout" ) }) & (element bins { list { xsd:string { maxLength = "20" }+ } } | - attribute bins { list { xsd:string { maxLength = "20" }+ } }) & - (element groups { xsd:string { maxLength = "20" }+ } | - attribute groups { xsd:string { maxLength = "20" }+ })? + attribute bins { list { xsd:string { maxLength = "20" }+ } }) }* & element nuclides { list { xsd:string { maxLength = "12" }+ } From 4fc764f5b3e3ac6aa4f93ffd55a0b9d525fb590b Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Sat, 14 Feb 2015 15:10:35 -0500 Subject: [PATCH 02/12] added xml validate file --- src/utils/xml_validate.py | 93 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100755 src/utils/xml_validate.py diff --git a/src/utils/xml_validate.py b/src/utils/xml_validate.py new file mode 100755 index 0000000000..d4a030cb53 --- /dev/null +++ b/src/utils/xml_validate.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import os +import sys +import glob +import lxml.etree as etree +from subprocess import call +from optparse import OptionParser + +# Command line parsing +parser = OptionParser() +parser.add_option('-r', '--relaxng-path', dest='relaxng', + help="Path to RelaxNG files.") +parser.add_option('-i', '--input-path', dest='inputs', default=os.getcwd(), + help="Path to OpenMC input files." ) +(options, args) = parser.parse_args() + +# Colored output +if sys.stdout.isatty(): + OK = '\033[92m' + FAIL = '\033[91m' + NOT_FOUND = '\033[93m' + ENDC = '\033[0m' + BOLD = '\033[1m' +else: + OK = '' + FAIL = '' + ENDC = '' + BOLD = '' + NOT_FOUND = '' + +# Get paths +relaxng_path = os.path.abspath(options.relaxng) +inputs_path = os.path.abspath(options.inputs) + +# Check for RelaxNG path +if not relaxng_path: + raise Exception("Must specify RelaxNG path.") + +# Make sure there are .rnc files in RelaxNG path +rnc_files = glob.glob(os.path.join(relaxng_path, "*.rnc")) +if len(rnc_files) == 0: + raise Exception("No .rnc files found in RelaxNG " + "path: {0}.".format(relaxng_path)) + +# Get list of xml input files +xml_files = glob.glob(os.path.join(inputs_path, "*.xml")) +if len(xml_files) == 0: + raise Exception("No .xml files found at input path: {0}.".format(inputs_path)) + +# Begin loop around input files +for xml_file in xml_files: + + text = "Validating {0}".format(os.path.basename(xml_file)) + print(text + '.'*(30 - len(text)), end="") + + # Validate the XML file + xml_tree = etree.parse(xml_file) + + # Get xml_filename prefix + xml_prefix = os.path.basename(xml_file) + xml_prefix = xml_prefix.split(".")[0] + + # Search for rnc file + rnc_file = os.path.join(relaxng_path, xml_prefix + ".rnc") + rng_file = xml_prefix + ".rng" + if rnc_file in rnc_files: + + # convert RNC to RNG file + rc = call("trang {0} {1}".format(rnc_file, rng_file), shell=True) + + # check return code + if rc == 0: + + # read in RelaxNG + relaxng_doc = etree.parse(rng_file) + relaxng = etree.RelaxNG(relaxng_doc) + + # validate xml file again RelaxNG + if relaxng.validate(xml_tree): + print(BOLD + OK + '[VALID]' + ENDC) + else: + print(BOLD + FAIL + '[NOT VALID]' + ENDC) + + # trang command failed + else: + print(BOLD + FAIL + '[TRANG RNC-->RNG FAILED]' + ENDC) + + # RNC file does not exist + else: + print(BOLD + NOT_FOUND + '[NO RELAXNG FOUND]' + ENDC) From 9060d420faeb458e9d7365322eafd9eeb466c808 Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Sat, 14 Feb 2015 15:31:36 -0500 Subject: [PATCH 03/12] removes rng files after use and prints more information if XML file does not conform to RelaxNG --- src/utils/xml_validate.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/utils/xml_validate.py b/src/utils/xml_validate.py index d4a030cb53..699ac3f4c3 100755 --- a/src/utils/xml_validate.py +++ b/src/utils/xml_validate.py @@ -79,10 +79,15 @@ for xml_file in xml_files: relaxng = etree.RelaxNG(relaxng_doc) # validate xml file again RelaxNG - if relaxng.validate(xml_tree): + try: + relaxng.assertValid(xml_tree) print(BOLD + OK + '[VALID]' + ENDC) - else: + except etree.DocumentInvalid as e: print(BOLD + FAIL + '[NOT VALID]' + ENDC) + print(" {0}".format(e)) + + # remove rng file + os.remove(rng_file) # trang command failed else: From f9715ff0cf91fe10719ec7cf4b4be2e08b87c2e5 Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Sat, 14 Feb 2015 15:35:56 -0500 Subject: [PATCH 04/12] handle xml parsing errors better --- src/utils/xml_validate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/xml_validate.py b/src/utils/xml_validate.py index 699ac3f4c3..568dbb40c9 100755 --- a/src/utils/xml_validate.py +++ b/src/utils/xml_validate.py @@ -57,7 +57,12 @@ for xml_file in xml_files: print(text + '.'*(30 - len(text)), end="") # Validate the XML file - xml_tree = etree.parse(xml_file) + try: + xml_tree = etree.parse(xml_file) + except etree.XMLSyntaxError as e: + print(BOLD + FAIL + '[XML ERROR]' + ENDC) + print(" {0}".format(e)) + continue # Get xml_filename prefix xml_prefix = os.path.basename(xml_file) From b217afdb84748eb2da45c5973b901cc9c048eabb Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Tue, 17 Feb 2015 20:42:13 -0500 Subject: [PATCH 05/12] install xml_validate script and relaxng files --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd920bfcc0..b3e1a88779 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -272,6 +272,10 @@ install(PROGRAMS utils/statepoint_meshplot.py install(PROGRAMS utils/update_inputs.py DESTINATION bin RENAME update_inputs) +install(PROGRAMS utils/xml_validate.py + DESTINATION bin + RENAME xml_validate) +install(DIRECTORY relaxng DESTINATION share) install(FILES ../man/man1/openmc.1 DESTINATION share/man/man1) install(FILES ../LICENSE DESTINATION "share/doc/${program}/copyright") From 1273951a0f70dc4bfddec3cca18fb8f9061750d1 Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Tue, 17 Feb 2015 20:42:43 -0500 Subject: [PATCH 06/12] restructed relaxng_path to search for directory if not set on command line --- src/utils/xml_validate.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/utils/xml_validate.py b/src/utils/xml_validate.py index 568dbb40c9..b22e3fc2c1 100755 --- a/src/utils/xml_validate.py +++ b/src/utils/xml_validate.py @@ -31,13 +31,24 @@ else: BOLD = '' NOT_FOUND = '' -# Get paths -relaxng_path = os.path.abspath(options.relaxng) -inputs_path = os.path.abspath(options.inputs) +# Get absolute paths +if options.relaxng is not None: + relaxng_path = os.path.abspath(options.relaxng) +if options.inputs is not None: + inputs_path = os.path.abspath(options.inputs) -# Check for RelaxNG path -if not relaxng_path: - raise Exception("Must specify RelaxNG path.") +# Search for relaxng path if not set +if options.relaxng is None: + xml_validate_path = os.path.abspath(os.path.dirname(sys.argv[0])) + if "bin" in xml_validate_path: + relaxng_path = os.path.join(xml_validate_path, "..", "share", "relaxng") + elif os.path.join("src", "utils") in xml_validate_path: + relaxng_path = os.path.join(xml_validate_path, "..", "relaxng") + else: + raise Exception("Set RelaxNG path with -r command line option.") +if not os.path.exists(relaxng_path): + raise Exception("RelaxNG path: {0} does not exist, set with -r " + "command line option.".format(relaxng_path)) # Make sure there are .rnc files in RelaxNG path rnc_files = glob.glob(os.path.join(relaxng_path, "*.rnc")) @@ -48,7 +59,8 @@ if len(rnc_files) == 0: # Get list of xml input files xml_files = glob.glob(os.path.join(inputs_path, "*.xml")) if len(xml_files) == 0: - raise Exception("No .xml files found at input path: {0}.".format(inputs_path)) + raise Exception("No .xml files found at input path: {0}" + ".".format(inputs_path)) # Begin loop around input files for xml_file in xml_files: From fc555bd15812d17ceba90a3ed5d6f8e2850229f4 Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Wed, 18 Feb 2015 21:32:31 -0500 Subject: [PATCH 07/12] changed trang failure message --- src/utils/xml_validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/xml_validate.py b/src/utils/xml_validate.py index b22e3fc2c1..0a4409c2a4 100755 --- a/src/utils/xml_validate.py +++ b/src/utils/xml_validate.py @@ -108,7 +108,7 @@ for xml_file in xml_files: # trang command failed else: - print(BOLD + FAIL + '[TRANG RNC-->RNG FAILED]' + ENDC) + print(BOLD + FAIL + '[TRANG FAILED]' + ENDC) # RNC file does not exist else: From 2b65568e9e0c5ab30b017971da30587d387a7a78 Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Wed, 18 Feb 2015 21:32:40 -0500 Subject: [PATCH 08/12] added documentation --- docs/source/usersguide/input.rst | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 20fd66e2f7..9ebdaa1660 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -51,6 +51,55 @@ files are called: * ``plots.xml`` * ``cmfd.xml`` +-------------------- +Validating XML Files +-------------------- + +Input files can be checked before executing OpenMC using the ``xml_validate`` +script. It is located in ``src/utils/xml_validate.py`` in the source code or in +``bin/xml_validate`` in the install directory. Before use, the third party +package TRANG_ must be installed and in your ``PATH`` to convert the compact +RelaxNG schema to standard RelaxNG format. For Ubuntu, you can install with: + +.. code-block:: bash + + sudo apt-get install trang + +Two command line arguments can be set when running ``xml_validate``: + +* ``-i``, ``--input-path`` - Location of OpenMC input files. + *Default*: current working directory +* ``-r``, ``--relaxng-path`` - Location of OpenMC RelaxNG files. + *Default*: None + +If the RelaxNG path is not set, ``xml_validate`` will search for these files +because it expects that the user is either running the script located in the +install directory ``bin`` folder or in ``src/utils``. Once executed, it will +match OpenMC XML files with their RelaxNG schema and check if they are valid. +Below is a table of the messages that will be printed after each file is +checked. + +======================== =================================== +Message Description +======================== =================================== +[XML ERROR] Cannot parse XML file. +[NO RELAXNG FOUND] No RelaxNG file found for XML file. +[TRANG FAILED] TRANG not installed properly. +[NOT VALID] XML file does not match RelaxNG. +[VALID] XML file matches RelaxNG. +======================== =================================== + +As an example, if OpenMC is installed in the directory +``/opt/openmc/0.6.2`` and the current working directory is where +OpenMC XML input files are located, they can be validated using +the following command: + +.. code-block:: bash + + /opt/openmc/0.6.2/bin/xml_validate + +.. _TRANG: http://www.thaiopensource.com/relaxng/trang.html + -------------------------------------- Settings Specification -- settings.xml -------------------------------------- From 40ebe23300d51965a237e97bfc6ca9036d9b941d Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Wed, 18 Feb 2015 21:40:39 -0500 Subject: [PATCH 09/12] changed tally bins to double and handle extra exception for common errors in tally bins --- src/relaxng/tallies.rnc | 4 ++-- src/utils/xml_validate.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/relaxng/tallies.rnc b/src/relaxng/tallies.rnc index 92c002ee5b..09a5a6eb85 100644 --- a/src/relaxng/tallies.rnc +++ b/src/relaxng/tallies.rnc @@ -26,8 +26,8 @@ element tallies { "surface" | "mesh" | "energy" | "energyout" ) } | attribute type { ( "cell" | "cellborn" | "material" | "universe" | "surface" | "mesh" | "energy" | "energyout" ) }) & - (element bins { list { xsd:string { maxLength = "20" }+ } } | - attribute bins { list { xsd:string { maxLength = "20" }+ } }) + (element bins { list { xsd:double+ } } | + attribute bins { list { xsd:double+ } }) }* & element nuclides { list { xsd:string { maxLength = "12" }+ } diff --git a/src/utils/xml_validate.py b/src/utils/xml_validate.py index 0a4409c2a4..aa56e6e0cf 100755 --- a/src/utils/xml_validate.py +++ b/src/utils/xml_validate.py @@ -99,7 +99,7 @@ for xml_file in xml_files: try: relaxng.assertValid(xml_tree) print(BOLD + OK + '[VALID]' + ENDC) - except etree.DocumentInvalid as e: + except (etree.DocumentInvalid, TypeError) as e: print(BOLD + FAIL + '[NOT VALID]' + ENDC) print(" {0}".format(e)) From 50d9de5def123091d250723db6b3792495a3b39c Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Thu, 19 Feb 2015 06:10:52 -0500 Subject: [PATCH 10/12] changed cell rotation schema from double to int --- src/relaxng/geometry.rnc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc index e93c8a9a83..14383f40b0 100644 --- a/src/relaxng/geometry.rnc +++ b/src/relaxng/geometry.rnc @@ -8,7 +8,7 @@ element geometry { attribute material { ( xsd:int | "void" ) }) ) & (element surfaces { list { xsd:int* } } | attribute surfaces { list { xsd:int* } })? & - (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & + (element rotation { list { xsd:int+ } } | attribute rotation { list { xsd:int+ } })? & (element translation { list { xsd:double+ } } | attribute translation { list { xsd:double+ } })? }* From ea1df445d26b9fd8a889e0c91d93c4fd0d193df8 Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Thu, 19 Feb 2015 07:46:07 -0500 Subject: [PATCH 11/12] cell rotation switched back to double in RelaxNG schema --- src/relaxng/geometry.rnc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc index 14383f40b0..e93c8a9a83 100644 --- a/src/relaxng/geometry.rnc +++ b/src/relaxng/geometry.rnc @@ -8,7 +8,7 @@ element geometry { attribute material { ( xsd:int | "void" ) }) ) & (element surfaces { list { xsd:int* } } | attribute surfaces { list { xsd:int* } })? & - (element rotation { list { xsd:int+ } } | attribute rotation { list { xsd:int+ } })? & + (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & (element translation { list { xsd:double+ } } | attribute translation { list { xsd:double+ } })? }* From e2f7fce57d2e04e58eb18fe675778edce61062bf Mon Sep 17 00:00:00 2001 From: Bryan Herman Date: Thu, 19 Feb 2015 07:59:15 -0500 Subject: [PATCH 12/12] Changed cell rotation to read in as double --- src/input_xml.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 292b32e066..fc003d448a 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -904,7 +904,7 @@ contains integer :: universe_num integer :: n_cells_in_univ integer :: coeffs_reqd - integer :: temp_int_array3(3) + integer :: temp_double_array3(3) integer, allocatable :: temp_int_array(:) real(8) :: phi, theta, psi logical :: file_exists @@ -1052,10 +1052,10 @@ contains end if ! Copy rotation angles in x,y,z directions - call get_node_array(node_cell, "rotation", temp_int_array3) - phi = -temp_int_array3(1) * PI/180.0_8 - theta = -temp_int_array3(2) * PI/180.0_8 - psi = -temp_int_array3(3) * PI/180.0_8 + call get_node_array(node_cell, "rotation", temp_double_array3) + phi = -temp_double_array3(1) * PI/180.0_8 + theta = -temp_double_array3(2) * PI/180.0_8 + psi = -temp_double_array3(3) * PI/180.0_8 ! Calculate rotation matrix based on angles given allocate(c % rotation(3,3))