From ce04299f30faac14a25416e280a4d81a13577d1e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 12 Sep 2018 22:39:27 -0500 Subject: [PATCH 001/175] Fix clang complaining about control reaching end of non-void function --- include/openmc/endf.h | 1 + include/openmc/position.h | 7 ++++++- openmc/capi/core.py | 2 +- src/distribution.cpp | 15 +++++++++------ src/eigenvalue.cpp | 2 +- src/endf.cpp | 19 ++++++++++++++----- src/geometry_aux.cpp | 1 + src/mesh.cpp | 17 +++++++++++------ src/thermal.cpp | 8 ++++---- src/xml_interface.cpp | 1 + 10 files changed, 49 insertions(+), 24 deletions(-) diff --git a/include/openmc/endf.h b/include/openmc/endf.h index 7f224b24f..c781bd0b8 100644 --- a/include/openmc/endf.h +++ b/include/openmc/endf.h @@ -29,6 +29,7 @@ bool is_fission(int MT); class Function1D { public: virtual double operator()(double x) const = 0; + virtual ~Function1D() = default; }; //============================================================================== diff --git a/include/openmc/position.h b/include/openmc/position.h index d7a13c01e..56d01ba0a 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -1,7 +1,8 @@ #ifndef OPENMC_POSITION_H #define OPENMC_POSITION_H -#include +#include // for sqrt +#include // for out_of_range #include namespace openmc { @@ -29,6 +30,8 @@ struct Position { case 0: return x; case 1: return y; case 2: return z; + default: + throw std::out_of_range{"Index in Position must be between 0 and 2."}; } } double& operator[](int i) { @@ -36,6 +39,8 @@ struct Position { case 0: return x; case 1: return y; case 2: return z; + default: + throw std::out_of_range{"Index in Position must be between 0 and 2."}; } } diff --git a/openmc/capi/core.py b/openmc/capi/core.py index f0c5ac45e..53c3c32bd 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -112,7 +112,7 @@ def find_material(xyz): if isinstance(mats, openmc.capi.Material): return mats else: - return mats[instance] + return mats[instance.value] def hard_reset(): """Reset tallies, timers, and pseudo-random number generator state.""" diff --git a/src/distribution.cpp b/src/distribution.cpp index f02ee1fc0..01b09e65d 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -4,6 +4,7 @@ #include // for sqrt, floor, max #include // for back_inserter #include // for accumulate +#include // for runtime_error #include // for string, stod #include "openmc/error.h" @@ -44,7 +45,7 @@ double Discrete::sample() const c += p_[i]; if (xi < c) return x_[i]; } - // throw exception? + throw std::runtime_error{"Error when sampling probability mass function."}; } else { return x_[0]; } @@ -248,19 +249,21 @@ UPtrDist distribution_from_xml(pugi::xml_node node) std::string type = get_node_value(node, "type", true, true); // Allocate extension of Distribution + UPtrDist dist; if (type == "uniform") { - return UPtrDist{new Uniform(node)}; + dist = UPtrDist{new Uniform(node)}; } else if (type == "maxwell") { - return UPtrDist{new Maxwell(node)}; + dist = UPtrDist{new Maxwell(node)}; } else if (type == "watt") { - return UPtrDist{new Watt(node)}; + dist = UPtrDist{new Watt(node)}; } else if (type == "discrete") { - return UPtrDist{new Discrete(node)}; + dist = UPtrDist{new Discrete(node)}; } else if (type == "tabular") { - return UPtrDist{new Tabular(node)}; + dist = UPtrDist{new Tabular(node)}; } else { openmc::fatal_error("Invalid distribution type: " + type); } + return dist; } } // namespace openmc diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index d4f629e06..454fd57e6 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -146,7 +146,7 @@ extern "C" double entropy_c(int i) return entropy.at(i - 1); } -extern "C" double entropy_clear() +extern "C" void entropy_clear() { entropy.clear(); } diff --git a/src/endf.cpp b/src/endf.cpp index fb7701ac3..8ffb75345 100644 --- a/src/endf.cpp +++ b/src/endf.cpp @@ -3,6 +3,7 @@ #include // for copy #include // for log, exp #include // for back_inserter +#include // for runtime_error #include "xtensor/xarray.hpp" #include "xtensor/xview.hpp" @@ -19,17 +20,23 @@ namespace openmc { Interpolation int2interp(int i) { + // TODO: We are ignoring specification of two-dimensional interpolation + // schemes (method of corresponding points and unit base interpolation). Those + // should be accounted for in the distribution classes somehow. + switch (i) { - case 1: + case 1: case 11: case 21: return Interpolation::histogram; - case 2: + case 2: case 12: case 22: return Interpolation::lin_lin; - case 3: + case 3: case 13: case 23: return Interpolation::lin_log; - case 4: + case 4: case 14: case 24: return Interpolation::log_lin; - case 5: + case 5: case 15: case 25: return Interpolation::log_log; + default: + throw std::runtime_error{"Invalid interpolation code."}; } } @@ -142,6 +149,8 @@ double Tabulated1D::operator()(double x) const case Interpolation::log_log: r = log(x/x0)/log(x1/x0); return y0*exp(r*log(y1/y0)); + default: + throw std::runtime_error{"Invalid interpolation scheme."}; } } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 273aad444..20f64e187 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -389,6 +389,7 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, return path.str(); } } + throw std::runtime_error{"Error determining distribcell path."}; } } diff --git a/src/mesh.cpp b/src/mesh.cpp index c1bd830a6..af088ffd0 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -162,12 +162,15 @@ int RegularMesh::get_bin(Position r) const int RegularMesh::get_bin_from_indices(const int* ijk) const { - if (n_dimension_ == 1) { - return ijk[0]; - } else if (n_dimension_ == 2) { - return (ijk[1] - 1)*shape_[0] + ijk[0]; - } else if (n_dimension_ == 3) { - return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0]; + switch (n_dimension_) { + case 1: + return ijk[0]; + case 2: + return (ijk[1] - 1)*shape_[0] + ijk[0]; + case 3: + return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0]; + default: + throw std::runtime_error{"Invalid number of mesh dimensions"}; } } @@ -206,6 +209,8 @@ bool RegularMesh::intersects(Position r0, Position r1) const return intersects_2d(r0, r1); case 3: return intersects_3d(r0, r1); + default: + throw std::runtime_error{"Invalid number of mesh dimensions."}; } } diff --git a/src/thermal.cpp b/src/thermal.cpp index 229aa35bc..7705dd72c 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -1,7 +1,7 @@ #include "openmc/thermal.h" #include // for sort, move, min, max, find -#include // for round, sqrt, fabs +#include // for round, sqrt, abs #include // for stringstream #include "xtensor/xarray.hpp" @@ -80,7 +80,7 @@ ThermalScattering::ThermalScattering(hid_t group, const std::vector& tem auto i_closest = xt::argmin(xt::abs(temps_available - T))[0]; auto temp_actual = temps_available[i_closest]; - if (std::fabs(temp_actual - T) < tolerance) { + if (std::abs(temp_actual - T) < tolerance) { if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) == temps_to_read.end()) { temps_to_read.push_back(std::round(temp_actual)); @@ -156,7 +156,7 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, if (settings::temperature_method == TEMPERATURE_NEAREST) { // If using nearest temperature, do linear search on temperature for (i = 0; i < kTs_.size(); ++i) { - if (abs(kTs_[i] - kT) < K_BOLTZMANN*settings::temperature_tolerance) { + if (std::abs(kTs_[i] - kT) < K_BOLTZMANN*settings::temperature_tolerance) { break; } } @@ -574,7 +574,7 @@ ThermalData::sample(const NuclideMicroXS* micro_xs, double E, // Because of floating-point roundoff, it may be possible for mu to be // outside of the range [-1,1). In these cases, we just set mu to exactly // -1 or 1 - if (std::fabs(*mu) > 1.0) *mu = std::copysign(1.0, *mu); + if (std::abs(*mu) > 1.0) *mu = std::copysign(1.0, *mu); } diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index 18627efe3..60ae7ffca 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -53,6 +53,7 @@ get_node_value_bool(pugi::xml_node node, const char* name) << node.name() << "\" XML node"; fatal_error(err_msg); } + return false; } } // namespace openmc From 0454d8b9adc8fc96268701b860afb8c6fd0b7dce Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 12 Sep 2018 23:38:16 -0500 Subject: [PATCH 002/175] Set CMake policy 0074 for version 3.12+ --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6821c414..73863bc3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,11 @@ endif() # HDF5 for binary output #=============================================================================== +# Allow user to specify HDF5_ROOT +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) + cmake_policy(SET CMP0074 NEW) +endif() + # Unfortunately FindHDF5.cmake will always prefer a serial HDF5 installation # over a parallel installation if both appear on the user's PATH. To get around # this, we check for the environment variable HDF5_ROOT and if it exists, use it From 4a43e28560fb7b04bd4b4616028612fe0a9dae94 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 22 Feb 2018 21:13:18 -0600 Subject: [PATCH 003/175] Creating a new subclass, CADSurface, with empty definitions for now. --- include/openmc/surface.h | 18 +++++++++++++++++- src/surface.cpp | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 23d5d1543..0d272de91 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -65,7 +65,7 @@ public: std::vector neighbor_neg_; //!< List of cells on negative side explicit Surface(pugi::xml_node surf_node); - + virtual ~Surface() {} //! Determine which side of a surface a point lies on. @@ -110,6 +110,22 @@ protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; }; +//============================================================================== +//! A `Surface` representing a CAD-based surface in DAGMC. +//============================================================================== + +class CADSurface : public Surface +{ + public: + explicit CADSurface(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + //! Get the bounding box of this surface. + BoundingBox bounding_box() const; +}; + //============================================================================== //! A `Surface` that supports periodic boundary conditions. //! diff --git a/src/surface.cpp b/src/surface.cpp index d7f523ed6..a8aa8dfb6 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -239,6 +239,27 @@ Surface::to_hdf5(hid_t group_id) const close_group(surf_group); } +//============================================================================== +// CADSurface implementation +//============================================================================== + + CADSurface::CADSurface(pugi::xml_node surf_node) : Surface {surf_node} {} // empty constructor + +double CADSurface::evaluate(const double xyz[3]) const +{ + return 0.0; +} + +double CADSurface::distance(const double xyz[3], const double uvw[3], bool coincident) const { + return 0.0; +} + +void CADSurface::normal(const double xyz[3], double uvw[3]) const { + return; +} + +BoundingBox CADSurface::bounding_box() const { return BoundingBox(); } + //============================================================================== // PeriodicSurface implementation //============================================================================== From 85722f5e5f7f25abd87681465e4e363d80fb9d80 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 22 Feb 2018 21:17:03 -0600 Subject: [PATCH 004/175] Adding empty constructor to Surface. Might remove usefulness of explicit constructors. --- include/openmc/surface.h | 3 ++- src/surface.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 0d272de91..c03cea660 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -65,6 +65,7 @@ public: std::vector neighbor_neg_; //!< List of cells on negative side explicit Surface(pugi::xml_node surf_node); + explicit Surface(); virtual ~Surface() {} @@ -117,7 +118,7 @@ protected: class CADSurface : public Surface { public: - explicit CADSurface(pugi::xml_node surf_node); + explicit CADSurface(); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; diff --git a/src/surface.cpp b/src/surface.cpp index a8aa8dfb6..6f34f1f14 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -138,6 +138,8 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, // Surface implementation //============================================================================== +Surface::Surface() {} + Surface::Surface(pugi::xml_node surf_node) { if (check_for_node(surf_node, "id")) { @@ -243,7 +245,7 @@ Surface::to_hdf5(hid_t group_id) const // CADSurface implementation //============================================================================== - CADSurface::CADSurface(pugi::xml_node surf_node) : Surface {surf_node} {} // empty constructor +CADSurface::CADSurface() :Surface{} {} // empty constructor double CADSurface::evaluate(const double xyz[3]) const { From dcf3eb84ee20b31bf23155dd565da18dd1970378 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 22 Feb 2018 22:01:34 -0600 Subject: [PATCH 005/175] Adding CAD cell class and constructor. --- include/openmc/cell.h | 11 ++++++++++- src/cell.cpp | 8 +++++++- src/surface.cpp | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index fa5134b60..191458689 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -111,7 +111,10 @@ public: explicit Cell(pugi::xml_node cell_node); - //! \brief Determine if a cell contains the particle at a given location. + explicit Cell(); + + //! \brief Determine if a cell contains the particle at a given location. + //! Determine if a cell contains the particle at a given location. //! //! The bounds of the cell are detemined by a logical expression involving //! surface half-spaces. At initialization, the expression was converted @@ -146,5 +149,11 @@ protected: bool contains_complex(Position r, Direction u, int32_t on_surface) const; }; + class CADCell : public Cell +{ + explicit CADCell(); + +}; + } // namespace openmc #endif // OPENMC_CELL_H diff --git a/src/cell.cpp b/src/cell.cpp index e579b9db4..05bfdb9e9 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -209,6 +209,8 @@ Universe::to_hdf5(hid_t universes_group) const // Cell implementation //============================================================================== +Cell::Cell() {} // empty constructor + Cell::Cell(pugi::xml_node cell_node) { if (check_for_node(cell_node, "id")) { @@ -586,9 +588,13 @@ Cell::contains_complex(Position r, Direction u, int32_t on_surface) const } //============================================================================== -// Non-method functions +// CAD Cell implementation //============================================================================== +CADCell::CADCell() : Cell{} {}; + +//============================================================================== +// Non-method functions extern "C" void read_cells(pugi::xml_node* node) { diff --git a/src/surface.cpp b/src/surface.cpp index 6f34f1f14..5a9c15d10 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -138,7 +138,7 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, // Surface implementation //============================================================================== -Surface::Surface() {} +Surface::Surface() {} // empty constructor Surface::Surface(pugi::xml_node surf_node) { From fd7368e1bdd821bcc1165e57a63645590fdaf312 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 00:26:31 -0600 Subject: [PATCH 006/175] Adding dagmc pointers to the CAD geometry classes. --- CMakeLists.txt | 11 +++++++++++ cmake/FindDAGMC.cmake | 18 ++++++++++++++++++ include/openmc/cell.h | 3 +++ include/openmc/surface.h | 2 ++ src/cad.cpp | 5 +++++ src/cad.h | 4 ++++ 6 files changed, 43 insertions(+) create mode 100644 cmake/FindDAGMC.cmake create mode 100644 src/cad.cpp create mode 100644 src/cad.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 73863bc3b..37104da36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,17 @@ if(MPI_ENABLED AND mpif08) message("-- Using Fortran 2008 MPI bindings") endif() +#=============================================================================== +# CAD Geometry Support - need DAGMC/MOAB +#=============================================================================== +if(cad) + find_package(DAGMC REQUIRED) + if(NOT DAGMC_FOUND) + message(FATAL_ERROR "Could not find DAGMC installation") + endif() + include_directories(${DAGMC_INCLUDE_DIRS}) +endif() + #=============================================================================== # HDF5 for binary output #=============================================================================== diff --git a/cmake/FindDAGMC.cmake b/cmake/FindDAGMC.cmake new file mode 100644 index 000000000..f284bcbab --- /dev/null +++ b/cmake/FindDAGMC.cmake @@ -0,0 +1,18 @@ +# Try to find MOAB +# +# Once done this will define +# +# DAGMC_FOUND - system has DAGMC +# DAGMC_INCLUDE_DIRS - the DAGMC include directory +# DAGMC_LIBRARIES - Link these to use DAGMC +# DAGMC_DEFINITIONS - Compiler switches required for using DAGMC + +find_path(DAGMC_CMAKE_CONFIG NAMES DAGMCConfig.cmake + HINTS ${DAGMC_ROOT} + PATHS ENV LD_LIBRARY_PATH + PATH_SUFFIXES lib Lib cmake lib/cmake + NO_DEFAULT_PATH) + +message(STATUS "Found DAGMC in ${DAGMC_CMAKE_CONFIG}") + +include(${DAGMC_CMAKE_CONFIG}/DAGMCConfig.cmake) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 191458689..53d017508 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -13,6 +13,7 @@ #include "openmc/constants.h" #include "openmc/position.h" +#include "DagMC.hpp" namespace openmc { @@ -151,6 +152,8 @@ protected: class CADCell : public Cell { + moab::DagMC *dagmc_ptr; + explicit CADCell(); }; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index c03cea660..ace9cf6d7 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -12,6 +12,7 @@ #include "openmc/constants.h" #include "openmc/position.h" +#include "DagMC.hpp" namespace openmc { @@ -117,6 +118,7 @@ protected: class CADSurface : public Surface { + moab::DagMC* dagmc_ptr; public: explicit CADSurface(); double evaluate(const double xyz[3]) const; diff --git a/src/cad.cpp b/src/cad.cpp new file mode 100644 index 000000000..935b9d773 --- /dev/null +++ b/src/cad.cpp @@ -0,0 +1,5 @@ + +#include "cad.h" + +moab::DagMC* DAGMC; + diff --git a/src/cad.h b/src/cad.h new file mode 100644 index 000000000..74cb3cc5c --- /dev/null +++ b/src/cad.h @@ -0,0 +1,4 @@ + + +#include "DagMC.hpp" + From bc3a09283683782dcae5d6e883e8ef90411315fc Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 01:14:48 -0600 Subject: [PATCH 007/175] Linking to the MOAB/DAGMC libraries. --- CMakeLists.txt | 6 +++++- src/cad.cpp | 14 +++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37104da36..e7e9f54b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Set module path set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) +# Make sure Fortran module directory is included when building +include_directories(${CMAKE_BINARY_DIR}/include) #=============================================================================== # Command line options #=============================================================================== @@ -394,6 +396,8 @@ add_library(libopenmc SHARED src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 + src/cad.h + src/cad.cpp src/cell.cpp src/cmfd_execute.cpp src/distribution.cpp @@ -490,7 +494,7 @@ target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml add_executable(openmc src/main.cpp) target_compile_options(openmc PRIVATE ${cxxflags}) -target_link_libraries(openmc libopenmc) +target_link_libraries(openmc ${ldflags} libopenmc ${DAGMC_LINK_LIBS}) #=============================================================================== # Python package diff --git a/src/cad.cpp b/src/cad.cpp index 935b9d773..3b4d45436 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -1,5 +1,17 @@ #include "cad.h" -moab::DagMC* DAGMC; +namespace moab { + +DagMC* DAGMC; + +void load_geometry() { + if(!DAGMC) { DAGMC = new DagMC(); } + + ErrorCode rval; + + return; +} + +} From 45ccb2da169bd328ac18bdcc6bbd11c4c7fadf58 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 01:31:26 -0600 Subject: [PATCH 008/175] Adding option for building with CAD support and moving FindDAGMC into the correct location for openmc cmake modules. --- CMakeLists.txt | 3 +++ cmake/{ => Modules}/FindDAGMC.cmake | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) rename cmake/{ => Modules}/FindDAGMC.cmake (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7e9f54b7..dfb69dec1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,9 @@ option(debug "Compile with debug flags" OFF) option(optimize "Turn on all compiler optimization flags" OFF) option(coverage "Compile with coverage analysis flags" OFF) option(mpif08 "Use Fortran 2008 MPI interface" OFF) +option(cad "Enable support for CAD-based geometry" OFF) + +# Maximum number of nested coordinates levels set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels") #=============================================================================== diff --git a/cmake/FindDAGMC.cmake b/cmake/Modules/FindDAGMC.cmake similarity index 96% rename from cmake/FindDAGMC.cmake rename to cmake/Modules/FindDAGMC.cmake index f284bcbab..63a8a3469 100644 --- a/cmake/FindDAGMC.cmake +++ b/cmake/Modules/FindDAGMC.cmake @@ -1,4 +1,4 @@ -# Try to find MOAB +# Try to find DAGMC # # Once done this will define # From 0e0bb25591ac633dd0357cb72ff9de36c5f0a895 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 02:07:36 -0600 Subject: [PATCH 009/175] Getting infrastrucure setup for loading a CAD model and creating cell instances. --- CMakeLists.txt | 1 + include/openmc/cell.h | 5 +++-- src/cad.cpp | 29 ++++++++++++++++++++++------- src/cad.h | 7 ++++++- src/cad_header.F90 | 19 +++++++++++++++++++ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/cad_header.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb69dec1..bfdf76e8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,6 +311,7 @@ add_library(libopenmc SHARED src/algorithm.F90 src/bank_header.F90 src/api.F90 + src/cad_header.F90 src/cmfd_data.F90 src/cmfd_execute.F90 src/cmfd_header.F90 diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 53d017508..6a4f9567a 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -150,10 +150,11 @@ protected: bool contains_complex(Position r, Direction u, int32_t on_surface) const; }; - class CADCell : public Cell +class CADCell : public Cell { moab::DagMC *dagmc_ptr; - + + public: explicit CADCell(); }; diff --git a/src/cad.cpp b/src/cad.cpp index 3b4d45436..d67a5d5d2 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -1,16 +1,31 @@ #include "cad.h" +extern moab::DagMC* DAGMC; namespace moab { + +void load_cad_geometry_c() +{ + if(!DAGMC) { + DAGMC = new DagMC(); + } + + ErrorCode rval = DAGMC->load_file("dagmc.h5m"); + MB_CHK_ERR_CONT(rval); + + rval = DAGMC->init_OBBTree(); + MB_CHK_ERR_CONT(rval); + + // initialize cell objects + for(int i = 0; i < DAGMC->num_entities(3); i++){ + + // set cell ids using global IDs + openmc::CADCell c = openmc::CADCell(); + c.id = DAGMC->id_by_index(3, 0); + openmc::cells_c.push_back(c); + } -DagMC* DAGMC; - -void load_geometry() { - if(!DAGMC) { DAGMC = new DagMC(); } - - ErrorCode rval; - return; } diff --git a/src/cad.h b/src/cad.h index 74cb3cc5c..adef8f432 100644 --- a/src/cad.h +++ b/src/cad.h @@ -1,4 +1,9 @@ - +#ifndef CAD_H +#define CAD_H #include "DagMC.hpp" +#include "cell.h" +extern "C" void load_cad_geometry_c(); + +#endif // CAD_H diff --git a/src/cad_header.F90 b/src/cad_header.F90 new file mode 100644 index 000000000..91176eaf9 --- /dev/null +++ b/src/cad_header.F90 @@ -0,0 +1,19 @@ +module cad_header + + use, intrinsic :: ISO_C_BINDING + use hdf5 + + implicit none + + interface + subroutine load_cad_geometry_c() bind(C) + end subroutine load_cad_geometry_c + end interface + +contains + + subroutine load_cad_geometry() + call load_cad_geometry_c() + end subroutine load_cad_geometry + +end module cad_header From 6f9037997d6f867e4d8a4f223f2f089b39817054 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 10:40:43 -0600 Subject: [PATCH 010/175] Updating build s.t. DAGMC is not required for a standard build. Corrections to exposing variables as global. --- CMakeLists.txt | 13 ++++++++++--- include/openmc/cell.h | 7 +++++-- include/openmc/surface.h | 6 ++++-- src/cad.cpp | 26 +++++++++----------------- src/cell.cpp | 11 ++++++++++- src/surface.cpp | 4 ++-- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bfdf76e8f..22f0ff7b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ if(cad) if(NOT DAGMC_FOUND) message(FATAL_ERROR "Could not find DAGMC installation") endif() + add_definitions(-DCAD) include_directories(${DAGMC_INCLUDE_DIRS}) endif() @@ -311,7 +312,6 @@ add_library(libopenmc SHARED src/algorithm.F90 src/bank_header.F90 src/api.F90 - src/cad_header.F90 src/cmfd_data.F90 src/cmfd_execute.F90 src/cmfd_header.F90 @@ -447,6 +447,14 @@ add_library(libopenmc SHARED src/thermal.cpp src/xml_interface.cpp src/xsdata.cpp) + +# add cad sources if enabled +if(cad) + list(APPEND LIBOPENMC_FORTRAN_SRC src/cad_header.F90) + list(APPEND LIBOPENMC_CXX_SRC src/cad.h src/cad.cpp) +endif() + +add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc LINKER_LANGUAGE Fortran) @@ -490,12 +498,11 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml - faddeeva xtensor) + faddeeva xtensor ${DAGMC_LINK_LIBS}) #=============================================================================== # openmc executable #=============================================================================== - add_executable(openmc src/main.cpp) target_compile_options(openmc PRIVATE ${cxxflags}) target_link_libraries(openmc ${ldflags} libopenmc ${DAGMC_LINK_LIBS}) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 6a4f9567a..41209246e 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -13,7 +13,9 @@ #include "openmc/constants.h" #include "openmc/position.h" +#ifdef CAD #include "DagMC.hpp" +#endif namespace openmc { @@ -150,14 +152,15 @@ protected: bool contains_complex(Position r, Direction u, int32_t on_surface) const; }; +#ifdef CAD class CADCell : public Cell { moab::DagMC *dagmc_ptr; public: - explicit CADCell(); - + explicit CADCell(); }; +#endif } // namespace openmc #endif // OPENMC_CELL_H diff --git a/include/openmc/surface.h b/include/openmc/surface.h index ace9cf6d7..61ae8ef53 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -12,7 +12,9 @@ #include "openmc/constants.h" #include "openmc/position.h" +#ifdef CAD #include "DagMC.hpp" +#endif namespace openmc { @@ -115,7 +117,7 @@ protected: //============================================================================== //! A `Surface` representing a CAD-based surface in DAGMC. //============================================================================== - +#ifdef CAD class CADSurface : public Surface { moab::DagMC* dagmc_ptr; @@ -128,7 +130,7 @@ class CADSurface : public Surface //! Get the bounding box of this surface. BoundingBox bounding_box() const; }; - +#endif //============================================================================== //! A `Surface` that supports periodic boundary conditions. //! diff --git a/src/cad.cpp b/src/cad.cpp index d67a5d5d2..f07c8cd39 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -1,32 +1,24 @@ #include "cad.h" -extern moab::DagMC* DAGMC; - -namespace moab { - void load_cad_geometry_c() { - if(!DAGMC) { - DAGMC = new DagMC(); - } + moab::DagMC* DAGMC = new moab::DagMC(); - ErrorCode rval = DAGMC->load_file("dagmc.h5m"); + moab::ErrorCode rval = DAGMC->load_file("dagmc.h5m"); MB_CHK_ERR_CONT(rval); rval = DAGMC->init_OBBTree(); MB_CHK_ERR_CONT(rval); // initialize cell objects - for(int i = 0; i < DAGMC->num_entities(3); i++){ - - // set cell ids using global IDs - openmc::CADCell c = openmc::CADCell(); - c.id = DAGMC->id_by_index(3, 0); - openmc::cells_c.push_back(c); - } + for(int i = 0; i < DAGMC->num_entities(3); i++) + { + // set cell ids using global IDs + openmc::CADCell c = openmc::CADCell(); + c.id = DAGMC->id_by_index(3, i); + openmc::cells_c.push_back(c); + } return; } - -} diff --git a/src/cell.cpp b/src/cell.cpp index 05bfdb9e9..b417b1199 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -15,9 +15,17 @@ #include "openmc/surface.h" #include "openmc/xml_interface.h" +//TODO: remove this include +#include + +extern "C" {int32_t n_cells {0};} namespace openmc { +std::vector cells_c; + +std::map cell_dict; + //============================================================================== // Global variables //============================================================================== @@ -590,8 +598,9 @@ Cell::contains_complex(Position r, Direction u, int32_t on_surface) const //============================================================================== // CAD Cell implementation //============================================================================== - +#ifdef CAD CADCell::CADCell() : Cell{} {}; +#endif //============================================================================== // Non-method functions diff --git a/src/surface.cpp b/src/surface.cpp index 5a9c15d10..0111d77bc 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -244,7 +244,7 @@ Surface::to_hdf5(hid_t group_id) const //============================================================================== // CADSurface implementation //============================================================================== - +#ifdef CAD CADSurface::CADSurface() :Surface{} {} // empty constructor double CADSurface::evaluate(const double xyz[3]) const @@ -261,7 +261,7 @@ void CADSurface::normal(const double xyz[3], double uvw[3]) const { } BoundingBox CADSurface::bounding_box() const { return BoundingBox(); } - +#endif //============================================================================== // PeriodicSurface implementation //============================================================================== From cb45c97b70d52ae6b8a4b9f74b3906560de15ac5 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 11:21:53 -0600 Subject: [PATCH 011/175] Adding Surface population in CAD. Creating a derived CSGSurfce class for support of (currently) non-CAD operations related to hdf5 summary files. --- include/openmc/cell.h | 5 ++--- include/openmc/surface.h | 35 ++++++++++++++++++++++------------- src/cad.cpp | 23 +++++++++++++++++++++-- src/cad.h | 1 + src/cell.cpp | 2 +- src/surface.cpp | 35 +++++++++++++++++++++++++---------- 6 files changed, 72 insertions(+), 29 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 41209246e..f819d41f4 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -155,10 +155,9 @@ protected: #ifdef CAD class CADCell : public Cell { - moab::DagMC *dagmc_ptr; - public: - explicit CADCell(); + moab::DagMC *dagmc_ptr; + explicit CADCell(); }; #endif diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 61ae8ef53..8a6b340ed 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -105,23 +105,32 @@ public: //! \return Normal direction virtual Direction normal(Position r) const = 0; +}; + +class CSGSurface : public Surface +{ + public: + explicit CSGSurface(pugi::xml_node surf_node); + explicit CSGSurface(); + //! Write all information needed to reconstruct the surface to an HDF5 group. //! \param group_id An HDF5 group id. //TODO: this probably needs to include i_periodic for PeriodicSurface void to_hdf5(hid_t group_id) const; -protected: - virtual void to_hdf5_inner(hid_t group_id) const = 0; + + protected: + virtual void to_hdf5_inner(hid_t group_id) const = 0; }; - + //============================================================================== //! A `Surface` representing a CAD-based surface in DAGMC. //============================================================================== #ifdef CAD class CADSurface : public Surface { - moab::DagMC* dagmc_ptr; public: + moab::DagMC* dagmc_ptr; explicit CADSurface(); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], @@ -139,7 +148,7 @@ class CADSurface : public Surface //! `XPlane`-`YPlane` pairs. //============================================================================== -class PeriodicSurface : public Surface +class PeriodicSurface : public CSGSurface { public: int i_periodic_{C_NONE}; //!< Index of corresponding periodic surface @@ -248,7 +257,7 @@ public: //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceXCylinder : public Surface +class SurfaceXCylinder : public CSGSurface { double y0_, z0_, radius_; public: @@ -266,7 +275,7 @@ public: //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceYCylinder : public Surface +class SurfaceYCylinder : public CSGSurface { double x0_, z0_, radius_; public: @@ -284,7 +293,7 @@ public: //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceZCylinder : public Surface +class SurfaceZCylinder : public CSGSurface { double x0_, y0_, radius_; public: @@ -302,7 +311,7 @@ public: //! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceSphere : public Surface +class SurfaceSphere : public CSGSurface { double x0_, y0_, z0_, radius_; public: @@ -320,7 +329,7 @@ public: //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ //============================================================================== -class SurfaceXCone : public Surface +class SurfaceXCone : public CSGSurface { double x0_, y0_, z0_, radius_sq_; public: @@ -338,7 +347,7 @@ public: //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ //============================================================================== -class SurfaceYCone : public Surface +class SurfaceYCone : public CSGSurface { double x0_, y0_, z0_, radius_sq_; public: @@ -356,7 +365,7 @@ public: //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ //============================================================================== -class SurfaceZCone : public Surface +class SurfaceZCone : public CSGSurface { double x0_, y0_, z0_, radius_sq_; public: @@ -373,7 +382,7 @@ public: //! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = 0\f$ //============================================================================== -class SurfaceQuadric : public Surface +class SurfaceQuadric : public CSGSurface { // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_; diff --git a/src/cad.cpp b/src/cad.cpp index f07c8cd39..90b325866 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -1,9 +1,13 @@ #include "cad.h" +moab::DagMC* DAGMC; + void load_cad_geometry_c() { - moab::DagMC* DAGMC = new moab::DagMC(); + if(!DAGMC) { + DAGMC = new moab::DagMC(); + } moab::ErrorCode rval = DAGMC->load_file("dagmc.h5m"); MB_CHK_ERR_CONT(rval); @@ -12,13 +16,28 @@ void load_cad_geometry_c() MB_CHK_ERR_CONT(rval); // initialize cell objects - for(int i = 0; i < DAGMC->num_entities(3); i++) + openmc::n_cells = DAGMC->num_entities(3); + for(int i = 0; i < openmc::n_cells; i++) { // set cell ids using global IDs openmc::CADCell c = openmc::CADCell(); c.id = DAGMC->id_by_index(3, i); + c.dagmc_ptr = DAGMC; openmc::cells_c.push_back(c); } + + // initialize surface objects + openmc::n_surfaces = DAGMC->num_entities(2); + openmc::surfaces_c = new openmc::Surface*[openmc::n_surfaces]; + for(int i = 0; i < openmc::n_surfaces; i++) + { + // set cell ids using global IDs + openmc::CADSurface* s = new openmc::CADSurface(); + s->id = DAGMC->id_by_index(2, i); + s->dagmc_ptr = DAGMC; + openmc::surfaces_c[i] = s; + } + return; } diff --git a/src/cad.h b/src/cad.h index adef8f432..f88c4be3f 100644 --- a/src/cad.h +++ b/src/cad.h @@ -3,6 +3,7 @@ #include "DagMC.hpp" #include "cell.h" +#include "surface.h" extern "C" void load_cad_geometry_c(); diff --git a/src/cell.cpp b/src/cell.cpp index b417b1199..35c69f371 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -601,7 +601,7 @@ Cell::contains_complex(Position r, Direction u, int32_t on_surface) const #ifdef CAD CADCell::CADCell() : Cell{} {}; #endif - + //============================================================================== // Non-method functions extern "C" void diff --git a/src/surface.cpp b/src/surface.cpp index 0111d77bc..53d9d2eeb 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -179,6 +179,7 @@ Surface::Surface(pugi::xml_node surf_node) } + bool Surface::sense(Position r, Direction u) const { @@ -209,8 +210,11 @@ Surface::reflect(Position r, Direction u) const return u -= (2.0 * projection / magnitude) * n; } +CSGSurface::CSGSurface() : Surface{} {}; +CSGSurface::CSGSurface(pugi::xml_node surf_node) : Surface{surf_node} {}; + void -Surface::to_hdf5(hid_t group_id) const +CSGSurface::to_hdf5(hid_t group_id) const { std::string group_name {"surface "}; group_name += std::to_string(id_); @@ -267,7 +271,7 @@ BoundingBox CADSurface::bounding_box() const { return BoundingBox(); } //============================================================================== PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) - : Surface {surf_node} + : CSGSurface {surf_node} { if (check_for_node(surf_node, "periodic_surface_id")) { i_periodic_ = std::stoi(get_node_value(surf_node, "periodic_surface_id")); @@ -603,7 +607,7 @@ axis_aligned_cylinder_normal(Position r, double offset1, double offset2) //============================================================================== SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, y0_, z0_, radius_); } @@ -637,7 +641,7 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const //============================================================================== SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, x0_, z0_, radius_); } @@ -670,7 +674,7 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const //============================================================================== SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, x0_, y0_, radius_); } @@ -703,7 +707,7 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const //============================================================================== SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_); } @@ -856,7 +860,7 @@ axis_aligned_cone_normal(Position r, double offset1, double offset2, //============================================================================== SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } @@ -889,7 +893,7 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const //============================================================================== SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } @@ -922,7 +926,7 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const //============================================================================== SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } @@ -955,7 +959,7 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const //============================================================================== SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { read_coeffs(surf_node, id_, A_, B_, C_, D_, E_, F_, G_, H_, J_, K_); } @@ -1253,6 +1257,17 @@ extern "C" { int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic_;} + void surface_normal(Surface* surf, double xyz[3], double uvw[3]) + { + Position r {xyz}; + Direction u = surf->normal(r); + uvw[0] = u.x; + uvw[1] = u.y; + uvw[2] = u.z; + } + + void surface_to_hdf5(CSGSurface* surf, hid_t group) {surf->to_hdf5(group);} + bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], double uvw[3]) From 0df290f3a33473efeefc5d8e16764ee12adb9e89 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 11:22:12 -0600 Subject: [PATCH 012/175] Adding a deallocation method for CAD pointer. --- src/cad.cpp | 5 +++++ src/cad.h | 1 + src/cad_header.F90 | 12 ++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index 90b325866..58eeeff48 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -41,3 +41,8 @@ void load_cad_geometry_c() return; } + +void dealloc_cad_c() +{ + delete DAGMC; +} diff --git a/src/cad.h b/src/cad.h index f88c4be3f..c3dc49715 100644 --- a/src/cad.h +++ b/src/cad.h @@ -6,5 +6,6 @@ #include "surface.h" extern "C" void load_cad_geometry_c(); +extern "C" void dealloc_cad_c(); #endif // CAD_H diff --git a/src/cad_header.F90 b/src/cad_header.F90 index 91176eaf9..1fc6dbf16 100644 --- a/src/cad_header.F90 +++ b/src/cad_header.F90 @@ -8,12 +8,20 @@ module cad_header interface subroutine load_cad_geometry_c() bind(C) end subroutine load_cad_geometry_c + + subroutine dealloc_cad_c() bind(C) + end subroutine dealloc_cad_c + end interface - + contains subroutine load_cad_geometry() call load_cad_geometry_c() end subroutine load_cad_geometry - + + subroutine dealloc_cad() + call dealloc_cad_c() + end subroutine dealloc_cad + end module cad_header From 88a41cbb85de1a9bbfddf17c387454f5ffe717a2 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 12:38:41 -0600 Subject: [PATCH 013/175] Loading CAD file based on geometry flag from settings.xml --- src/api.F90 | 10 +++++++++- src/cad.cpp | 2 +- src/cad.h | 4 +++- src/cad_header.F90 | 10 +++++----- src/constants.F90 | 5 +++++ src/input_xml.F90 | 18 ++++++++++++++++++ src/settings.F90 | 3 +++ src/xml_interface.F90 | 1 + 8 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index b39a2f8fa..05d276015 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -29,6 +29,10 @@ module openmc_api use timer_header use volume_calc, only: openmc_calculate_volumes +#ifdef CAD + use cad_header, only: free_memory_cad +#endif + implicit none private @@ -149,6 +153,7 @@ contains root_universe = -1 run_CE = .true. run_mode = -1 + dagmc = .false. satisfy_triggers = .false. call openmc_set_seed(DEFAULT_SEED) source_latest = .false. @@ -325,7 +330,10 @@ contains call free_memory_tally_filter() call free_memory_tally_derivative() call free_memory_bank() - +#ifdef CAD + call free_memory_cad() +#endif + ! Deallocate CMFD call deallocate_cmfd(cmfd) diff --git a/src/cad.cpp b/src/cad.cpp index 58eeeff48..325fda9de 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -42,7 +42,7 @@ void load_cad_geometry_c() return; } -void dealloc_cad_c() +void free_memory_cad_c() { delete DAGMC; } diff --git a/src/cad.h b/src/cad.h index c3dc49715..ff2540841 100644 --- a/src/cad.h +++ b/src/cad.h @@ -5,7 +5,9 @@ #include "cell.h" #include "surface.h" +extern moab::DagMC* DAGMC; + extern "C" void load_cad_geometry_c(); -extern "C" void dealloc_cad_c(); +extern "C" void free_memory_cad_c(); #endif // CAD_H diff --git a/src/cad_header.F90 b/src/cad_header.F90 index 1fc6dbf16..3c53254c9 100644 --- a/src/cad_header.F90 +++ b/src/cad_header.F90 @@ -9,8 +9,8 @@ module cad_header subroutine load_cad_geometry_c() bind(C) end subroutine load_cad_geometry_c - subroutine dealloc_cad_c() bind(C) - end subroutine dealloc_cad_c + subroutine free_memory_cad_c() bind(C) + end subroutine free_memory_cad_c end interface @@ -20,8 +20,8 @@ contains call load_cad_geometry_c() end subroutine load_cad_geometry - subroutine dealloc_cad() - call dealloc_cad_c() - end subroutine dealloc_cad + subroutine free_memory_cad() + call free_memory_cad_c() + end subroutine free_memory_cad end module cad_header diff --git a/src/constants.F90 b/src/constants.F90 index a3118f84d..80c1d2322 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -429,7 +429,12 @@ module constants MODE_EIGENVALUE = 2, & ! K eigenvalue mode MODE_PLOTTING = 3, & ! Plotting mode MODE_PARTICLE = 4, & ! Particle restart mode +#ifdef CAD + MODE_VOLUME = 5, & ! Volume calculation mode + MODE_CAD = 6 ! CAD-based Geometry mode +#else MODE_VOLUME = 5 ! Volume calculation mode +#endif ! Electron treatments integer, parameter :: & diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 7361dd85b..16c107d13 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,6 +11,7 @@ module input_xml use error, only: fatal_error, warning, write_message, openmc_err_msg use geometry, only: neighbor_lists use geometry_header + use cad_header use hdf5_interface use list_header, only: ListChar, ListInt, ListReal use material_header @@ -216,6 +217,17 @@ contains ! Get proper XMLNode type given pointer root % ptr = root_ptr + ! Check for use of CAD geometry + if (check_for_node(root, "dagmc")) then +#ifdef CAD + call get_node_value_bool(root, "dagmc", dagmc) +#else + if (dagmc) then + call fatal_error("CAD mode unsupported for this build of OpenMC") + end if +#endif + end if + if (run_mode == MODE_EIGENVALUE) then ! Preallocate space for keff and entropy by generation call k_generation % reserve(n_max_batches*gen_per_batch) @@ -375,6 +387,12 @@ contains type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each ! universe contains + if (dagmc) then + call write_message("Reading CAD geometry...", 5) + call load_cad_geometry() + return + end if + ! Display output message call write_message("Reading geometry XML file...", 5) diff --git a/src/settings.F90 b/src/settings.F90 index ec7bbf2c8..4efe25102 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -80,6 +80,9 @@ module settings ! Mode to run in (fixed source, eigenvalue, plotting, etc) integer(C_INT), bind(C) :: run_mode + ! flag for use of CAD geometry + logical, bind(C) :: dagmc = .false. + ! Restart run logical(C_BOOL), bind(C) :: restart_run diff --git a/src/xml_interface.F90 b/src/xml_interface.F90 index 7aa86556b..39c6330ec 100644 --- a/src/xml_interface.F90 +++ b/src/xml_interface.F90 @@ -12,6 +12,7 @@ module xml_interface public :: check_for_node public :: get_node_list public :: get_node_value + public :: get_node_value_bool public :: get_node_array public :: node_value_string public :: node_word_count From 9331cb8945f19e011c0358adc3234e3e9e7c0084 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 15:12:01 -0600 Subject: [PATCH 014/175] Factoring out cell and surface allocation on the fortran side. --- src/input_xml.F90 | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 16c107d13..41ab30d28 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -390,6 +390,8 @@ contains if (dagmc) then call write_message("Reading CAD geometry...", 5) call load_cad_geometry() + call allocate_surfaces() + call allocate_cells() return end if @@ -417,16 +419,12 @@ contains call read_surfaces(root % ptr) + call allocate_surfaces() ! Allocate surfaces array - allocate(surfaces(n_surfaces)) - do i = 1, n_surfaces surfaces(i) % ptr = surface_pointer(i - 1); if (surfaces(i) % bc() /= BC_TRANSMIT) boundary_exists = .true. - - ! Add surface to dictionary - call surface_dict % set(surfaces(i) % id(), i) end do ! Check to make sure a boundary condition was applied to at least one @@ -453,8 +451,6 @@ contains call fatal_error("No cells found in geometry.xml!") end if - ! Allocate cells array - allocate(cells(n_cells)) n_universes = 0 do i = 1, n_cells @@ -577,6 +573,29 @@ contains end subroutine read_geometry_xml + subroutine allocate_surfaces() + integer :: i + + ! Allocate surfaces array + allocate(surfaces(n_surfaces)) + + do i = 1, n_surfaces + surfaces(i) % ptr = surface_pointer_c(i - 1); + ! Add surface to dictionary + call surface_dict % set(surfaces(i) % id(), i) + end do + + end subroutine allocate_surfaces + + subroutine allocate_cells() + integer :: i + ! Allocate cells array + allocate(cells(n_cells)) + do i = 1, n_cells + cells(i) % ptr = cell_pointer_c(i - 1) + end do + end subroutine allocate_cells + !=============================================================================== ! READ_MATERIAL_XML reads data from a materials.xml file and parses it, checking ! for errors and placing properly-formatted data in the right data structures From 2a1d449709aaa67da7d22c3e63b55b418397f554 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 23 Feb 2018 15:12:34 -0600 Subject: [PATCH 015/175] Setting all cell universes to zero for CAD. --- src/cad.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cad.cpp b/src/cad.cpp index 325fda9de..ff22f235f 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -23,6 +23,7 @@ void load_cad_geometry_c() openmc::CADCell c = openmc::CADCell(); c.id = DAGMC->id_by_index(3, i); c.dagmc_ptr = DAGMC; + c.universe = 0; // set to zero for now openmc::cells_c.push_back(c); } From c02f8c0b486c8c3ffc887d2a601b2f881c1900a1 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sun, 25 Feb 2018 08:25:49 -0600 Subject: [PATCH 016/175] Setting index values in cell and surface dictionaries --- src/cad.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cad.cpp b/src/cad.cpp index ff22f235f..970046041 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -25,6 +25,7 @@ void load_cad_geometry_c() c.dagmc_ptr = DAGMC; c.universe = 0; // set to zero for now openmc::cells_c.push_back(c); + openmc::cell_dict[c.id] = i; } // initialize surface objects @@ -38,6 +39,7 @@ void load_cad_geometry_c() s->id = DAGMC->id_by_index(2, i); s->dagmc_ptr = DAGMC; openmc::surfaces_c[i] = s; + openmc::surface_dict[s->id] = i; } return; From 24f52cd3deb1e804584d0baed3fb0c5494a1b4f9 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sun, 25 Feb 2018 08:55:20 -0600 Subject: [PATCH 017/175] Adding dagmc attribute to the settings class. --- openmc/settings.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openmc/settings.py b/openmc/settings.py index efe41b2a1..ef0cfe396 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -92,6 +92,8 @@ class Settings(object): Indicate if coarse mesh finite difference acceleration is to be used run_mode : {'eigenvalue', 'fixed source', 'plot', 'volume', 'particle restart'} The type of calculation to perform (default is 'eigenvalue') + dagmc : bool + Enables CAD-based geometry through DAGMC (default False) seed : int Seed for the linear congruential pseudorandom number generator source : Iterable of openmc.Source @@ -162,6 +164,7 @@ class Settings(object): # Run mode subelement (default is 'eigenvalue') self._run_mode = 'eigenvalue' + self._dagmc = False self._batches = None self._generations_per_batch = None self._inactive = None @@ -228,6 +231,10 @@ class Settings(object): def run_mode(self): return self._run_mode + @property + def dagmc(self): + return self._dagmc + @property def batches(self): return self._batches @@ -373,6 +380,11 @@ class Settings(object): cv.check_value('run mode', run_mode, _RUN_MODES) self._run_mode = run_mode + @dagmc.setter + def dagmc(self, dagmc): + cv.check_type('dagmc', dagmc, bool) + self._dagmc = dagmc + @batches.setter def batches(self, batches): cv.check_type('batches', batches, Integral) @@ -706,6 +718,10 @@ class Settings(object): elem = ET.SubElement(root, "run_mode") elem.text = self._run_mode + def _create_dagmc_subelement(self, root): + elem = ET.Subelement(root, "dagmc") + elem.text = str(self._dagmc).lower() + def _create_batches_subelement(self, run_mode_element): if self._batches is not None: element = ET.SubElement(run_mode_element, "batches") @@ -959,6 +975,7 @@ class Settings(object): root_element = ET.Element("settings") self._create_run_mode_subelement(root_element) + self._create_dagmc_subelement(root_element) self._create_particles_subelement(root_element) self._create_batches_subelement(root_element) self._create_inactive_subelement(root_element) From 3363075abed77fa39700f592181ef92465ce0afc Mon Sep 17 00:00:00 2001 From: shriwise Date: Sun, 25 Feb 2018 14:46:53 -0600 Subject: [PATCH 018/175] Adding allocate_cells call and wrapping cad commands in an ifdef. --- src/input_xml.F90 | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 41ab30d28..77ffe6e4f 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,7 +11,9 @@ module input_xml use error, only: fatal_error, warning, write_message, openmc_err_msg use geometry, only: neighbor_lists use geometry_header +#ifdef CAD use cad_header +#endif use hdf5_interface use list_header, only: ListChar, ListInt, ListReal use material_header @@ -386,7 +388,7 @@ contains type(VectorInt) :: univ_ids ! List of all universe IDs type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each ! universe contains - +#ifdef CAD if (dagmc) then call write_message("Reading CAD geometry...", 5) call load_cad_geometry() @@ -394,7 +396,8 @@ contains call allocate_cells() return end if - +#endif + ! Display output message call write_message("Reading geometry XML file...", 5) @@ -440,6 +443,8 @@ contains call read_cells(root % ptr) + call allocate_cells() + ! Get pointer to list of XML call get_node_list(root, "cell", node_cell_list) @@ -589,10 +594,25 @@ contains subroutine allocate_cells() integer :: i + type(Cell), pointer :: c + ! Allocate cells array allocate(cells(n_cells)) + do i = 1, n_cells - cells(i) % ptr = cell_pointer_c(i - 1) + c => cells(i) + + c % ptr = cell_pointer_c(i - 1) + + ! Check to make sure 'id' hasn't been used + if (cell_dict % has(c % id())) then + call fatal_error("Two or more cells use the same unique ID: " & + // to_str(c % id())) + end if + + ! Add cell to dictionary + call cell_dict % set(c % id(), i) + end do end subroutine allocate_cells From 8dc0ba2b6227d91b5cd6084d62118cc24b0b97ef Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 28 Feb 2018 10:03:59 -0600 Subject: [PATCH 019/175] Updating build variables in favor of better CMake practices. --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22f0ff7b0..57f3ee64f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ if(cad) message(FATAL_ERROR "Could not find DAGMC installation") endif() add_definitions(-DCAD) + link_directories(${DAGMC_LIBRARY_DIRS}) include_directories(${DAGMC_INCLUDE_DIRS}) endif() @@ -497,15 +498,15 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. -target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml - faddeeva xtensor ${DAGMC_LINK_LIBS}) +target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml_fortran + faddeeva xtensor ${DAGMC_LIBRARIES}) #=============================================================================== # openmc executable #=============================================================================== add_executable(openmc src/main.cpp) target_compile_options(openmc PRIVATE ${cxxflags}) -target_link_libraries(openmc ${ldflags} libopenmc ${DAGMC_LINK_LIBS}) +target_link_libraries(openmc ${ldflags} libopenmc ${DAGMC_LIBRARIES}) #=============================================================================== # Python package From 3f2fc67d0b52b8d66b7405fb40865962ac2a9e56 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 15 May 2018 11:55:09 -0500 Subject: [PATCH 020/175] Adding code for handling universes and other Fortran-side cell attributes. Skipping geometry writeout for CAD runs for now. --- src/cad.cpp | 1 + src/input_xml.F90 | 69 ++++++++++++++++++++++++++++++++++++++++++++++- src/summary.cpp | 8 ++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/cad.cpp b/src/cad.cpp index 970046041..8ca5c26cb 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -38,6 +38,7 @@ void load_cad_geometry_c() openmc::CADSurface* s = new openmc::CADSurface(); s->id = DAGMC->id_by_index(2, i); s->dagmc_ptr = DAGMC; + s->bc = openmc::BC_TRANSMIT; openmc::surfaces_c[i] = s; openmc::surface_dict[s->id] = i; } diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 77ffe6e4f..95af050ed 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -180,7 +180,7 @@ contains ! After reading input and basic geometry setup is complete, build lists of ! neighboring cells for efficient tracking call neighbor_lists() - + ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() @@ -394,6 +394,73 @@ contains call load_cad_geometry() call allocate_surfaces() call allocate_cells() + + ! setup universe data structs + do i = 1, n_cells + c => cells(i) + ! additional metadata spoofing + allocate(c % material(1)) + c % material(1) = 40 + c % fill = NONE + allocate(c % sqrtKT(1)) + c % sqrtkT(1) = 293 + c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) + univ_id = c % universe() + if (.not. allocated(c%region)) allocate(c%region(0)) + + if (.not. cells_in_univ_dict % has(univ_id)) then + n_universes = n_universes + 1 + n_cells_in_univ = 1 + call universe_dict % set(univ_id, n_universes) + call univ_ids % push_back(univ_id) + else + n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) + end if + call cells_in_univ_dict % set(univ_id, n_cells_in_univ) + + end do + + ! ========================================================================== + ! SETUP UNIVERSES + + ! Allocate universes, universe cell arrays, and assign base universe + allocate(universes(n_universes)) + do i = 1, n_universes + associate (u => universes(i)) + u % id = univ_ids % data(i) + + ! Allocate cell list + n_cells_in_univ = cells_in_univ_dict % get(u % id) + allocate(u % cells(n_cells_in_univ)) + u % cells(:) = 0 + + ! Check whether universe is a fill universe + if (find(fill_univ_ids, u % id) == -1) then + if (root_universe > 0) then + call fatal_error("Two or more universes are not used as fill & + &universes, so it is not possible to distinguish which one & + &is the root universe.") + else + root_universe = i + end if + end if + end associate + end do + + do i = 1, n_cells + ! Get index in universes array + j = universe_dict % get(cells(i) % universe()) + + ! Set the first zero entry in the universe cells array to the index in the + ! global cells array + associate (u => universes(j)) + u % cells(find(u % cells, 0)) = i + end associate + end do + + ! Clear dictionary + call cells_in_univ_dict%clear() + return end if #endif diff --git a/src/summary.cpp b/src/summary.cpp index d103e78b9..c371eb56c 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -8,6 +8,14 @@ namespace openmc { extern "C" void write_geometry(hid_t file_id) { + +#ifdef CAD + if (dagmc) { + return; + } +#endif + + auto geom_group = create_group(file_id, "geometry"); write_attribute(geom_group, "n_cells", cells.size()); write_attribute(geom_group, "n_surfaces", surfaces.size()); From 8e5f424ae121699f8e6bdc1c89eaddde54955f93 Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 16 May 2018 13:40:03 -0500 Subject: [PATCH 021/175] Resolving some duplicate code from the rebase. --- src/cad.cpp | 2 +- src/cad_header.F90 | 1 - src/cell.cpp | 4 ---- src/input_xml.F90 | 16 +++------------- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index 8ca5c26cb..790a88f76 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -24,7 +24,7 @@ void load_cad_geometry_c() c.id = DAGMC->id_by_index(3, i); c.dagmc_ptr = DAGMC; c.universe = 0; // set to zero for now - openmc::cells_c.push_back(c); + openmc::cells_c.push_back(&c); openmc::cell_dict[c.id] = i; } diff --git a/src/cad_header.F90 b/src/cad_header.F90 index 3c53254c9..403e0782b 100644 --- a/src/cad_header.F90 +++ b/src/cad_header.F90 @@ -1,7 +1,6 @@ module cad_header use, intrinsic :: ISO_C_BINDING - use hdf5 implicit none diff --git a/src/cell.cpp b/src/cell.cpp index 35c69f371..fba9c8934 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -22,10 +22,6 @@ extern "C" {int32_t n_cells {0};} namespace openmc { -std::vector cells_c; - -std::map cell_dict; - //============================================================================== // Global variables //============================================================================== diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 95af050ed..911ec99fa 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -422,7 +422,7 @@ contains ! ========================================================================== ! SETUP UNIVERSES - + ! Allocate universes, universe cell arrays, and assign base universe allocate(universes(n_universes)) do i = 1, n_universes @@ -433,20 +433,10 @@ contains n_cells_in_univ = cells_in_univ_dict % get(u % id) allocate(u % cells(n_cells_in_univ)) u % cells(:) = 0 - - ! Check whether universe is a fill universe - if (find(fill_univ_ids, u % id) == -1) then - if (root_universe > 0) then - call fatal_error("Two or more universes are not used as fill & - &universes, so it is not possible to distinguish which one & - &is the root universe.") - else - root_universe = i - end if - end if end associate end do - + root_universe = find_root_universe() + 1 + do i = 1, n_cells ! Get index in universes array j = universe_dict % get(cells(i) % universe()) From df342211ccb82edda53ff063053e54c6e17dcb4b Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 16 May 2018 17:24:52 -0500 Subject: [PATCH 022/175] Populating c-side structures. Updating Fortran universe population in read_geometry_xml. --- src/cad.cpp | 27 +++++++++++++++++++++------ src/input_xml.F90 | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index 790a88f76..65cab484f 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -15,17 +15,32 @@ void load_cad_geometry_c() rval = DAGMC->init_OBBTree(); MB_CHK_ERR_CONT(rval); + int32_t cad_univ_id = 0; // universe is always 0 for CAD + // initialize cell objects openmc::n_cells = DAGMC->num_entities(3); for(int i = 0; i < openmc::n_cells; i++) { // set cell ids using global IDs - openmc::CADCell c = openmc::CADCell(); - c.id = DAGMC->id_by_index(3, i); - c.dagmc_ptr = DAGMC; - c.universe = 0; // set to zero for now - openmc::cells_c.push_back(&c); - openmc::cell_dict[c.id] = i; + openmc::CADCell* c = new openmc::CADCell(); + c->id = DAGMC->id_by_index(3, i); + c->dagmc_ptr = DAGMC; + c->universe = cad_univ_id; // set to zero for now + c->material.push_back(40); // TEMPORARY + openmc::cells_c.push_back(c); + openmc::cell_dict[c->id] = i; + + // Populate the Universe vector and dict + auto it = openmc::universe_dict.find(cad_univ_id); + if (it == openmc::universe_dict.end()) { + openmc::universes_c.push_back(new openmc::Universe()); + openmc::universes_c.back()-> id = cad_univ_id; + openmc::universes_c.back()->cells.push_back(i); + openmc::universe_dict[cad_univ_id] = openmc::universes_c.size() - 1; + } + else { + openmc::universes_c[it->second]->cells.push_back(i); + } } // initialize surface objects diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 911ec99fa..fcd568e75 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -435,7 +435,7 @@ contains u % cells(:) = 0 end associate end do - root_universe = find_root_universe() + 1 + root_universe = 0 + 1 do i = 1, n_cells ! Get index in universes array From 3c1827c7dde907ccaae4acd1ecf90cab0f6fb289 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 17 May 2018 10:57:13 -0500 Subject: [PATCH 023/175] Abstracting cell class to support both CAD and CSG. --- include/openmc/cell.h | 48 +++++++++++++++++++++++++++++++++++++++++-- src/cad.cpp | 8 ++++---- src/cell.cpp | 31 ++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index f819d41f4..9bbc00460 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -110,12 +110,49 @@ public: std::vector offset_; //!< Distribcell offset table - Cell() {}; - explicit Cell(pugi::xml_node cell_node); explicit Cell(); + + //! Determine if a cell contains the particle at a given location. + //! + //! The bounds of the cell are detemined by a logical expression involving + //! surface half-spaces. At initialization, the expression was converted + //! to RPN notation. + //! + //! The function is split into two cases, one for simple cells (those + //! involving only the intersection of half-spaces) and one for complex cells. + //! Simple cells can be evaluated with short circuit evaluation, i.e., as soon + //! as we know that one half-space is not satisfied, we can exit. This + //! provides a performance benefit for the common case. In + //! contains_complex, we evaluate the RPN expression using a stack, similar to + //! how a RPN calculator would work. + //! @param xyz[3] The 3D Cartesian coordinate to check. + //! @param uvw[3] A direction used to "break ties" the coordinates are very + //! close to a surface. + //! @param on_surface The signed index of a surface that the coordinate is + //! known to be on. This index takes precedence over surface sense + //! calculations. + virtual bool + contains(const double xyz[3], const double uvw[3], int32_t on_surface) const = 0; + + virtual std::pair + distance(const double xyz[3], const double uvw[3], int32_t on_surface) const = 0; + + //! Write all information needed to reconstruct the cell to an HDF5 group. + //! @param group_id An HDF5 group id. + virtual void to_hdf5(hid_t group_id) const = 0; + +}; + +class CSGCell : public Cell +{ +public: + + CSGCell(); + explicit CSGCell(pugi::xml_node cell_node); + //! \brief Determine if a cell contains the particle at a given location. //! Determine if a cell contains the particle at a given location. //! @@ -147,6 +184,7 @@ public: //! \param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; + protected: bool contains_simple(Position r, Direction u, int32_t on_surface) const; bool contains_complex(Position r, Direction u, int32_t on_surface) const; @@ -158,6 +196,12 @@ class CADCell : public Cell public: moab::DagMC *dagmc_ptr; explicit CADCell(); + + std::pair distance(const double xyz[3], const double uvw[3], int32_t on_surface) const; + bool contains(const double xyz[3], const double uvw[3], int32_t on_surface) const; + + void to_hdf5(hid_t group_id) const; + }; #endif diff --git a/src/cad.cpp b/src/cad.cpp index 65cab484f..be008174e 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -23,12 +23,12 @@ void load_cad_geometry_c() { // set cell ids using global IDs openmc::CADCell* c = new openmc::CADCell(); - c->id = DAGMC->id_by_index(3, i); + c->id_ = DAGMC->id_by_index(3, i); c->dagmc_ptr = DAGMC; - c->universe = cad_univ_id; // set to zero for now - c->material.push_back(40); // TEMPORARY + c->universe_ = cad_univ_id; // set to zero for now + c->material_.push_back(40); // TEMPORARY openmc::cells_c.push_back(c); - openmc::cell_dict[c->id] = i; + openmc::cell_dict[c->id_] = i; // Populate the Universe vector and dict auto it = openmc::universe_dict.find(cad_univ_id); diff --git a/src/cell.cpp b/src/cell.cpp index fba9c8934..6060edc7a 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -213,9 +213,9 @@ Universe::to_hdf5(hid_t universes_group) const // Cell implementation //============================================================================== -Cell::Cell() {} // empty constructor +CSGCell::CSGCell() {} // empty constructor -Cell::Cell(pugi::xml_node cell_node) +CSGCell::CSGCell(pugi::xml_node cell_node) { if (check_for_node(cell_node, "id")) { id_ = std::stoi(get_node_value(cell_node, "id")); @@ -399,7 +399,7 @@ Cell::Cell(pugi::xml_node cell_node) //============================================================================== bool -Cell::contains(Position r, Direction u, int32_t on_surface) const +CSGCell::contains(Position r, Direction u, int32_t on_surface) const { if (simple_) { return contains_simple(r, u, on_surface); @@ -411,7 +411,7 @@ Cell::contains(Position r, Direction u, int32_t on_surface) const //============================================================================== std::pair -Cell::distance(Position r, Direction u, int32_t on_surface) const +CSGCell::distance(Position r, Direction u, int32_t on_surface) const { double min_dist {INFTY}; int32_t i_surf {std::numeric_limits::max()}; @@ -440,7 +440,7 @@ Cell::distance(Position r, Direction u, int32_t on_surface) const //============================================================================== void -Cell::to_hdf5(hid_t cells_group) const +CSGCell::to_hdf5(hid_t cell_group) const { // Create a group for this cell. std::stringstream group_name; @@ -519,7 +519,7 @@ Cell::to_hdf5(hid_t cells_group) const //============================================================================== bool -Cell::contains_simple(Position r, Direction u, int32_t on_surface) const +CSGCell::contains_simple(Position r, Direction u, int32_t on_surface) const { for (int32_t token : rpn_) { if (token < OP_UNION) { @@ -543,7 +543,7 @@ Cell::contains_simple(Position r, Direction u, int32_t on_surface) const //============================================================================== bool -Cell::contains_complex(Position r, Direction u, int32_t on_surface) const +CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const { // Make a stack of booleans. We don't know how big it needs to be, but we do // know that rpn.size() is an upper-bound. @@ -596,6 +596,19 @@ Cell::contains_complex(Position r, Direction u, int32_t on_surface) const //============================================================================== #ifdef CAD CADCell::CADCell() : Cell{} {}; + +std::pair CADCell::distance(const double xyz[3], const double uvw[3], int32_t on_surface) const { + std::cout << "Cell Distance" << std::endl; + std::pair result(1.0, 0); + return result; +} + +bool CADCell::contains(const double xyz[3], const double uvw[3], int32_t on_surface) const { + std::cout << "Cell Contains" << std::endl; + return true; +} + +void CADCell::to_hdf5(hid_t group_id) const { return; } #endif //============================================================================== @@ -612,7 +625,7 @@ read_cells(pugi::xml_node* node) // Loop over XML cell elements and populate the array. cells.reserve(n_cells); for (pugi::xml_node cell_node: node->children("cell")) { - cells.push_back(new Cell(cell_node)); + cells_c.push_back(new CSGCell(cell_node)); } // Populate the Universe vector and map. @@ -764,7 +777,7 @@ extern "C" { { cells.reserve(cells.size() + n); for (int32_t i = 0; i < n; i++) { - cells.push_back(new Cell()); + cells_c.push_back(new CSGCell()); } n_cells = cells.size(); } From a3e008db095ade9f52a78c62aec157bac727b82a Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 17 May 2018 18:42:23 -0500 Subject: [PATCH 024/175] Some hacking to get a simple geometry running. The simulations agree though :tada: --- src/cad.cpp | 8 ++++---- src/cell.cpp | 37 +++++++++++++++++++++++++++++++++---- src/geometry.F90 | 30 +++++++++++++++++++++++++++++- src/tracking.F90 | 25 ++++++++++++++++++++++++- 4 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index be008174e..2271aa856 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -23,12 +23,12 @@ void load_cad_geometry_c() { // set cell ids using global IDs openmc::CADCell* c = new openmc::CADCell(); - c->id_ = DAGMC->id_by_index(3, i); + c->id_ = DAGMC->id_by_index(3, i+1); c->dagmc_ptr = DAGMC; c->universe_ = cad_univ_id; // set to zero for now c->material_.push_back(40); // TEMPORARY openmc::cells_c.push_back(c); - openmc::cell_dict[c->id_] = i; + openmc::cell_dict[c->id_] = c->id; // Populate the Universe vector and dict auto it = openmc::universe_dict.find(cad_univ_id); @@ -51,11 +51,11 @@ void load_cad_geometry_c() { // set cell ids using global IDs openmc::CADSurface* s = new openmc::CADSurface(); - s->id = DAGMC->id_by_index(2, i); + s->id = DAGMC->id_by_index(2, i+1); s->dagmc_ptr = DAGMC; s->bc = openmc::BC_TRANSMIT; openmc::surfaces_c[i] = s; - openmc::surface_dict[s->id] = i; + openmc::surface_dict[s->id] = s->id; } return; diff --git a/src/cell.cpp b/src/cell.cpp index 6060edc7a..c0a28cedb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -598,14 +598,26 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const CADCell::CADCell() : Cell{} {}; std::pair CADCell::distance(const double xyz[3], const double uvw[3], int32_t on_surface) const { - std::cout << "Cell Distance" << std::endl; - std::pair result(1.0, 0); + + moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); + moab::EntityHandle hit_surf; + double dist; + dagmc_ptr->ray_fire(vol, xyz, uvw, hit_surf, dist); + + int surf_idx = dagmc_ptr->index_by_handle(hit_surf); + + std::pair result(dist, surf_idx); + return result; } bool CADCell::contains(const double xyz[3], const double uvw[3], int32_t on_surface) const { - std::cout << "Cell Contains" << std::endl; - return true; + moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); + + int result = 0; + dagmc_ptr->point_in_volume(vol, xyz, result, uvw); + + return bool(result); } void CADCell::to_hdf5(hid_t group_id) const { return; } @@ -749,6 +761,23 @@ extern "C" { int cell_type(Cell* c) {return c->type_;} +#ifdef CAD + int32_t next_cell(CADCell* cur_cell, CADSurface *surf_xed ) { + moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id); + moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id); + + moab::EntityHandle new_vol; + cur_cell->dagmc_ptr->next_vol(surf, vol, new_vol); + + return cur_cell->dagmc_ptr->index_by_handle(new_vol); + } + + bool is_implicit_complement(CADCell *c) { + moab::EntityHandle handle = c->dagmc_ptr->entity_by_id(3,c->id); + return c->dagmc_ptr->is_implicit_complement(handle); + } +#endif + int32_t cell_universe(Cell* c) {return c->universe_;} int32_t cell_fill(Cell* c) {return c->fill_;} diff --git a/src/geometry.F90 b/src/geometry.F90 index b5dee81fa..b6212d73a 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -55,10 +55,38 @@ module geometry subroutine neighbor_lists() bind(C) end subroutine neighbor_lists - end interface + + function next_cell_c(current_cell, surface_crossed) & + bind(C, name="next_cell") result(new_cell) + import C_PTR, C_INT32_T + type(C_PTR), intent(in), value :: current_cell + type(C_PTR), intent(in), value :: surface_crossed + integer(C_INT32_T) :: new_cell + end function next_cell_c + + function is_implicit_complement_C(cell) & + bind(C, name="is_implicit_complement") result(res) + import C_PTR, C_BOOL + type(C_PTR), intent(in), value :: cell + logical(C_BOOL) :: res + end function is_implicit_complement_C + end interface contains + function next_cell(c, s) result(new_cell) + type(Cell), intent(in) :: c + type(Surface), intent(in) :: s + integer :: new_cell + new_cell = next_cell_c(c%ptr, s%ptr) + end function next_cell + + function is_implicit_complement(c) result(res) + type(Cell), intent(in) :: c + logical:: res + res = is_implicit_complement_c(c%ptr) + end function is_implicit_complement + !=============================================================================== ! FIND_CELL determines what cell a source particle is in within a particular ! universe. If the base universe is passed, the particle should be found as long diff --git a/src/tracking.F90 b/src/tracking.F90 index d93ac9ab9..67c76f183 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -6,7 +6,7 @@ module tracking use error, only: warning, write_message use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice,& - check_cell_overlap + check_cell_overlap, next_cell, is_implicit_complement use material_header, only: materials, Material use message_passing use mgxs_interface @@ -309,11 +309,34 @@ contains real(8) :: norm ! "norm" of surface normal real(8) :: xyz(3) ! Saved global coordinate integer :: i_surface ! index in surfaces + integer :: i_cell ! index of new cell logical :: rotational ! if rotational periodic BC applied logical :: found ! particle found in universe? class(Surface), pointer :: surf class(Surface), pointer :: surf2 ! periodic partner surface + +#ifdef CAD + if (dagmc) then + i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) + ! save material and temp + p % last_material = p % material + p % last_sqrtkT = p % sqrtKT + ! set new cell value + p % coord(1) % cell = i_cell + p % cell_instance = 1 + p % material = cells(i_cell) % material(1) + p % sqrtKT = cells(i_cell) % sqrtKT(1) + if (is_implicit_complement(cells(i_cell))) then + p % alive = .false. + end if + + return + + end if +#endif + + i_surface = abs(p % surface) surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then From a002c5b06022bfe7d0add2a0f47ccfdfe8539c03 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 29 May 2018 00:36:29 -0500 Subject: [PATCH 025/175] Adding ifdefs to keep stable CAD-free build. --- src/geometry.F90 | 21 +++++++++++++++++++-- src/tracking.F90 | 5 ++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index b6212d73a..f83bd902e 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -56,6 +56,8 @@ module geometry subroutine neighbor_lists() bind(C) end subroutine neighbor_lists +#ifdef CAD + function next_cell_c(current_cell, surface_crossed) & bind(C, name="next_cell") result(new_cell) import C_PTR, C_INT32_T @@ -63,17 +65,30 @@ module geometry type(C_PTR), intent(in), value :: surface_crossed integer(C_INT32_T) :: new_cell end function next_cell_c - + function is_implicit_complement_C(cell) & bind(C, name="is_implicit_complement") result(res) import C_PTR, C_BOOL type(C_PTR), intent(in), value :: cell logical(C_BOOL) :: res end function is_implicit_complement_C - end interface +#endif + + end interface + contains + function cell_contains(c, p) result(in_cell) + type(Cell), intent(in) :: c + type(Particle), intent(in) :: p + logical :: in_cell + in_cell = cell_contains_c(c%ptr, p%coord(p%n_coord)%xyz, & + p%coord(p%n_coord)%uvw, p%surface) + end function cell_contains + +#ifdef CAD + function next_cell(c, s) result(new_cell) type(Cell), intent(in) :: c type(Surface), intent(in) :: s @@ -86,6 +101,8 @@ contains logical:: res res = is_implicit_complement_c(c%ptr) end function is_implicit_complement + +#endif !=============================================================================== ! FIND_CELL determines what cell a source particle is in within a particular diff --git a/src/tracking.F90 b/src/tracking.F90 index 67c76f183..487ab4372 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -6,7 +6,10 @@ module tracking use error, only: warning, write_message use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice,& - check_cell_overlap, next_cell, is_implicit_complement + check_cell_overlap +#ifdef CAD + use geometry, only: next_cell, is_implicit_complement +#endif use material_header, only: materials, Material use message_passing use mgxs_interface From 0cd8b88ca4021020ff719e1fa3ff1e4bb82ef9e7 Mon Sep 17 00:00:00 2001 From: shriwise Date: Mon, 18 Jun 2018 14:46:46 -0500 Subject: [PATCH 026/175] Some corrections from the rebase onto develop. --- include/openmc/cell.h | 2 -- src/cell.cpp | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 9bbc00460..1e2bd2d98 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -112,8 +112,6 @@ public: explicit Cell(pugi::xml_node cell_node); - explicit Cell(); - //! Determine if a cell contains the particle at a given location. //! //! The bounds of the cell are detemined by a logical expression involving diff --git a/src/cell.cpp b/src/cell.cpp index c0a28cedb..13081c9e3 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -18,7 +18,7 @@ //TODO: remove this include #include -extern "C" {int32_t n_cells {0};} +//extern "C" {int32_t n_cells {0};} namespace openmc { @@ -637,7 +637,7 @@ read_cells(pugi::xml_node* node) // Loop over XML cell elements and populate the array. cells.reserve(n_cells); for (pugi::xml_node cell_node: node->children("cell")) { - cells_c.push_back(new CSGCell(cell_node)); + global_cells.push_back(new CSGCell(cell_node)); } // Populate the Universe vector and map. @@ -806,7 +806,7 @@ extern "C" { { cells.reserve(cells.size() + n); for (int32_t i = 0; i < n; i++) { - cells_c.push_back(new CSGCell()); + global_cells.push_back(new CSGCell()); } n_cells = cells.size(); } From 3f359d1acdc863397e9a2afbce7ef5ed7e394c5e Mon Sep 17 00:00:00 2001 From: shriwise Date: Mon, 18 Jun 2018 16:12:12 -0500 Subject: [PATCH 027/175] Updating global variable names in CAD initialization. --- src/cad.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index 2271aa856..79321e397 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -27,19 +27,19 @@ void load_cad_geometry_c() c->dagmc_ptr = DAGMC; c->universe_ = cad_univ_id; // set to zero for now c->material_.push_back(40); // TEMPORARY - openmc::cells_c.push_back(c); - openmc::cell_dict[c->id_] = c->id; + openmc::global_cells.push_back(c); + openmc::cell_map[c->id_] = c->id; // Populate the Universe vector and dict - auto it = openmc::universe_dict.find(cad_univ_id); - if (it == openmc::universe_dict.end()) { - openmc::universes_c.push_back(new openmc::Universe()); - openmc::universes_c.back()-> id = cad_univ_id; - openmc::universes_c.back()->cells.push_back(i); - openmc::universe_dict[cad_univ_id] = openmc::universes_c.size() - 1; + auto it = openmc::universe_map.find(cad_univ_id); + if (it == openmc::universe_map.end()) { + openmc::global_universes.push_back(new openmc::Universe()); + openmc::global_universes.back()-> id = cad_univ_id; + openmc::global_universes.back()->cells.push_back(i); + openmc::universe_map[cad_univ_id] = openmc::global_universes.size() - 1; } else { - openmc::universes_c[it->second]->cells.push_back(i); + openmc::global_universes[it->second]->cells.push_back(i); } } @@ -55,7 +55,7 @@ void load_cad_geometry_c() s->dagmc_ptr = DAGMC; s->bc = openmc::BC_TRANSMIT; openmc::surfaces_c[i] = s; - openmc::surface_dict[s->id] = s->id; + openmc::surface_map[s->id] = s->id; } return; From 9ce6f039bb22846ee8dd4842b45b93ab05e5e7cf Mon Sep 17 00:00:00 2001 From: shriwise Date: Mon, 18 Jun 2018 16:12:29 -0500 Subject: [PATCH 028/175] Correcting some missed changes in the rebase. --- src/input_xml.F90 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index fcd568e75..33f1e72cc 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -401,7 +401,6 @@ contains ! additional metadata spoofing allocate(c % material(1)) c % material(1) = 40 - c % fill = NONE allocate(c % sqrtKT(1)) c % sqrtkT(1) = 293 c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) @@ -479,12 +478,15 @@ contains call read_surfaces(root % ptr) - call allocate_surfaces() ! Allocate surfaces array + allocate(surfaces(n_surfaces)) do i = 1, n_surfaces surfaces(i) % ptr = surface_pointer(i - 1); if (surfaces(i) % bc() /= BC_TRANSMIT) boundary_exists = .true. + + ! Add surface to dictionary + call surface_dict % set(surfaces(i) % id(), i) end do ! Check to make sure a boundary condition was applied to at least one @@ -500,7 +502,7 @@ contains call read_cells(root % ptr) - call allocate_cells() +! call allocate_cells() ! Get pointer to list of XML call get_node_list(root, "cell", node_cell_list) @@ -513,6 +515,8 @@ contains call fatal_error("No cells found in geometry.xml!") end if + ! Allocate cells array + allocate(cells(n_cells)) n_universes = 0 do i = 1, n_cells @@ -567,6 +571,8 @@ contains ! Add cell to dictionary call cell_dict % set(c % id(), i) + call cell_dict % set(c % id(), i) + ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the ! specified universe From 7da17713f870ec50ab91132ace553b726b18c935 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 19 Jun 2018 15:11:21 -0500 Subject: [PATCH 029/175] Updates to meet style guide. --- src/api.F90 | 4 +- src/cad_header.F90 | 8 +- src/constants.F90 | 7 +- src/geometry.F90 | 14 +- src/input_xml.F90 | 350 +++++++++++++++++++++++++++++++++++---------- src/settings.F90 | 2 +- src/tracking.F90 | 38 ++--- 7 files changed, 309 insertions(+), 114 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 05d276015..5058b0ab1 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -32,7 +32,7 @@ module openmc_api #ifdef CAD use cad_header, only: free_memory_cad #endif - + implicit none private @@ -333,7 +333,7 @@ contains #ifdef CAD call free_memory_cad() #endif - + ! Deallocate CMFD call deallocate_cmfd(cmfd) diff --git a/src/cad_header.F90 b/src/cad_header.F90 index 403e0782b..04db460e1 100644 --- a/src/cad_header.F90 +++ b/src/cad_header.F90 @@ -5,11 +5,11 @@ module cad_header implicit none interface - subroutine load_cad_geometry_c() bind(C) - end subroutine load_cad_geometry_c + subroutine load_cad_geometry_c() bind(C) + end subroutine load_cad_geometry_c - subroutine free_memory_cad_c() bind(C) - end subroutine free_memory_cad_c + subroutine free_memory_cad_c() bind(C) + end subroutine free_memory_cad_c end interface diff --git a/src/constants.F90 b/src/constants.F90 index 80c1d2322..925ffc808 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -424,17 +424,12 @@ module constants real(8), parameter :: ERROR_REAL = -huge(0.0_8) * 0.917826354_8 ! Running modes - integer, parameter :: & + integer, parameter :: & MODE_FIXEDSOURCE = 1, & ! Fixed source mode MODE_EIGENVALUE = 2, & ! K eigenvalue mode MODE_PLOTTING = 3, & ! Plotting mode MODE_PARTICLE = 4, & ! Particle restart mode -#ifdef CAD - MODE_VOLUME = 5, & ! Volume calculation mode - MODE_CAD = 6 ! CAD-based Geometry mode -#else MODE_VOLUME = 5 ! Volume calculation mode -#endif ! Electron treatments integer, parameter :: & diff --git a/src/geometry.F90 b/src/geometry.F90 index f83bd902e..0eb463fe2 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -57,15 +57,15 @@ module geometry end subroutine neighbor_lists #ifdef CAD - + function next_cell_c(current_cell, surface_crossed) & - bind(C, name="next_cell") result(new_cell) + bind(C, name="next_cell") result(new_cell) import C_PTR, C_INT32_T type(C_PTR), intent(in), value :: current_cell type(C_PTR), intent(in), value :: surface_crossed integer(C_INT32_T) :: new_cell end function next_cell_c - + function is_implicit_complement_C(cell) & bind(C, name="is_implicit_complement") result(res) import C_PTR, C_BOOL @@ -75,8 +75,8 @@ module geometry #endif - end interface - + end interface + contains function cell_contains(c, p) result(in_cell) @@ -88,7 +88,7 @@ contains end function cell_contains #ifdef CAD - + function next_cell(c, s) result(new_cell) type(Cell), intent(in) :: c type(Surface), intent(in) :: s @@ -103,7 +103,7 @@ contains end function is_implicit_complement #endif - + !=============================================================================== ! FIND_CELL determines what cell a source particle is in within a particular ! universe. If the base universe is passed, the particle should be found as long diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 33f1e72cc..c8403f863 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -180,7 +180,7 @@ contains ! After reading input and basic geometry setup is complete, build lists of ! neighboring cells for efficient tracking call neighbor_lists() - + ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() @@ -222,11 +222,11 @@ contains ! Check for use of CAD geometry if (check_for_node(root, "dagmc")) then #ifdef CAD - call get_node_value_bool(root, "dagmc", dagmc) + call get_node_value_bool(root, "dagmc", dagmc) #else - if (dagmc) then - call fatal_error("CAD mode unsupported for this build of OpenMC") - end if + if (dagmc) then + call fatal_error("CAD mode unsupported for this build of OpenMC") + end if #endif end if @@ -235,6 +235,206 @@ contains call k_generation % reserve(n_max_batches*gen_per_batch) end if + ! Check run mode if it hasn't been set from the command line + if (run_mode == NONE) then + if (check_for_node(root, "run_mode")) then + call get_node_value(root, "run_mode", temp_str) + select case (to_lower(temp_str)) + case ("eigenvalue") + run_mode = MODE_EIGENVALUE + case ("fixed source") + run_mode = MODE_FIXEDSOURCE + case ("plot") + run_mode = MODE_PLOTTING + case ("particle restart") + run_mode = MODE_PARTICLE + case ("volume") + run_mode = MODE_VOLUME + case default + call fatal_error("Unrecognized run mode: " // & + trim(temp_str) // ".") + end select + + ! Assume XML specifics , , etc. directly + node_mode = root + else + call warning(" should be specified.") + + ! Make sure that either eigenvalue or fixed source was specified + node_mode = root % child("eigenvalue") + if (node_mode % associated()) then + if (run_mode == NONE) run_mode = MODE_EIGENVALUE + else + node_mode = root % child("fixed_source") + if (node_mode % associated()) then + if (run_mode == NONE) run_mode = MODE_FIXEDSOURCE + else + call fatal_error(" or not specified.") + end if + end if + end if + end if + + if (run_mode == MODE_EIGENVALUE .or. run_mode == MODE_FIXEDSOURCE) then + ! Read run parameters + call get_run_parameters(node_mode) + + ! Check number of active batches, inactive batches, and particles + if (n_batches <= n_inactive) then + call fatal_error("Number of active batches must be greater than zero.") + elseif (n_inactive < 0) then + call fatal_error("Number of inactive batches must be non-negative.") + elseif (n_particles <= 0) then + call fatal_error("Number of particles must be greater than zero.") + end if + end if + + ! Copy random number seed if specified + if (check_for_node(root, "seed")) then + call get_node_value(root, "seed", seed) + call openmc_set_seed(seed) + end if + + ! Check for electron treatment + if (check_for_node(root, "electron_treatment")) then + call get_node_value(root, "electron_treatment", temp_str) + select case (to_lower(temp_str)) + case ("led") + electron_treatment = ELECTRON_LED + case ("ttb") + electron_treatment = ELECTRON_TTB + case default + call fatal_error("Unrecognized electron treatment: " // & + trim(temp_str) // ".") + end select + end if + + ! Check for photon transport + if (check_for_node(root, "photon_transport")) then + call get_node_value(root, "photon_transport", photon_transport) + + if (.not. run_CE .and. photon_transport) then + call fatal_error("Photon transport is not currently supported & + &in Multi-group mode") + end if + end if + + ! Number of bins for logarithmic grid + if (check_for_node(root, "log_grid_bins")) then + call get_node_value(root, "log_grid_bins", n_log_bins) + if (n_log_bins < 1) then + call fatal_error("Number of bins for logarithmic grid must be & + &greater than zero.") + end if + else + n_log_bins = 8000 + end if + + ! Number of OpenMP threads + if (check_for_node(root, "threads")) then +#ifdef _OPENMP + if (n_threads == NONE) then + call get_node_value(root, "threads", n_threads) + if (n_threads < 1) then + call fatal_error("Invalid number of threads: " // to_str(n_threads)) + end if + call omp_set_num_threads(n_threads) + end if +#else + if (master) call warning("Ignoring number of threads.") +#endif + end if + + ! ========================================================================== + ! EXTERNAL SOURCE + + ! Get point to list of elements and make sure there is at least one + call get_node_list(root, "source", node_source_list) + n = size(node_source_list) + + if (n == 0) then + ! Default source is isotropic point source at origin with Watt spectrum + allocate(external_source(1)) + external_source % particle = NEUTRON + external_source % strength = ONE + + allocate(SpatialPoint :: external_source(1) % space) + select type (space => external_source(1) % space) + type is (SpatialPoint) + space % xyz(:) = [ZERO, ZERO, ZERO] + end select + + allocate(Isotropic :: external_source(1) % angle) + external_source(1) % angle % reference_uvw(:) = [ZERO, ZERO, ONE] + + allocate(Watt :: external_source(1) % energy) + select type(energy => external_source(1) % energy) + type is (Watt) + energy % a = 0.988e6_8 + energy % b = 2.249e-6_8 + end select + else + ! Allocate array for sources + allocate(external_source(n)) + end if + + ! Check if we want to write out source + if (check_for_node(root, "write_initial_source")) then + call get_node_value(root, "write_initial_source", write_initial_source) + end if + + ! Read each source + do i = 1, n + call external_source(i) % from_xml(node_source_list(i), path_source) + end do + + ! Survival biasing + if (check_for_node(root, "survival_biasing")) then + call get_node_value(root, "survival_biasing", survival_biasing) + end if + + ! Probability tables + if (check_for_node(root, "ptables")) then + call get_node_value(root, "ptables", urr_ptables_on) + end if + + ! Cutoffs + if (check_for_node(root, "cutoff")) then + node_cutoff = root % child("cutoff") + if (check_for_node(node_cutoff, "weight")) then + call get_node_value(node_cutoff, "weight", weight_cutoff) + end if + if (check_for_node(node_cutoff, "weight_avg")) then + call get_node_value(node_cutoff, "weight_avg", weight_survive) + end if + if (check_for_node(node_cutoff, "energy_neutron")) then + call get_node_value(node_cutoff, "energy_neutron", energy_cutoff(1)) + elseif (check_for_node(node_cutoff, "energy")) then + call warning("The use of an cutoff is deprecated and should & + &be replaced by .") + call get_node_value(node_cutoff, "energy", energy_cutoff(1)) + end if + if (check_for_node(node_cutoff, "energy_photon")) then + call get_node_value(node_cutoff, "energy_photon", energy_cutoff(2)) + end if + if (check_for_node(node_cutoff, "energy_electron")) then + call get_node_value(node_cutoff, "energy_electron", energy_cutoff(3)) + end if + if (check_for_node(node_cutoff, "energy_positron")) then + call get_node_value(node_cutoff, "energy_positron", energy_cutoff(4)) + end if + end if + + ! Particle trace + if (check_for_node(root, "trace")) then + call get_node_array(root, "trace", temp_int_array3) + trace_batch = temp_int_array3(1) + trace_gen = temp_int_array3(2) + trace_particle = int(temp_int_array3(3), 8) +>>>>>>> Updates to meet style guide. +>>>>>>> Updates to meet style guide. + end if + ! Particle tracks if (check_for_node(root, "track")) then ! Make sure that there are three values per particle @@ -390,70 +590,68 @@ contains ! universe contains #ifdef CAD if (dagmc) then - call write_message("Reading CAD geometry...", 5) - call load_cad_geometry() - call allocate_surfaces() - call allocate_cells() + call write_message("Reading CAD geometry...", 5) + call load_cad_geometry() + call allocate_surfaces() + call allocate_cells() ! setup universe data structs - do i = 1, n_cells - c => cells(i) - ! additional metadata spoofing - allocate(c % material(1)) - c % material(1) = 40 - allocate(c % sqrtKT(1)) - c % sqrtkT(1) = 293 - c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) - univ_id = c % universe() - if (.not. allocated(c%region)) allocate(c%region(0)) - - if (.not. cells_in_univ_dict % has(univ_id)) then - n_universes = n_universes + 1 - n_cells_in_univ = 1 - call universe_dict % set(univ_id, n_universes) - call univ_ids % push_back(univ_id) - else - n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) - end if - call cells_in_univ_dict % set(univ_id, n_cells_in_univ) - - end do + do i = 1, n_cells + c => cells(i) + ! additional metadata spoofing + allocate(c % material(1)) + c % material(1) = 40 + allocate(c % sqrtKT(1)) + c % sqrtkT(1) = 293 + c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) + univ_id = c % universe() + if (.not. allocated(c%region)) allocate(c%region(0)) + + if (.not. cells_in_univ_dict % has(univ_id)) then + n_universes = n_universes + 1 + n_cells_in_univ = 1 + call universe_dict % set(univ_id, n_universes) + call univ_ids % push_back(univ_id) + else + n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) + end if + call cells_in_univ_dict % set(univ_id, n_cells_in_univ) + end do ! ========================================================================== ! SETUP UNIVERSES ! Allocate universes, universe cell arrays, and assign base universe - allocate(universes(n_universes)) - do i = 1, n_universes - associate (u => universes(i)) - u % id = univ_ids % data(i) + allocate(universes(n_universes)) + do i = 1, n_universes + associate (u => universes(i)) + u % id = univ_ids % data(i) + ! Allocate cell list + n_cells_in_univ = cells_in_univ_dict % get(u % id) + allocate(u % cells(n_cells_in_univ)) + u % cells(:) = 0 + end associate + end do - ! Allocate cell list - n_cells_in_univ = cells_in_univ_dict % get(u % id) - allocate(u % cells(n_cells_in_univ)) - u % cells(:) = 0 - end associate - end do - root_universe = 0 + 1 + root_universe = 0 + 1 - do i = 1, n_cells - ! Get index in universes array - j = universe_dict % get(cells(i) % universe()) - - ! Set the first zero entry in the universe cells array to the index in the - ! global cells array - associate (u => universes(j)) - u % cells(find(u % cells, 0)) = i - end associate - end do - - ! Clear dictionary - call cells_in_univ_dict%clear() - - return + do i = 1, n_cells + ! Get index in universes array + j = universe_dict % get(cells(i) % universe()) + ! Set the first zero entry in the universe cells array to the index in the + ! global cells array + associate (u => universes(j)) + u % cells(find(u % cells, 0)) = i + end associate + end do + + ! Clear dictionary + call cells_in_univ_dict%clear() + + return end if #endif - + ! Display output message call write_message("Reading geometry XML file...", 5) @@ -485,8 +683,8 @@ contains if (surfaces(i) % bc() /= BC_TRANSMIT) boundary_exists = .true. - ! Add surface to dictionary - call surface_dict % set(surfaces(i) % id(), i) + ! Add surface to dictionary + call surface_dict % set(surfaces(i) % id(), i) end do ! Check to make sure a boundary condition was applied to at least one @@ -524,6 +722,12 @@ contains c % ptr = cell_pointer(i - 1) +<<<<<<< 25ab6776f10a1ea974b3aa15f74271aa80748913 +======= + ! Initialize distribcell instances and distribcell index + c % distribcell_index = NONE + +>>>>>>> Updates to meet style guide. ! Get pointer to i-th cell node node_cell = node_cell_list(i) @@ -572,7 +776,7 @@ contains call cell_dict % set(c % id(), i) call cell_dict % set(c % id(), i) - + ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the ! specified universe @@ -658,24 +862,20 @@ contains subroutine allocate_cells() integer :: i type(Cell), pointer :: c - + ! Allocate cells array allocate(cells(n_cells)) - + do i = 1, n_cells - c => cells(i) - - c % ptr = cell_pointer_c(i - 1) - - ! Check to make sure 'id' hasn't been used - if (cell_dict % has(c % id())) then - call fatal_error("Two or more cells use the same unique ID: " & + c => cells(i) + c % ptr = cell_pointer_c(i - 1) + ! Check to make sure 'id' hasn't been used + if (cell_dict % has(c % id())) then + call fatal_error("Two or more cells use the same unique ID: " & // to_str(c % id())) - end if - - ! Add cell to dictionary - call cell_dict % set(c % id(), i) - + end if + ! Add cell to dictionary + call cell_dict % set(c % id(), i) end do end subroutine allocate_cells diff --git a/src/settings.F90 b/src/settings.F90 index 4efe25102..66af618f7 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -82,7 +82,7 @@ module settings ! flag for use of CAD geometry logical, bind(C) :: dagmc = .false. - + ! Restart run logical(C_BOOL), bind(C) :: restart_run diff --git a/src/tracking.F90 b/src/tracking.F90 index 487ab4372..99eb22688 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -7,7 +7,7 @@ module tracking use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice,& check_cell_overlap -#ifdef CAD +#ifdef CAD use geometry, only: next_cell, is_implicit_complement #endif use material_header, only: materials, Material @@ -317,29 +317,29 @@ contains logical :: found ! particle found in universe? class(Surface), pointer :: surf class(Surface), pointer :: surf2 ! periodic partner surface - + #ifdef CAD if (dagmc) then - i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) - ! save material and temp - p % last_material = p % material - p % last_sqrtkT = p % sqrtKT - ! set new cell value - p % coord(1) % cell = i_cell - p % cell_instance = 1 - p % material = cells(i_cell) % material(1) - p % sqrtKT = cells(i_cell) % sqrtKT(1) + i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) + ! save material and temp + p % last_material = p % material + p % last_sqrtkT = p % sqrtKT + ! set new cell value + p % coord(1) % cell = i_cell + p % cell_instance = 1 + p % material = cells(i_cell) % material(1) + p % sqrtKT = cells(i_cell) % sqrtKT(1) + + if (is_implicit_complement(cells(i_cell))) then + p % alive = .false. + end if + + return - if (is_implicit_complement(cells(i_cell))) then - p % alive = .false. - end if - - return - end if #endif - - + + i_surface = abs(p % surface) surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then From 89381b802b2415b55cff0012d71037953f93031b Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 19 Jun 2018 16:12:30 -0500 Subject: [PATCH 030/175] Reverting the settings.py file to get travis tests working. --- openmc/settings.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index ef0cfe396..efe41b2a1 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -92,8 +92,6 @@ class Settings(object): Indicate if coarse mesh finite difference acceleration is to be used run_mode : {'eigenvalue', 'fixed source', 'plot', 'volume', 'particle restart'} The type of calculation to perform (default is 'eigenvalue') - dagmc : bool - Enables CAD-based geometry through DAGMC (default False) seed : int Seed for the linear congruential pseudorandom number generator source : Iterable of openmc.Source @@ -164,7 +162,6 @@ class Settings(object): # Run mode subelement (default is 'eigenvalue') self._run_mode = 'eigenvalue' - self._dagmc = False self._batches = None self._generations_per_batch = None self._inactive = None @@ -231,10 +228,6 @@ class Settings(object): def run_mode(self): return self._run_mode - @property - def dagmc(self): - return self._dagmc - @property def batches(self): return self._batches @@ -380,11 +373,6 @@ class Settings(object): cv.check_value('run mode', run_mode, _RUN_MODES) self._run_mode = run_mode - @dagmc.setter - def dagmc(self, dagmc): - cv.check_type('dagmc', dagmc, bool) - self._dagmc = dagmc - @batches.setter def batches(self, batches): cv.check_type('batches', batches, Integral) @@ -718,10 +706,6 @@ class Settings(object): elem = ET.SubElement(root, "run_mode") elem.text = self._run_mode - def _create_dagmc_subelement(self, root): - elem = ET.Subelement(root, "dagmc") - elem.text = str(self._dagmc).lower() - def _create_batches_subelement(self, run_mode_element): if self._batches is not None: element = ET.SubElement(run_mode_element, "batches") @@ -975,7 +959,6 @@ class Settings(object): root_element = ET.Element("settings") self._create_run_mode_subelement(root_element) - self._create_dagmc_subelement(root_element) self._create_particles_subelement(root_element) self._create_batches_subelement(root_element) self._create_inactive_subelement(root_element) From aa5983ad0b024ab6dba8690e6967a9590f38ebbb Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 6 Jul 2018 11:01:35 -0500 Subject: [PATCH 031/175] Adding a CAD build to travis. --- .travis.yml | 5 +++++ tools/ci/travis-install.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aacf9fa72..bebdc3a2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,13 @@ env: - OMP=y MPI=n PHDF5=n - OMP=n MPI=y PHDF5=n - OMP=n MPI=y PHDF5=y + - OMP=n MPI=y PHDF5=y CAD=y notifications: webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN +before_install: + - sudo add-apt-repository ppa:nschloe/hdf5-backports -y + - sudo apt-get update -q + - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y install: - ./tools/ci/travis-install.sh before_script: diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 15e4d576b..7985a3600 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -2,6 +2,7 @@ import os import shutil import subprocess +MOAB_VERSION= '5.0' def which(program): def is_exe(fpath): @@ -20,7 +21,7 @@ def which(program): return None -def install(omp=False, mpi=False, phdf5=False): +def install(omp=False, mpi=False, phdf5=False, cad=False): # Create build directory and change to it shutil.rmtree('build', ignore_errors=True) os.mkdir('build') @@ -48,6 +49,9 @@ def install(omp=False, mpi=False, phdf5=False): else: cmake_cmd.append('-DHDF5_PREFER_PARALLEL=OFF') + if cad: + build_dagmc() + # Build and install cmake_cmd.append('..') print(' '.join(cmake_cmd)) @@ -55,6 +59,29 @@ def install(omp=False, mpi=False, phdf5=False): subprocess.check_call(['make', '-j']) subprocess.check_call(['sudo', 'make', 'install']) +def build_dagmc(): + + current_dir = os.getcwd() + home_dir = os.environ['HOME'] + + os.chdir(home_dir) + os.mkdir('MOAB') + os.chdir('MOAB') + + clone_cmd = ['git', 'clone', '-b', 'Version'+MOAB_VERSION, 'https://bitbucket.org/fathomteam/moab'] + subprocess.check_call(clone_cmd) + + os.mkdir('build') + os.chdir('build') + + cmake_cmd = ['cmake', '../moab', '-DENABLE_HDF5=ON', '-DENABLE_TOOLS=ON', '-DCMAKE_INSTALL_PREFIX='+home_dir] + subprocess.check_call(cmake_cmd) + + subprocess.check_call(['make', '-j']) + + subprocess.check_call(['make', 'test']) + + subprocess.check_call(['make', 'test']) def main(): # Convert Travis matrix environment variables into arguments for install() @@ -62,8 +89,10 @@ def main(): mpi = (os.environ.get('MPI') == 'y') phdf5 = (os.environ.get('PHDF5') == 'y') + cad = (os.environ.get('CAD') == 'y') + # Build and install - install(omp, mpi, phdf5) + install(omp, mpi, phdf5, cad) if __name__ == '__main__': From 788ffb1bbe1181bb8b559fb9401c1e7b3fb6cb63 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 6 Jul 2018 13:29:53 -0500 Subject: [PATCH 032/175] Adding libblas to travis (MOAB dependency) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bebdc3a2d..8c32057f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ notifications: before_install: - sudo add-apt-repository ppa:nschloe/hdf5-backports -y - sudo apt-get update -q - - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y + - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev libblas-dev -y install: - ./tools/ci/travis-install.sh before_script: From 4071e396343f9666c6725a5b61bafc1d0985c1e8 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 6 Jul 2018 14:12:26 -0500 Subject: [PATCH 033/175] Adding liblapack to travis. (another MOAB dep) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8c32057f8..279f6b535 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ notifications: before_install: - sudo add-apt-repository ppa:nschloe/hdf5-backports -y - sudo apt-get update -q - - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev libblas-dev -y + - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev libblas-dev liblapack-dev -y install: - ./tools/ci/travis-install.sh before_script: From b7a63b6e6d72db78846300ee18a78643b639dc67 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 6 Jul 2018 14:44:14 -0500 Subject: [PATCH 034/175] Go back to previous directory after building MOAB. --- tools/ci/travis-install.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 7985a3600..4dddcfd60 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -83,6 +83,8 @@ def build_dagmc(): subprocess.check_call(['make', 'test']) + os.chdir(current_dir) + def main(): # Convert Travis matrix environment variables into arguments for install() omp = (os.environ.get('OMP') == 'y') From 2bfc036add60e14d5093c53f7101f5ac85b5668f Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 6 Jul 2018 15:45:08 -0500 Subject: [PATCH 035/175] Adding DAGMC installation commands. --- tools/ci/travis-install.py | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 4dddcfd60..566f463af 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -51,6 +51,7 @@ def install(omp=False, mpi=False, phdf5=False, cad=False): if cad: build_dagmc() + cmake_cmd.append('-Dcad=ON') # Build and install cmake_cmd.append('..') @@ -59,30 +60,54 @@ def install(omp=False, mpi=False, phdf5=False, cad=False): subprocess.check_call(['make', '-j']) subprocess.check_call(['sudo', 'make', 'install']) +def mkcd(directory): + os.mkdir(directory) + os.chdir(directory) + def build_dagmc(): current_dir = os.getcwd() home_dir = os.environ['HOME'] os.chdir(home_dir) - os.mkdir('MOAB') - os.chdir('MOAB') + mkcd('MOAB') clone_cmd = ['git', 'clone', '-b', 'Version'+MOAB_VERSION, 'https://bitbucket.org/fathomteam/moab'] subprocess.check_call(clone_cmd) - os.mkdir('build') - os.chdir('build') + mkcd('build') - cmake_cmd = ['cmake', '../moab', '-DENABLE_HDF5=ON', '-DENABLE_TOOLS=ON', '-DCMAKE_INSTALL_PREFIX='+home_dir] + moab_install_dir = home_dir + "/" + "MOAB" + cmake_cmd = ['cmake', '../moab', '-DENABLE_HDF5=ON', '-DENABLE_TOOLS=ON', '-DCMAKE_INSTALL_PREFIX='+moab_install_dir] subprocess.check_call(cmake_cmd) subprocess.check_call(['make', '-j']) subprocess.check_call(['make', 'test']) - subprocess.check_call(['make', 'test']) + subprocess.check_call(['make','install']) + # update LB_LIBRARY_PATH (so DAGMC can find MOAB) + os.environ['LD_LIBRARY_PATH'] = moab_install_dir + ":" + os.environ['LD_LIBRARY_PATH'] + + # build dagmc + os.chdir(home_dir) + + mkcd('DAGMC') + + clone_cmd = ['git', 'clone', 'https://github.com/svalinn/dagmc'] + subprocess.check_call(clone_cmd) + + mkcd('build') + + dagmc_install_dir = home_dir + "/" + 'DAGMC' + cmake_cmd = ['cmake', '../dagmc', '-DCMAKE_INSTALL_PREFIX='+dagmc_install_dir] + subprocess.check_call(cmake_cmd) + + subprocess.check_call(['make','-j']) + + subprocess.check_call(['make','install']) + os.chdir(current_dir) def main(): From 789d66a0b161e68446415b995ea01bf4d8070cd9 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 6 Jul 2018 17:58:42 -0500 Subject: [PATCH 036/175] Defensive check for existing LD_LIBRARY_PATH --- tools/ci/travis-install.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 566f463af..95eb34023 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -71,7 +71,7 @@ def build_dagmc(): os.chdir(home_dir) mkcd('MOAB') - + clone_cmd = ['git', 'clone', '-b', 'Version'+MOAB_VERSION, 'https://bitbucket.org/fathomteam/moab'] subprocess.check_call(clone_cmd) @@ -87,8 +87,14 @@ def build_dagmc(): subprocess.check_call(['make','install']) + # check for existing LD_LIBRARY_PATH + try: + ld_lib_path = os.environ['LD_LIBRARY_PATH'] + except: + ld_lib_path = '' + # update LB_LIBRARY_PATH (so DAGMC can find MOAB) - os.environ['LD_LIBRARY_PATH'] = moab_install_dir + ":" + os.environ['LD_LIBRARY_PATH'] + os.environ['LD_LIBRARY_PATH'] = moab_install_dir+"/lib" + ":" + ld_lib_path # build dagmc os.chdir(home_dir) From 095503f85a36aa65f48aaaa37bd3980508ccab93 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 7 Jul 2018 07:18:16 -0500 Subject: [PATCH 037/175] Adding DAGMC to LD_LIBRARY_PATH. --- tools/ci/travis-install.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 95eb34023..cb08b52ae 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -113,6 +113,9 @@ def build_dagmc(): subprocess.check_call(['make','-j']) subprocess.check_call(['make','install']) + + # update LB_LIBRARY_PATH (so DAGMC can find MOAB) + os.environ['LD_LIBRARY_PATH'] = dagmc_install_dir+"/lib" + ":" + ld_lib_path os.chdir(current_dir) From a928ef0f31ee4901e0f7cb4b6c9a6f82d0c53a02 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 7 Jul 2018 08:07:51 -0500 Subject: [PATCH 038/175] Building DAGMC tally library. --- tools/ci/travis-install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index cb08b52ae..ded3c6c00 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -107,7 +107,7 @@ def build_dagmc(): mkcd('build') dagmc_install_dir = home_dir + "/" + 'DAGMC' - cmake_cmd = ['cmake', '../dagmc', '-DCMAKE_INSTALL_PREFIX='+dagmc_install_dir] + cmake_cmd = ['cmake', '../dagmc', '-DCMAKE_INSTALL_PREFIX='+dagmc_install_dir, '-DBUILD_TALLY=ON'] subprocess.check_call(cmake_cmd) subprocess.check_call(['make','-j']) From 88ac58f0b50e1daa23fa03aad7b94055500e6445 Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 1 Aug 2018 00:32:24 -0500 Subject: [PATCH 039/175] Adding implementation of surface normal calculation for DAGMC. --- src/surface.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/surface.cpp b/src/surface.cpp index 53d9d2eeb..270c6723a 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -261,7 +261,11 @@ double CADSurface::distance(const double xyz[3], const double uvw[3], bool coinc } void CADSurface::normal(const double xyz[3], double uvw[3]) const { - return; + + moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); + dagmc_ptr->get_angle(surf, xyz, uvw); + return; + } BoundingBox CADSurface::bounding_box() const { return BoundingBox(); } From a70d8b05b0a9762bf27a214df7429b205c58d57c Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 2 Aug 2018 10:56:51 -0500 Subject: [PATCH 040/175] Updates to CMakeLists after rebase. --- CMakeLists.txt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57f3ee64f..d79701bd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,7 +309,7 @@ set_target_properties(faddeeva PROPERTIES # libopenmc #=============================================================================== -add_library(libopenmc SHARED +set(LIBOPENMC_SRC SHARED src/algorithm.F90 src/bank_header.F90 src/api.F90 @@ -401,8 +401,6 @@ add_library(libopenmc SHARED src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 - src/cad.h - src/cad.cpp src/cell.cpp src/cmfd_execute.cpp src/distribution.cpp @@ -451,11 +449,12 @@ add_library(libopenmc SHARED # add cad sources if enabled if(cad) - list(APPEND LIBOPENMC_FORTRAN_SRC src/cad_header.F90) - list(APPEND LIBOPENMC_CXX_SRC src/cad.h src/cad.cpp) + list(APPEND LIBOPENMC_SRC src/cad_header.F90) + list(APPEND LIBOPENMC_SRC src/cad.h src/cad.cpp) endif() -add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) +add_library(libopenmc SHARED ${LIBOPENMC_SRC}) + set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc LINKER_LANGUAGE Fortran) @@ -498,7 +497,7 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. -target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml_fortran +target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml faddeeva xtensor ${DAGMC_LIBRARIES}) #=============================================================================== From 76660f7459c5df5071f5369ea81e92a9a974f167 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 2 Aug 2018 11:29:28 -0500 Subject: [PATCH 041/175] Changing list of sources back to library command and ifdef'ing all CAD source files. --- CMakeLists.txt | 13 ++++--------- src/cad.cpp | 4 ++++ src/cad.h | 5 +++++ src/cad_header.F90 | 4 ++++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d79701bd8..a5a187dba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,10 +309,11 @@ set_target_properties(faddeeva PROPERTIES # libopenmc #=============================================================================== -set(LIBOPENMC_SRC SHARED +add_library(libopenmc SHARED src/algorithm.F90 src/bank_header.F90 src/api.F90 + src/cad_header.F90 src/cmfd_data.F90 src/cmfd_execute.F90 src/cmfd_header.F90 @@ -401,6 +402,8 @@ set(LIBOPENMC_SRC SHARED src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 + src/cad.cpp + src/cad.h src/cell.cpp src/cmfd_execute.cpp src/distribution.cpp @@ -447,14 +450,6 @@ set(LIBOPENMC_SRC SHARED src/xml_interface.cpp src/xsdata.cpp) -# add cad sources if enabled -if(cad) - list(APPEND LIBOPENMC_SRC src/cad_header.F90) - list(APPEND LIBOPENMC_SRC src/cad.h src/cad.cpp) -endif() - -add_library(libopenmc SHARED ${LIBOPENMC_SRC}) - set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc LINKER_LANGUAGE Fortran) diff --git a/src/cad.cpp b/src/cad.cpp index 79321e397..a8a2a3722 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -1,4 +1,6 @@ +#ifdef CAD + #include "cad.h" moab::DagMC* DAGMC; @@ -65,3 +67,5 @@ void free_memory_cad_c() { delete DAGMC; } + +#endif diff --git a/src/cad.h b/src/cad.h index ff2540841..8f14d2530 100644 --- a/src/cad.h +++ b/src/cad.h @@ -1,3 +1,6 @@ + +#ifdef CAD + #ifndef CAD_H #define CAD_H @@ -11,3 +14,5 @@ extern "C" void load_cad_geometry_c(); extern "C" void free_memory_cad_c(); #endif // CAD_H + +#endif diff --git a/src/cad_header.F90 b/src/cad_header.F90 index 04db460e1..898211454 100644 --- a/src/cad_header.F90 +++ b/src/cad_header.F90 @@ -1,3 +1,5 @@ +#ifdef CAD + module cad_header use, intrinsic :: ISO_C_BINDING @@ -24,3 +26,5 @@ contains end subroutine free_memory_cad end module cad_header + +#endif From 2e4809c8d55bc845d46436c86ce8d71a06e439ea Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 11 Aug 2018 08:20:52 -0500 Subject: [PATCH 042/175] Updating CAD cell/surface methods to use new Position and Direction structs. --- include/openmc/cell.h | 9 ++++----- include/openmc/surface.h | 6 +++--- src/cell.cpp | 9 +++++++-- src/surface.cpp | 11 +++++++---- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 1e2bd2d98..a2910e74c 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -132,10 +132,10 @@ public: //! known to be on. This index takes precedence over surface sense //! calculations. virtual bool - contains(const double xyz[3], const double uvw[3], int32_t on_surface) const = 0; + contains(Position p, Direction u, int32_t on_surface) const = 0; virtual std::pair - distance(const double xyz[3], const double uvw[3], int32_t on_surface) const = 0; + distance(Position p, Direction u, int32_t on_surface) const = 0; //! Write all information needed to reconstruct the cell to an HDF5 group. //! @param group_id An HDF5 group id. @@ -182,7 +182,6 @@ public: //! \param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; - protected: bool contains_simple(Position r, Direction u, int32_t on_surface) const; bool contains_complex(Position r, Direction u, int32_t on_surface) const; @@ -195,8 +194,8 @@ class CADCell : public Cell moab::DagMC *dagmc_ptr; explicit CADCell(); - std::pair distance(const double xyz[3], const double uvw[3], int32_t on_surface) const; - bool contains(const double xyz[3], const double uvw[3], int32_t on_surface) const; + std::pair distance(Position p, Direction u, int32_t on_surface) const; + bool contains(Position p, Direction u, int32_t on_surface) const; void to_hdf5(hid_t group_id) const; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 8a6b340ed..3f7e6ac3f 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -132,10 +132,10 @@ class CADSurface : public Surface public: moab::DagMC* dagmc_ptr; explicit CADSurface(); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], + double evaluate(Position p) const; + double distance(Position p, Direction u, bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + Direction normal(Position p) const; //! Get the bounding box of this surface. BoundingBox bounding_box() const; }; diff --git a/src/cell.cpp b/src/cell.cpp index 13081c9e3..1d71ff4da 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -597,8 +597,10 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const #ifdef CAD CADCell::CADCell() : Cell{} {}; -std::pair CADCell::distance(const double xyz[3], const double uvw[3], int32_t on_surface) const { +std::pair CADCell::distance(Position p, Direction u, int32_t on_surface) const { + double xyz[3] = {p.x, p.y, p.z}; + double uvw[3] = {u.x, u.y, u.z}; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); moab::EntityHandle hit_surf; double dist; @@ -611,7 +613,10 @@ std::pair CADCell::distance(const double xyz[3], const double u return result; } -bool CADCell::contains(const double xyz[3], const double uvw[3], int32_t on_surface) const { +bool CADCell::contains(Position p, Direction u, int32_t on_surface) const { + + double xyz[3] = {p.x, p.y, p.z}; + double uvw[3] = {u.x, u.y, u.z}; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); int result = 0; diff --git a/src/surface.cpp b/src/surface.cpp index 270c6723a..5c05d9d40 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -251,20 +251,23 @@ CSGSurface::to_hdf5(hid_t group_id) const #ifdef CAD CADSurface::CADSurface() :Surface{} {} // empty constructor -double CADSurface::evaluate(const double xyz[3]) const +double CADSurface::evaluate(Position r) const { return 0.0; } -double CADSurface::distance(const double xyz[3], const double uvw[3], bool coincident) const { +double CADSurface::distance(Position p, Direction u, bool coincident) const { return 0.0; } -void CADSurface::normal(const double xyz[3], double uvw[3]) const { +Direction CADSurface::normal(Position p) const { + double xyz[3] = {p.x, p.y, p.z}; + double uvw[3]; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); dagmc_ptr->get_angle(surf, xyz, uvw); - return; + Direction u = {uvw}; + return u; } From baa92194ef488b8fe44bdb41f5936cae5a30a0d2 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 11 Aug 2018 08:30:12 -0500 Subject: [PATCH 043/175] Making Position/Direction structs more friendly for array-based signatures. --- include/openmc/position.h | 4 +--- src/cell.cpp | 8 ++------ src/surface.cpp | 6 ++---- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/include/openmc/position.h b/include/openmc/position.h index 56d01ba0a..eff76dbca 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -57,9 +57,7 @@ struct Position { } // Data members - double x = 0.; - double y = 0.; - double z = 0.; + union{ double xyz[3]; struct{ double x,y,z; }; }; }; // Binary operators diff --git a/src/cell.cpp b/src/cell.cpp index 1d71ff4da..c544c5b3d 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -599,12 +599,10 @@ CADCell::CADCell() : Cell{} {}; std::pair CADCell::distance(Position p, Direction u, int32_t on_surface) const { - double xyz[3] = {p.x, p.y, p.z}; - double uvw[3] = {u.x, u.y, u.z}; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); moab::EntityHandle hit_surf; double dist; - dagmc_ptr->ray_fire(vol, xyz, uvw, hit_surf, dist); + dagmc_ptr->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); int surf_idx = dagmc_ptr->index_by_handle(hit_surf); @@ -615,12 +613,10 @@ std::pair CADCell::distance(Position p, Direction u, int32_t on bool CADCell::contains(Position p, Direction u, int32_t on_surface) const { - double xyz[3] = {p.x, p.y, p.z}; - double uvw[3] = {u.x, u.y, u.z}; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); int result = 0; - dagmc_ptr->point_in_volume(vol, xyz, result, uvw); + dagmc_ptr->point_in_volume(vol, p.xyz, result, u.xyz); return bool(result); } diff --git a/src/surface.cpp b/src/surface.cpp index 5c05d9d40..18947a86b 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -262,11 +262,9 @@ double CADSurface::distance(Position p, Direction u, bool coincident) const { Direction CADSurface::normal(Position p) const { - double xyz[3] = {p.x, p.y, p.z}; - double uvw[3]; + Direction u; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); - dagmc_ptr->get_angle(surf, xyz, uvw); - Direction u = {uvw}; + dagmc_ptr->get_angle(surf, p.xyz, u.xyz); return u; } From b3dd1f5751a67e6e71d098d64a5cf976903b7a53 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 11 Aug 2018 08:34:37 -0500 Subject: [PATCH 044/175] Simplifying index operators. --- include/openmc/position.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/openmc/position.h b/include/openmc/position.h index eff76dbca..e49958fe3 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -25,6 +25,7 @@ struct Position { Position& operator-=(double); Position& operator*=(Position); Position& operator*=(double); + const double& operator[](int i) const { switch (i) { case 0: return x; From c975644d4e0bb226223035f357d8dff68777f798 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 11 Aug 2018 08:40:13 -0500 Subject: [PATCH 045/175] Maintain default values in Pos/Dir struct. --- include/openmc/position.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openmc/position.h b/include/openmc/position.h index e49958fe3..a0106b5f2 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -58,7 +58,7 @@ struct Position { } // Data members - union{ double xyz[3]; struct{ double x,y,z; }; }; + union{ double xyz[3]; struct{ double x,y,z = 0.0; }; }; }; // Binary operators From 748e3a6c75eef75e4ab95a448cdced469308805f Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 11 Aug 2018 15:47:21 -0500 Subject: [PATCH 046/175] Set material by property. --- src/cad.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index a8a2a3722..5d1ade5a7 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -11,26 +11,47 @@ void load_cad_geometry_c() DAGMC = new moab::DagMC(); } + int32_t cad_univ_id = 0; // universe is always 0 for CAD + moab::ErrorCode rval = DAGMC->load_file("dagmc.h5m"); MB_CHK_ERR_CONT(rval); rval = DAGMC->init_OBBTree(); MB_CHK_ERR_CONT(rval); - int32_t cad_univ_id = 0; // universe is always 0 for CAD + std::vector< std::string > prop_keywords; + prop_keywords.push_back("mat"); + + std::map ph; + DAGMC->parse_properties(prop_keywords, ph, ":"); + MB_CHK_ERR_CONT(rval); // initialize cell objects openmc::n_cells = DAGMC->num_entities(3); for(int i = 0; i < openmc::n_cells; i++) { + moab::EntityHandle vol_handle = DAGMC->entity_by_index(3, i+1); // set cell ids using global IDs openmc::CADCell* c = new openmc::CADCell(); c->id_ = DAGMC->id_by_index(3, i+1); c->dagmc_ptr = DAGMC; c->universe_ = cad_univ_id; // set to zero for now - c->material_.push_back(40); // TEMPORARY + + if(DAGMC->has_prop(vol_handle, "mat")){ + std::string mat_value; + + rval = DAGMC->prop_value(vol_handle, "mat", mat_value); + MB_CHK_ERR_CONT(rval); + int mat_id = std::stoi(mat_value); + c->material_.push_back(mat_id); + } + else { + c->material_.push_back(40); // TO-DO: add void material here + } + + c->fill_ = openmc::C_NONE; openmc::global_cells.push_back(c); - openmc::cell_map[c->id_] = c->id; + openmc::cell_map[c->id_] = c->id_; // Populate the Universe vector and dict auto it = openmc::universe_map.find(cad_univ_id); From 8cd56396a77cf9a7064088391edd83e26950964f Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 16 Aug 2018 16:37:49 -0500 Subject: [PATCH 047/175] Making implicit complement a void material for now. --- src/cad.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cad.cpp b/src/cad.cpp index 5d1ade5a7..3d73e4534 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -30,7 +30,8 @@ void load_cad_geometry_c() openmc::n_cells = DAGMC->num_entities(3); for(int i = 0; i < openmc::n_cells; i++) { - moab::EntityHandle vol_handle = DAGMC->entity_by_index(3, i+1); + moab::EntityHandle vol_handle = DAGMC->entity_by_index(3, i+1); + // set cell ids using global IDs openmc::CADCell* c = new openmc::CADCell(); c->id_ = DAGMC->id_by_index(3, i+1); @@ -50,6 +51,7 @@ void load_cad_geometry_c() } c->fill_ = openmc::C_NONE; + openmc::global_cells.push_back(c); openmc::cell_map[c->id_] = c->id_; @@ -64,6 +66,25 @@ void load_cad_geometry_c() else { openmc::global_universes[it->second]->cells.push_back(i); } + + + if(DAGMC->is_implicit_complement(vol_handle)) { + // assuming implicit complement is void for now + c->material.push_back(openmc::C_MATERIAL_VOID); + continue; + } + + if(DAGMC->has_prop(vol_handle, "mat")){ + std::string mat_value; + rval = DAGMC->prop_value(vol_handle, "mat", mat_value); + MB_CHK_ERR_CONT(rval); + int mat_id = std::stoi(mat_value); + c->material.push_back(mat_id); + } + else { + std::cout << "Warning: volume without material found!" << std::endl; + } + } // initialize surface objects From 9688e23609a73679b4afed4dd2871bdc519e84c6 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 16 Aug 2018 18:08:29 -0500 Subject: [PATCH 048/175] Updating setup to allow vacuum boundary conditions. --- src/cad.cpp | 23 +++++++++++++++++++++-- src/tracking.F90 | 8 +++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index 3d73e4534..c9d9f6221 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -21,7 +21,8 @@ void load_cad_geometry_c() std::vector< std::string > prop_keywords; prop_keywords.push_back("mat"); - + prop_keywords.push_back("boundary"); + std::map ph; DAGMC->parse_properties(prop_keywords, ph, ":"); MB_CHK_ERR_CONT(rval); @@ -83,6 +84,7 @@ void load_cad_geometry_c() } else { std::cout << "Warning: volume without material found!" << std::endl; + c->material.push_back(openmc::C_MATERIAL_VOID); } } @@ -93,11 +95,28 @@ void load_cad_geometry_c() for(int i = 0; i < openmc::n_surfaces; i++) { + moab::EntityHandle surf_handle = DAGMC->entity_by_index(2, i+1); + // set cell ids using global IDs openmc::CADSurface* s = new openmc::CADSurface(); s->id = DAGMC->id_by_index(2, i+1); s->dagmc_ptr = DAGMC; - s->bc = openmc::BC_TRANSMIT; + + if(DAGMC->has_prop(surf_handle, "boundary")) { + std::string value; + rval = DAGMC->prop_value(surf_handle, "boundary", value); + MB_CHK_ERR_CONT(rval); + if(value.find("Vacuum") != std::string::npos) { + s->bc = openmc::BC_VACUUM; + } + else { + s->bc = openmc::BC_TRANSMIT; + } + } + else { + s->bc = openmc::BC_TRANSMIT; + } + openmc::surfaces_c[i] = s; openmc::surface_map[s->id] = s->id; } diff --git a/src/tracking.F90 b/src/tracking.F90 index 99eb22688..b3f302e1e 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -330,7 +330,13 @@ contains p % material = cells(i_cell) % material(1) p % sqrtKT = cells(i_cell) % sqrtKT(1) - if (is_implicit_complement(cells(i_cell))) then + i_surface = abs(p % surface) + surf => surfaces(i_surface) + if ( surf % bc() == BC_VACUUM .and. (run_mode /= MODE_PLOTTING)) then + ! ======================================================================= + ! PARTICLE LEAKS OUT OF PROBLEM + + ! Kill particle p % alive = .false. end if From d245842137b2a8361cbd99587fbec4ce0d4db676 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 10:07:10 -0500 Subject: [PATCH 049/175] Porting material assignments from C cells when using CAD. --- src/cell.cpp | 2 ++ src/geometry_header.F90 | 7 +++++++ src/input_xml.F90 | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cell.cpp b/src/cell.cpp index c544c5b3d..ebdc549d8 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -762,6 +762,8 @@ extern "C" { int cell_type(Cell* c) {return c->type_;} + int cell_material(Cell* c, int32_t mat_ind) {return c->material[mat_ind-1];} + #ifdef CAD int32_t next_cell(CADCell* cur_cell, CADSurface *surf_xed ) { moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id); diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index b58b5415b..3b6c702f3 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -28,6 +28,13 @@ module geometry_header type(C_PTR) :: ptr end function cell_pointer + function cell_material_c(cell_ptr, mat_ind) bind(C, name='cell_material') result(mat_id) + import C_PTR, C_INT32_T + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T), intent(in), value :: mat_ind + integer(C_INT32_T) :: mat_id + end function cell_material_c + function cell_id_c(cell_ptr) bind(C, name='cell_id') result(id) import C_PTR, C_INT32_T type(C_PTR), intent(in), value :: cell_ptr diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c8403f863..e58b2eb40 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -600,7 +600,7 @@ contains c => cells(i) ! additional metadata spoofing allocate(c % material(1)) - c % material(1) = 40 + c % material(1) = cell_material_c(cell_pointer_c(i-1), 1) allocate(c % sqrtKT(1)) c % sqrtkT(1) = 293 c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) From 7587e15a286f0f2e9c6fcb772b76ad4d6f01fa49 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 10:08:24 -0500 Subject: [PATCH 050/175] Moved CAD surface crossing code to a better location. --- src/geometry.cpp | 21 +++++++++++++++++++++ src/tracking.F90 | 28 ---------------------------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/geometry.cpp b/src/geometry.cpp index 857dbd32e..abbca4481 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -56,6 +56,27 @@ find_cell(Particle* p, int search_surf) { p->coord[i].reset(); } +#ifdef CAD + // if (dagmc) then + // i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) + // p % last_material = p % material + // p % last_sqrtKT = p % sqrtKT + // p % coord(1) % cell = i_cell + // p % cell_instance = 1 + // p % material = cells(i_cell) % material(1) + // p % sqrtKT = cells(i_cell) % sqrtKT(1) + + // ! Show cell information on trace + // if (verbosity >= 10 .or. trace) then + // call write_message(" Entering cell " // trim(to_str(& + // cells(i_cell) % id()))) + // call write_message(" with material " // trim(to_str(p % material))) + // end if + + // return + // end if +#endif + // Determine universe (if not yet set, use root universe) int i_universe = p->coord[p->n_coord-1].universe; if (i_universe == C_NONE) { diff --git a/src/tracking.F90 b/src/tracking.F90 index b3f302e1e..6037daac9 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -318,34 +318,6 @@ contains class(Surface), pointer :: surf class(Surface), pointer :: surf2 ! periodic partner surface -#ifdef CAD - if (dagmc) then - i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) - ! save material and temp - p % last_material = p % material - p % last_sqrtkT = p % sqrtKT - ! set new cell value - p % coord(1) % cell = i_cell - p % cell_instance = 1 - p % material = cells(i_cell) % material(1) - p % sqrtKT = cells(i_cell) % sqrtKT(1) - - i_surface = abs(p % surface) - surf => surfaces(i_surface) - if ( surf % bc() == BC_VACUUM .and. (run_mode /= MODE_PLOTTING)) then - ! ======================================================================= - ! PARTICLE LEAKS OUT OF PROBLEM - - ! Kill particle - p % alive = .false. - end if - - return - - end if -#endif - - i_surface = abs(p % surface) surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then From 2a7849f3c4bea3df740f703bdc7925240d779f12 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 10:08:59 -0500 Subject: [PATCH 051/175] Indicating when a particle is lost rather than causing a fatal error. --- src/cell.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cell.cpp b/src/cell.cpp index ebdc549d8..e95f4c4ac 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -604,7 +604,14 @@ std::pair CADCell::distance(Position p, Direction u, int32_t on double dist; dagmc_ptr->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); - int surf_idx = dagmc_ptr->index_by_handle(hit_surf); + int surf_idx; + if(hit_surf != 0) { + surf_idx = dagmc_ptr->index_by_handle(hit_surf); + } + // indicate that particle is lost + else { + surf_idx = -1; + } std::pair result(dist, surf_idx); From c31765e7076e1532b561857616e20f60a10756e7 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 10:20:47 -0500 Subject: [PATCH 052/175] Removing implicit complement exposure, shouldn't be needed anymore. Cleaning up some formatting too. --- src/cell.cpp | 5 +---- src/constants.F90 | 2 +- src/geometry.F90 | 13 ------------- src/tracking.F90 | 2 +- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index e95f4c4ac..cfefe0a7f 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -772,6 +772,7 @@ extern "C" { int cell_material(Cell* c, int32_t mat_ind) {return c->material[mat_ind-1];} #ifdef CAD + int32_t next_cell(CADCell* cur_cell, CADSurface *surf_xed ) { moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id); moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id); @@ -782,10 +783,6 @@ extern "C" { return cur_cell->dagmc_ptr->index_by_handle(new_vol); } - bool is_implicit_complement(CADCell *c) { - moab::EntityHandle handle = c->dagmc_ptr->entity_by_id(3,c->id); - return c->dagmc_ptr->is_implicit_complement(handle); - } #endif int32_t cell_universe(Cell* c) {return c->universe_;} diff --git a/src/constants.F90 b/src/constants.F90 index 925ffc808..77b4a06e0 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -129,7 +129,7 @@ module constants integer(C_INT), bind(C, name='FILL_LATTICE') :: FILL_LATTICE_C = FILL_LATTICE ! Void material - integer, parameter :: MATERIAL_VOID = -1 + integer, parameter :: MATERIAL_VOID = -2 ! Flag to say that the outside of a lattice is not defined integer, parameter :: NO_OUTER_UNIVERSE = -1 diff --git a/src/geometry.F90 b/src/geometry.F90 index 0eb463fe2..90bdccb92 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -66,13 +66,6 @@ module geometry integer(C_INT32_T) :: new_cell end function next_cell_c - function is_implicit_complement_C(cell) & - bind(C, name="is_implicit_complement") result(res) - import C_PTR, C_BOOL - type(C_PTR), intent(in), value :: cell - logical(C_BOOL) :: res - end function is_implicit_complement_C - #endif end interface @@ -96,12 +89,6 @@ contains new_cell = next_cell_c(c%ptr, s%ptr) end function next_cell - function is_implicit_complement(c) result(res) - type(Cell), intent(in) :: c - logical:: res - res = is_implicit_complement_c(c%ptr) - end function is_implicit_complement - #endif !=============================================================================== diff --git a/src/tracking.F90 b/src/tracking.F90 index 6037daac9..5e1e019a8 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -8,7 +8,7 @@ module tracking use geometry, only: find_cell, distance_to_boundary, cross_lattice,& check_cell_overlap #ifdef CAD - use geometry, only: next_cell, is_implicit_complement + use geometry, only: next_cell #endif use material_header, only: materials, Material use message_passing From aa1374504b519f9c6abdfa45fefa3d93d0eacd9c Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 10:54:03 -0500 Subject: [PATCH 053/175] Supporting other boundary conditions. --- src/cad.cpp | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index c9d9f6221..f49295ae4 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -2,9 +2,15 @@ #ifdef CAD #include "cad.h" +#include "error.h" + +#include +#include moab::DagMC* DAGMC; +#define TOLOWER(S) std::transform(S.begin(), S.end(), S.begin(), ::tolower) + void load_cad_geometry_c() { if(!DAGMC) { @@ -78,15 +84,20 @@ void load_cad_geometry_c() if(DAGMC->has_prop(vol_handle, "mat")){ std::string mat_value; rval = DAGMC->prop_value(vol_handle, "mat", mat_value); - MB_CHK_ERR_CONT(rval); - int mat_id = std::stoi(mat_value); - c->material.push_back(mat_id); + MB_CHK_ERR_CONT(rval); + TOLOWER(mat_value); + + if(mat_value == "void") { + c->material.push_back(openmc::C_MATERIAL_VOID); + } + else { + c->material.push_back(std::stoi(mat_value)); + } } else { std::cout << "Warning: volume without material found!" << std::endl; c->material.push_back(openmc::C_MATERIAL_VOID); - } - + } } // initialize surface objects @@ -103,20 +114,36 @@ void load_cad_geometry_c() s->dagmc_ptr = DAGMC; if(DAGMC->has_prop(surf_handle, "boundary")) { - std::string value; - rval = DAGMC->prop_value(surf_handle, "boundary", value); + std::string bc_value; + rval = DAGMC->prop_value(surf_handle, "boundary", bc_value); MB_CHK_ERR_CONT(rval); - if(value.find("Vacuum") != std::string::npos) { - s->bc = openmc::BC_VACUUM; - } - else { + TOLOWER(bc_value); + + if(bc_value == "transmit" || bc_value == "transmission") { s->bc = openmc::BC_TRANSMIT; } + else if(bc_value == "vacuum") { + s->bc = openmc::BC_VACUUM; + } + else if(bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { + s->bc = openmc::BC_REFLECT; + } + else if(bc_value == "periodic") { + openmc::fatal_error("Periodic boundary condition not supported in CAD."); + } + else { + std::stringstream err_msg; + err_msg << "Unknown boundary condition \"" << s->bc + << "\" specified on surface " << s->id; + openmc::fatal_error(err_msg); + } } + // if no BC property is found, set to transmit else { s->bc = openmc::BC_TRANSMIT; } - + + // add to global array and map openmc::surfaces_c[i] = s; openmc::surface_map[s->id] = s->id; } From 32f91ace56eb525656b721c667264ac27c9f859b Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 13:36:16 -0500 Subject: [PATCH 054/175] Some fixes after the rebase. --- include/openmc/surface.h | 4 ++++ src/cad.cpp | 10 +++++----- src/cell.cpp | 2 -- src/constants.F90 | 4 ++-- src/geometry_header.F90 | 7 ------- src/input_xml.F90 | 8 ++++---- src/surface.cpp | 2 +- 7 files changed, 16 insertions(+), 21 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 3f7e6ac3f..7f1feb4b9 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -404,6 +404,10 @@ extern "C" { int surface_bc(Surface* surf); bool surface_sense(Surface* surf, double xyz[3], double uvw[3]); void surface_reflect(Surface* surf, double xyz[3], double uvw[3]); + /* double surface_distance(Surface* surf, double xyz[3], double uvw[3], */ + /* bool coincident); */ + /* void surface_normal(Surface* surf, double xyz[3], double uvw[3]); */ + /* void surface_to_hdf5(CSGSurface* surf, hid_t group); */ int surface_i_periodic(PeriodicSurface* surf); bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], double uvw[3]); diff --git a/src/cad.cpp b/src/cad.cpp index f49295ae4..a3d1c7648 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -77,7 +77,7 @@ void load_cad_geometry_c() if(DAGMC->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now - c->material.push_back(openmc::C_MATERIAL_VOID); + c->material.push_back(openmc::MATERIAL_VOID); continue; } @@ -88,7 +88,7 @@ void load_cad_geometry_c() TOLOWER(mat_value); if(mat_value == "void") { - c->material.push_back(openmc::C_MATERIAL_VOID); + c->material.push_back(openmc::MATERIAL_VOID); } else { c->material.push_back(std::stoi(mat_value)); @@ -96,13 +96,13 @@ void load_cad_geometry_c() } else { std::cout << "Warning: volume without material found!" << std::endl; - c->material.push_back(openmc::C_MATERIAL_VOID); + c->material.push_back(openmc::MATERIAL_VOID); } } // initialize surface objects openmc::n_surfaces = DAGMC->num_entities(2); - openmc::surfaces_c = new openmc::Surface*[openmc::n_surfaces]; + openmc::global_surfaces.resize(openmc::n_surfaces); for(int i = 0; i < openmc::n_surfaces; i++) { @@ -144,7 +144,7 @@ void load_cad_geometry_c() } // add to global array and map - openmc::surfaces_c[i] = s; + openmc::global_surfaces[i] = s; openmc::surface_map[s->id] = s->id; } diff --git a/src/cell.cpp b/src/cell.cpp index cfefe0a7f..d3eba08e5 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -769,8 +769,6 @@ extern "C" { int cell_type(Cell* c) {return c->type_;} - int cell_material(Cell* c, int32_t mat_ind) {return c->material[mat_ind-1];} - #ifdef CAD int32_t next_cell(CADCell* cur_cell, CADSurface *surf_xed ) { diff --git a/src/constants.F90 b/src/constants.F90 index 77b4a06e0..a3118f84d 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -129,7 +129,7 @@ module constants integer(C_INT), bind(C, name='FILL_LATTICE') :: FILL_LATTICE_C = FILL_LATTICE ! Void material - integer, parameter :: MATERIAL_VOID = -2 + integer, parameter :: MATERIAL_VOID = -1 ! Flag to say that the outside of a lattice is not defined integer, parameter :: NO_OUTER_UNIVERSE = -1 @@ -424,7 +424,7 @@ module constants real(8), parameter :: ERROR_REAL = -huge(0.0_8) * 0.917826354_8 ! Running modes - integer, parameter :: & + integer, parameter :: & MODE_FIXEDSOURCE = 1, & ! Fixed source mode MODE_EIGENVALUE = 2, & ! K eigenvalue mode MODE_PLOTTING = 3, & ! Plotting mode diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 3b6c702f3..942a2f77c 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -27,13 +27,6 @@ module geometry_header integer(C_INT32_T), intent(in), value :: cell_ind type(C_PTR) :: ptr end function cell_pointer - - function cell_material_c(cell_ptr, mat_ind) bind(C, name='cell_material') result(mat_id) - import C_PTR, C_INT32_T - type(C_PTR), intent(in), value :: cell_ptr - integer(C_INT32_T), intent(in), value :: mat_ind - integer(C_INT32_T) :: mat_id - end function cell_material_c function cell_id_c(cell_ptr) bind(C, name='cell_id') result(id) import C_PTR, C_INT32_T diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e58b2eb40..afb68c946 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -599,8 +599,8 @@ contains do i = 1, n_cells c => cells(i) ! additional metadata spoofing - allocate(c % material(1)) - c % material(1) = cell_material_c(cell_pointer_c(i-1), 1) +! allocate(c % material(1)) +! c % material(1) = cell_material(cell_pointer(i-1), 1) allocate(c % sqrtKT(1)) c % sqrtkT(1) = 293 c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) @@ -852,7 +852,7 @@ contains allocate(surfaces(n_surfaces)) do i = 1, n_surfaces - surfaces(i) % ptr = surface_pointer_c(i - 1); + surfaces(i) % ptr = surface_pointer(i - 1); ! Add surface to dictionary call surface_dict % set(surfaces(i) % id(), i) end do @@ -868,7 +868,7 @@ contains do i = 1, n_cells c => cells(i) - c % ptr = cell_pointer_c(i - 1) + c % ptr = cell_pointer(i - 1) ! Check to make sure 'id' hasn't been used if (cell_dict % has(c % id())) then call fatal_error("Two or more cells use the same unique ID: " & diff --git a/src/surface.cpp b/src/surface.cpp index 18947a86b..174a24deb 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -249,7 +249,7 @@ CSGSurface::to_hdf5(hid_t group_id) const // CADSurface implementation //============================================================================== #ifdef CAD -CADSurface::CADSurface() :Surface{} {} // empty constructor +CADSurface::CADSurface() : Surface{} {} // empty constructor double CADSurface::evaluate(Position r) const { From 28f04592a34c7470212b67f1b4610294bc9bf0ad Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 14:07:05 -0500 Subject: [PATCH 055/175] Factoring out the CAD geometry setup. --- src/input_xml.F90 | 147 +++++++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 59 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index afb68c946..468e21b33 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -561,6 +561,92 @@ contains end subroutine read_settings_xml_f + +!=============================================================================== +! READ_GEOMETRY_CAD reads data from a DAGMC .h5m file, checking +! for material properties and surface boundary conditions +! some universe information is spoofed for now +!=============================================================================== + + subroutine read_geometry_cad() + + integer :: i, j + integer :: univ_id + integer :: n_cells_in_univ + logical :: file_exists + character(MAX_LINE_LEN) :: filename + type(Cell), pointer :: c + type(VectorInt) :: univ_ids ! List of all universe IDs + type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each + ! universe contains + + ! Check if dagmc.h5m exists + filename = trim(path_input) // "dagmc.h5m" + inquire(FILE=filename, EXIST=file_exists) + if (.not. file_exists) then + call fatal_error("Geometry CAD file '" // trim(filename) // "' does not & + &exist!") + end if + + call write_message("Reading CAD geometry...", 5) + call load_cad_geometry() + call allocate_surfaces() + call allocate_cells() + + ! setup universe data structs + do i = 1, n_cells + c => cells(i) + ! additional metadata spoofing + allocate(c % sqrtKT(1)) + c % sqrtkT(1) = -1.0 ! rely on temps from elsewhere + univ_id = c % universe() + if (.not. allocated(c%region)) allocate(c%region(0)) + + if (.not. cells_in_univ_dict % has(univ_id)) then + n_universes = n_universes + 1 + n_cells_in_univ = 1 + call universe_dict % set(univ_id, n_universes) + call univ_ids % push_back(univ_id) + else + n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) + end if + call cells_in_univ_dict % set(univ_id, n_cells_in_univ) + end do + + ! ========================================================================== + ! SETUP UNIVERSES + + ! Allocate universes, universe cell arrays, and assign base universe + allocate(universes(n_universes)) + do i = 1, n_universes + associate (u => universes(i)) + u % id = univ_ids % data(i) + ! Allocate cell list + n_cells_in_univ = cells_in_univ_dict % get(u % id) + allocate(u % cells(n_cells_in_univ)) + u % cells(:) = 0 + end associate + end do + + root_universe = 0 + 1 + + do i = 1, n_cells + ! Get index in universes array + j = universe_dict % get(cells(i) % universe()) + ! Set the first zero entry in the universe cells array to the index in the + ! global cells array + associate (u => universes(j)) + u % cells(find(u % cells, 0)) = i + end associate + end do + + ! Clear dictionary + call cells_in_univ_dict%clear() + + return + + end subroutine read_geometry_cad + !=============================================================================== ! READ_GEOMETRY_XML reads data from a geometry.xml file and parses it, checking ! for errors and placing properly-formatted data in the right data structures @@ -590,65 +676,8 @@ contains ! universe contains #ifdef CAD if (dagmc) then - call write_message("Reading CAD geometry...", 5) - call load_cad_geometry() - call allocate_surfaces() - call allocate_cells() - - ! setup universe data structs - do i = 1, n_cells - c => cells(i) - ! additional metadata spoofing -! allocate(c % material(1)) -! c % material(1) = cell_material(cell_pointer(i-1), 1) - allocate(c % sqrtKT(1)) - c % sqrtkT(1) = 293 - c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) - univ_id = c % universe() - if (.not. allocated(c%region)) allocate(c%region(0)) - - if (.not. cells_in_univ_dict % has(univ_id)) then - n_universes = n_universes + 1 - n_cells_in_univ = 1 - call universe_dict % set(univ_id, n_universes) - call univ_ids % push_back(univ_id) - else - n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) - end if - call cells_in_univ_dict % set(univ_id, n_cells_in_univ) - end do - - ! ========================================================================== - ! SETUP UNIVERSES - - ! Allocate universes, universe cell arrays, and assign base universe - allocate(universes(n_universes)) - do i = 1, n_universes - associate (u => universes(i)) - u % id = univ_ids % data(i) - ! Allocate cell list - n_cells_in_univ = cells_in_univ_dict % get(u % id) - allocate(u % cells(n_cells_in_univ)) - u % cells(:) = 0 - end associate - end do - - root_universe = 0 + 1 - - do i = 1, n_cells - ! Get index in universes array - j = universe_dict % get(cells(i) % universe()) - ! Set the first zero entry in the universe cells array to the index in the - ! global cells array - associate (u => universes(j)) - u % cells(find(u % cells, 0)) = i - end associate - end do - - ! Clear dictionary - call cells_in_univ_dict%clear() - - return + call read_geometry_cad() + return end if #endif From da2a99b475708d823398a8b00e6e63e3ca79fd14 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 14:52:25 -0500 Subject: [PATCH 056/175] Implementing a couple more methods for CAD surfaces. --- include/openmc/surface.h | 8 ++++++++ src/surface.cpp | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 7f1feb4b9..858cb4846 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -45,6 +45,14 @@ extern std::map surface_map; struct BoundingBox { + + BoundingBox(double x_min, double x_max, + double y_min, double y_max, + double z_min, double z_max) : + xmin(x_min), xmax(x_max), + ymin(y_min), ymax(y_max), + zmin(z_min), zmax(z_max) {} + double xmin; double xmax; double ymin; diff --git a/src/surface.cpp b/src/surface.cpp index 174a24deb..aee21287e 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -257,19 +257,27 @@ double CADSurface::evaluate(Position r) const } double CADSurface::distance(Position p, Direction u, bool coincident) const { - return 0.0; + moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); + moab::EntityHandle hit_surf; + double dist; + dagmc_ptr->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); + if (dist < 0.0) dist = INFTY; + return dist; } Direction CADSurface::normal(Position p) const { - Direction u; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); dagmc_ptr->get_angle(surf, p.xyz, u.xyz); return u; - } -BoundingBox CADSurface::bounding_box() const { return BoundingBox(); } +BoundingBox CADSurface::bounding_box() const { + moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); + double min[3], max[3]; + dagmc_ptr->getobb(surf, min, max); + return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); +} #endif //============================================================================== // PeriodicSurface implementation From 3492a1a44d4b0a6c3f32270c35b371befa6ae597 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 14:53:31 -0500 Subject: [PATCH 057/175] Updating travis temporarily. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 279f6b535..80e9c588a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,8 +39,6 @@ env: notifications: webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN before_install: - - sudo add-apt-repository ppa:nschloe/hdf5-backports -y - - sudo apt-get update -q - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev libblas-dev liblapack-dev -y install: - ./tools/ci/travis-install.sh From 7455212bf5808439f15c6b6abe76b18c58f53d5f Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 15:14:29 -0500 Subject: [PATCH 058/175] ifdef-ing read_geometry_cad --- src/input_xml.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 468e21b33..1a2013f1c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -562,6 +562,8 @@ contains end subroutine read_settings_xml_f +#ifdef CAD + !=============================================================================== ! READ_GEOMETRY_CAD reads data from a DAGMC .h5m file, checking ! for material properties and surface boundary conditions @@ -646,6 +648,8 @@ contains return end subroutine read_geometry_cad + +#endif !=============================================================================== ! READ_GEOMETRY_XML reads data from a geometry.xml file and parses it, checking From 122cce8ed4da874c99c7c42c718a37885c7cabae Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 17 Aug 2018 16:30:40 -0500 Subject: [PATCH 059/175] Ahereing to Fortran styleguide. --- src/geometry.cpp | 29 +++++++------- src/geometry_header.F90 | 2 +- src/input_xml.F90 | 86 ++++++++++++++++++++--------------------- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/src/geometry.cpp b/src/geometry.cpp index abbca4481..2dca114cf 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -58,22 +58,21 @@ find_cell(Particle* p, int search_surf) { #ifdef CAD // if (dagmc) then - // i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) - // p % last_material = p % material - // p % last_sqrtKT = p % sqrtKT - // p % coord(1) % cell = i_cell - // p % cell_instance = 1 - // p % material = cells(i_cell) % material(1) - // p % sqrtKT = cells(i_cell) % sqrtKT(1) + // i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) + // p % last_material = p % material + // p % last_sqrtKT = p % sqrtKT + // p % coord(1) % cell = i_cell + // p % cell_instance = 1 + // p % material = cells(i_cell) % material(1) + // p % sqrtKT = cells(i_cell) % sqrtKT(1) - // ! Show cell information on trace - // if (verbosity >= 10 .or. trace) then - // call write_message(" Entering cell " // trim(to_str(& - // cells(i_cell) % id()))) - // call write_message(" with material " // trim(to_str(p % material))) - // end if - - // return + // ! Show cell information on trace + // if (verbosity >= 10 .or. trace) then + // call write_message(" Entering cell " // trim(to_str(& + // cells(i_cell) % id()))) + // end if + + // return // end if #endif diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 942a2f77c..b58b5415b 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -27,7 +27,7 @@ module geometry_header integer(C_INT32_T), intent(in), value :: cell_ind type(C_PTR) :: ptr end function cell_pointer - + function cell_id_c(cell_ptr) bind(C, name='cell_id') result(id) import C_PTR, C_INT32_T type(C_PTR), intent(in), value :: cell_ptr diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 1a2013f1c..9954a9b85 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -563,7 +563,7 @@ contains #ifdef CAD - + !=============================================================================== ! READ_GEOMETRY_CAD reads data from a DAGMC .h5m file, checking ! for material properties and surface boundary conditions @@ -589,68 +589,68 @@ contains call fatal_error("Geometry CAD file '" // trim(filename) // "' does not & &exist!") end if - + call write_message("Reading CAD geometry...", 5) call load_cad_geometry() call allocate_surfaces() call allocate_cells() - + ! setup universe data structs do i = 1, n_cells - c => cells(i) - ! additional metadata spoofing - allocate(c % sqrtKT(1)) - c % sqrtkT(1) = -1.0 ! rely on temps from elsewhere - univ_id = c % universe() - if (.not. allocated(c%region)) allocate(c%region(0)) - - if (.not. cells_in_univ_dict % has(univ_id)) then - n_universes = n_universes + 1 - n_cells_in_univ = 1 - call universe_dict % set(univ_id, n_universes) - call univ_ids % push_back(univ_id) - else - n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) - end if - call cells_in_univ_dict % set(univ_id, n_cells_in_univ) - end do - + c => cells(i) + ! additional metadata spoofing + allocate(c % sqrtKT(1)) + c % sqrtkT(1) = -1.0 ! rely on temps from elsewhere + univ_id = c % universe() + if (.not. allocated(c%region)) allocate(c%region(0)) + + if (.not. cells_in_univ_dict % has(univ_id)) then + n_universes = n_universes + 1 + n_cells_in_univ = 1 + call universe_dict % set(univ_id, n_universes) + call univ_ids % push_back(univ_id) + else + n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) + end if + call cells_in_univ_dict % set(univ_id, n_cells_in_univ) + end do + ! ========================================================================== ! SETUP UNIVERSES - + ! Allocate universes, universe cell arrays, and assign base universe allocate(universes(n_universes)) do i = 1, n_universes - associate (u => universes(i)) - u % id = univ_ids % data(i) - ! Allocate cell list - n_cells_in_univ = cells_in_univ_dict % get(u % id) - allocate(u % cells(n_cells_in_univ)) - u % cells(:) = 0 - end associate + associate (u => universes(i)) + u % id = univ_ids % data(i) + ! Allocate cell list + n_cells_in_univ = cells_in_univ_dict % get(u % id) + allocate(u % cells(n_cells_in_univ)) + u % cells(:) = 0 + end associate end do - + root_universe = 0 + 1 - + do i = 1, n_cells - ! Get index in universes array - j = universe_dict % get(cells(i) % universe()) - ! Set the first zero entry in the universe cells array to the index in the - ! global cells array - associate (u => universes(j)) - u % cells(find(u % cells, 0)) = i - end associate + ! Get index in universes array + j = universe_dict % get(cells(i) % universe()) + ! Set the first zero entry in the universe cells array to the index in the + ! global cells array + associate (u => universes(j)) + u % cells(find(u % cells, 0)) = i + end associate end do - + ! Clear dictionary call cells_in_univ_dict%clear() - + return end subroutine read_geometry_cad #endif - + !=============================================================================== ! READ_GEOMETRY_XML reads data from a geometry.xml file and parses it, checking ! for errors and placing properly-formatted data in the right data structures @@ -680,8 +680,8 @@ contains ! universe contains #ifdef CAD if (dagmc) then - call read_geometry_cad() - return + call read_geometry_cad() + return end if #endif From 53dc9b4e48fd965d665490f6578785ab9a65b727 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 4 Sep 2018 17:34:32 -0500 Subject: [PATCH 060/175] Fixes after rebase. Non-CAD build is working. --- include/openmc/cell.h | 3 ++- include/openmc/surface.h | 9 +++++---- src/cell.cpp | 21 +++++++++++---------- src/geometry.F90 | 8 -------- src/input_xml.F90 | 8 -------- src/source.cpp | 2 +- 6 files changed, 19 insertions(+), 32 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index a2910e74c..d69547721 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -111,7 +111,8 @@ public: std::vector offset_; //!< Distribcell offset table explicit Cell(pugi::xml_node cell_node); - + inline Cell() {}; + //! Determine if a cell contains the particle at a given location. //! //! The bounds of the cell are detemined by a logical expression involving diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 858cb4846..d1e3f2b49 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -113,6 +113,11 @@ public: //! \return Normal direction virtual Direction normal(Position r) const = 0; + //! Write all information needed to reconstruct the surface to an HDF5 group. + //! \param group_id An HDF5 group id. + //TODO: this probably needs to include i_periodic for PeriodicSurface + virtual void to_hdf5(hid_t group_id) const = 0; + }; class CSGSurface : public Surface @@ -121,11 +126,7 @@ class CSGSurface : public Surface explicit CSGSurface(pugi::xml_node surf_node); explicit CSGSurface(); - //! Write all information needed to reconstruct the surface to an HDF5 group. - //! \param group_id An HDF5 group id. - //TODO: this probably needs to include i_periodic for PeriodicSurface void to_hdf5(hid_t group_id) const; - protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; diff --git a/src/cell.cpp b/src/cell.cpp index d3eba08e5..f504ef0bb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -351,7 +351,7 @@ CSGCell::CSGCell(pugi::xml_node cell_node) err_msg << "Non-3D translation vector applied to cell " << id_; fatal_error(err_msg); } - translation_ = xyz; + translation_ = *xyz.begin(); } // Read the rotation transform. @@ -371,15 +371,16 @@ CSGCell::CSGCell(pugi::xml_node cell_node) } // Store the rotation angles. + std::vector rot_vec = *rot.begin(); rotation_.reserve(12); - rotation_.push_back(rot[0]); - rotation_.push_back(rot[1]); - rotation_.push_back(rot[2]); + rotation_.push_back(rot_vec[0]); + rotation_.push_back(rot_vec[1]); + rotation_.push_back(rot_vec[2]); // Compute and store the rotation matrix. - auto phi = -rot[0] * PI / 180.0; - auto theta = -rot[1] * PI / 180.0; - auto psi = -rot[2] * PI / 180.0; + auto phi = -rot_vec[0] * PI / 180.0; + auto theta = -rot_vec[1] * PI / 180.0; + auto psi = -rot_vec[2] * PI / 180.0; rotation_.push_back(std::cos(theta) * std::cos(psi)); rotation_.push_back(-std::cos(phi) * std::sin(psi) + std::sin(phi) * std::sin(theta) * std::cos(psi)); @@ -445,7 +446,7 @@ CSGCell::to_hdf5(hid_t cell_group) const // Create a group for this cell. std::stringstream group_name; group_name << "cell " << id_; - auto group = create_group(cells_group, group_name); + auto group = create_group(cell_group, group_name); if (!name_.empty()) { write_string(group, "name", name_, false); @@ -645,7 +646,7 @@ read_cells(pugi::xml_node* node) // Loop over XML cell elements and populate the array. cells.reserve(n_cells); for (pugi::xml_node cell_node: node->children("cell")) { - global_cells.push_back(new CSGCell(cell_node)); + cells.push_back(new CSGCell(cell_node)); } // Populate the Universe vector and map. @@ -811,7 +812,7 @@ extern "C" { { cells.reserve(cells.size() + n); for (int32_t i = 0; i < n; i++) { - global_cells.push_back(new CSGCell()); + cells.push_back(new CSGCell()); } n_cells = cells.size(); } diff --git a/src/geometry.F90 b/src/geometry.F90 index 90bdccb92..c06084888 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -72,14 +72,6 @@ module geometry contains - function cell_contains(c, p) result(in_cell) - type(Cell), intent(in) :: c - type(Particle), intent(in) :: p - logical :: in_cell - in_cell = cell_contains_c(c%ptr, p%coord(p%n_coord)%xyz, & - p%coord(p%n_coord)%uvw, p%surface) - end function cell_contains - #ifdef CAD function next_cell(c, s) result(new_cell) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 9954a9b85..3875bc80a 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -431,8 +431,6 @@ contains trace_batch = temp_int_array3(1) trace_gen = temp_int_array3(2) trace_particle = int(temp_int_array3(3), 8) ->>>>>>> Updates to meet style guide. ->>>>>>> Updates to meet style guide. end if ! Particle tracks @@ -755,12 +753,6 @@ contains c % ptr = cell_pointer(i - 1) -<<<<<<< 25ab6776f10a1ea974b3aa15f74271aa80748913 -======= - ! Initialize distribcell instances and distribcell index - c % distribcell_index = NONE - ->>>>>>> Updates to meet style guide. ! Get pointer to i-th cell node node_cell = node_cell_list(i) diff --git a/src/source.cpp b/src/source.cpp index 666bbb783..f2800c1cc 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -316,7 +316,7 @@ Bank sample_external_source() } // Sample source site from i-th source distribution - Bank site {external_sources[i].sample()}; + Bank site = external_sources[i].sample(); // If running in MG, convert site % E to group if (!settings::run_CE) { From 289a6b37ff7c1300d7c791714bffe3c60d254623 Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 5 Sep 2018 08:40:57 -0500 Subject: [PATCH 061/175] Reverting some changes for older gcc compiler (<5.0). --- src/cell.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index f504ef0bb..01f4eb6d4 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -351,7 +351,7 @@ CSGCell::CSGCell(pugi::xml_node cell_node) err_msg << "Non-3D translation vector applied to cell " << id_; fatal_error(err_msg); } - translation_ = *xyz.begin(); + translation_ = xyz; } // Read the rotation transform. @@ -371,16 +371,15 @@ CSGCell::CSGCell(pugi::xml_node cell_node) } // Store the rotation angles. - std::vector rot_vec = *rot.begin(); rotation_.reserve(12); - rotation_.push_back(rot_vec[0]); - rotation_.push_back(rot_vec[1]); - rotation_.push_back(rot_vec[2]); + rotation_.push_back(rot[0]); + rotation_.push_back(rot[1]); + rotation_.push_back(rot[2]); // Compute and store the rotation matrix. - auto phi = -rot_vec[0] * PI / 180.0; - auto theta = -rot_vec[1] * PI / 180.0; - auto psi = -rot_vec[2] * PI / 180.0; + auto phi = -rot[0] * PI / 180.0; + auto theta = -rot[1] * PI / 180.0; + auto psi = -rot[2] * PI / 180.0; rotation_.push_back(std::cos(theta) * std::cos(psi)); rotation_.push_back(-std::cos(phi) * std::sin(psi) + std::sin(phi) * std::sin(theta) * std::cos(psi)); From 146d7002224cfdf676168ca55f1caee89299190a Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 4 Sep 2018 21:49:58 -0500 Subject: [PATCH 062/175] Some updates to get the CAD build working again. --- include/openmc/settings.h | 2 +- include/openmc/surface.h | 2 ++ src/cad.cpp | 42 ++++++++++++++-------------- src/cad.h | 4 +-- src/cell.cpp | 8 +++--- src/input_xml.F90 | 59 ++++++++++++++++----------------------- src/settings.F90 | 2 +- src/settings.cpp | 14 +++++++++- src/summary.cpp | 4 +-- src/surface.cpp | 8 ++++-- 10 files changed, 75 insertions(+), 70 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index e5684c7ae..6565d3e46 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -45,6 +45,7 @@ extern "C" bool ufs_on; //!< uniform fission site method on? extern "C" bool urr_ptables_on; //!< use unresolved resonance prob. tables? extern "C" bool write_all_tracks; //!< write track files for every particle? extern "C" bool write_initial_source; //!< write out initial source file? +extern "C" bool dagmc; //!< indicator of DAGMC geometry // Paths to various files extern std::string path_cross_sections; //!< path to cross_sections.xml @@ -86,7 +87,6 @@ extern "C" int trigger_batch_interval; //!< Batch interval for triggers extern "C" int verbosity; //!< How verbose to make output extern "C" double weight_cutoff; //!< Weight cutoff for Russian roulette extern "C" double weight_survive; //!< Survival weight after Russian roulette - } // namespace settings //! Read settings from XML file diff --git a/include/openmc/surface.h b/include/openmc/surface.h index d1e3f2b49..f5b30e413 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -147,6 +147,8 @@ class CADSurface : public Surface Direction normal(Position p) const; //! Get the bounding box of this surface. BoundingBox bounding_box() const; + + void to_hdf5(hid_t group_id) const; }; #endif //============================================================================== diff --git a/src/cad.cpp b/src/cad.cpp index a3d1c7648..ef937a346 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -2,7 +2,7 @@ #ifdef CAD #include "cad.h" -#include "error.h" +#include "openmc/error.h" #include #include @@ -59,25 +59,25 @@ void load_cad_geometry_c() c->fill_ = openmc::C_NONE; - openmc::global_cells.push_back(c); + openmc::cells.push_back(c); openmc::cell_map[c->id_] = c->id_; // Populate the Universe vector and dict auto it = openmc::universe_map.find(cad_univ_id); if (it == openmc::universe_map.end()) { - openmc::global_universes.push_back(new openmc::Universe()); - openmc::global_universes.back()-> id = cad_univ_id; - openmc::global_universes.back()->cells.push_back(i); - openmc::universe_map[cad_univ_id] = openmc::global_universes.size() - 1; + openmc::universes.push_back(new openmc::Universe()); + openmc::universes.back()-> id_ = cad_univ_id; + openmc::universes.back()->cells_.push_back(i); + openmc::universe_map[cad_univ_id] = openmc::universes.size() - 1; } else { - openmc::global_universes[it->second]->cells.push_back(i); + openmc::universes[it->second]->cells_.push_back(i); } if(DAGMC->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now - c->material.push_back(openmc::MATERIAL_VOID); + c->material_.push_back(openmc::MATERIAL_VOID); continue; } @@ -88,21 +88,21 @@ void load_cad_geometry_c() TOLOWER(mat_value); if(mat_value == "void") { - c->material.push_back(openmc::MATERIAL_VOID); + c->material_.push_back(openmc::MATERIAL_VOID); } else { - c->material.push_back(std::stoi(mat_value)); + c->material_.push_back(std::stoi(mat_value)); } } else { std::cout << "Warning: volume without material found!" << std::endl; - c->material.push_back(openmc::MATERIAL_VOID); + c->material_.push_back(openmc::MATERIAL_VOID); } } // initialize surface objects openmc::n_surfaces = DAGMC->num_entities(2); - openmc::global_surfaces.resize(openmc::n_surfaces); + openmc::surfaces.resize(openmc::n_surfaces); for(int i = 0; i < openmc::n_surfaces; i++) { @@ -110,7 +110,7 @@ void load_cad_geometry_c() // set cell ids using global IDs openmc::CADSurface* s = new openmc::CADSurface(); - s->id = DAGMC->id_by_index(2, i+1); + s->id_ = DAGMC->id_by_index(2, i+1); s->dagmc_ptr = DAGMC; if(DAGMC->has_prop(surf_handle, "boundary")) { @@ -120,32 +120,32 @@ void load_cad_geometry_c() TOLOWER(bc_value); if(bc_value == "transmit" || bc_value == "transmission") { - s->bc = openmc::BC_TRANSMIT; + s->bc_ = openmc::BC_TRANSMIT; } else if(bc_value == "vacuum") { - s->bc = openmc::BC_VACUUM; + s->bc_ = openmc::BC_VACUUM; } else if(bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { - s->bc = openmc::BC_REFLECT; + s->bc_ = openmc::BC_REFLECT; } else if(bc_value == "periodic") { openmc::fatal_error("Periodic boundary condition not supported in CAD."); } else { std::stringstream err_msg; - err_msg << "Unknown boundary condition \"" << s->bc - << "\" specified on surface " << s->id; + err_msg << "Unknown boundary condition \"" << s->bc_ + << "\" specified on surface " << s->id_; openmc::fatal_error(err_msg); } } // if no BC property is found, set to transmit else { - s->bc = openmc::BC_TRANSMIT; + s->bc_ = openmc::BC_TRANSMIT; } // add to global array and map - openmc::global_surfaces[i] = s; - openmc::surface_map[s->id] = s->id; + openmc::surfaces[i] = s; + openmc::surface_map[s->id_] = s->id_; } return; diff --git a/src/cad.h b/src/cad.h index 8f14d2530..1a1663cdb 100644 --- a/src/cad.h +++ b/src/cad.h @@ -5,8 +5,8 @@ #define CAD_H #include "DagMC.hpp" -#include "cell.h" -#include "surface.h" +#include "openmc/cell.h" +#include "openmc/surface.h" extern moab::DagMC* DAGMC; diff --git a/src/cell.cpp b/src/cell.cpp index 01f4eb6d4..047798a24 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -599,7 +599,7 @@ CADCell::CADCell() : Cell{} {}; std::pair CADCell::distance(Position p, Direction u, int32_t on_surface) const { - moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); + moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); moab::EntityHandle hit_surf; double dist; dagmc_ptr->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); @@ -620,7 +620,7 @@ std::pair CADCell::distance(Position p, Direction u, int32_t on bool CADCell::contains(Position p, Direction u, int32_t on_surface) const { - moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id); + moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); int result = 0; dagmc_ptr->point_in_volume(vol, p.xyz, result, u.xyz); @@ -772,8 +772,8 @@ extern "C" { #ifdef CAD int32_t next_cell(CADCell* cur_cell, CADSurface *surf_xed ) { - moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id); - moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id); + moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id_); + moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id_); moab::EntityHandle new_vol; cur_cell->dagmc_ptr->next_vol(surf, vol, new_vol); diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 3875bc80a..d3531cbe5 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -219,17 +219,6 @@ contains ! Get proper XMLNode type given pointer root % ptr = root_ptr - ! Check for use of CAD geometry - if (check_for_node(root, "dagmc")) then -#ifdef CAD - call get_node_value_bool(root, "dagmc", dagmc) -#else - if (dagmc) then - call fatal_error("CAD mode unsupported for this build of OpenMC") - end if -#endif - end if - if (run_mode == MODE_EIGENVALUE) then ! Preallocate space for keff and entropy by generation call k_generation % reserve(n_max_batches*gen_per_batch) @@ -597,10 +586,10 @@ contains do i = 1, n_cells c => cells(i) ! additional metadata spoofing - allocate(c % sqrtKT(1)) - c % sqrtkT(1) = -1.0 ! rely on temps from elsewhere +! allocate(c % sqrtKT(1)) +! c % sqrtkT(1) = -1.0 ! rely on temps from elsewhere univ_id = c % universe() - if (.not. allocated(c%region)) allocate(c%region(0)) +! if (.not. allocated(c%region)) allocate(c%region(0)) if (.not. cells_in_univ_dict % has(univ_id)) then n_universes = n_universes + 1 @@ -615,30 +604,30 @@ contains ! ========================================================================== ! SETUP UNIVERSES - + ! Allocate universes, universe cell arrays, and assign base universe - allocate(universes(n_universes)) - do i = 1, n_universes - associate (u => universes(i)) - u % id = univ_ids % data(i) - ! Allocate cell list - n_cells_in_univ = cells_in_univ_dict % get(u % id) - allocate(u % cells(n_cells_in_univ)) - u % cells(:) = 0 - end associate - end do + ! allocate(universes(n_universes)) + ! do i = 1, n_universes + ! associate (u => universes(i)) + ! u % id = univ_ids % data(i) + ! ! Allocate cell list + ! n_cells_in_univ = cells_in_univ_dict % get(u % id) + ! allocate(u % cells(n_cells_in_univ)) + ! u % cells(:) = 0 + ! end associate + ! end do - root_universe = 0 + 1 + root_universe = find_root_universe() - do i = 1, n_cells - ! Get index in universes array - j = universe_dict % get(cells(i) % universe()) - ! Set the first zero entry in the universe cells array to the index in the - ! global cells array - associate (u => universes(j)) - u % cells(find(u % cells, 0)) = i - end associate - end do + ! do i = 1, n_cells + ! ! Get index in universes array + ! j = universe_dict % get(cells(i) % universe()) + ! ! Set the first zero entry in the universe cells array to the index in the + ! ! global cells array + ! associate (u => universes(j)) + ! u % cells(find(u % cells, 0)) = i + ! end associate + ! end do ! Clear dictionary call cells_in_univ_dict%clear() diff --git a/src/settings.F90 b/src/settings.F90 index 66af618f7..6625ccef0 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -81,7 +81,7 @@ module settings integer(C_INT), bind(C) :: run_mode ! flag for use of CAD geometry - logical, bind(C) :: dagmc = .false. + logical(C_BOOL), bind(C) :: dagmc ! Restart run logical(C_BOOL), bind(C) :: restart_run diff --git a/src/settings.cpp b/src/settings.cpp index 007c515b0..60a805a01 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -56,7 +56,8 @@ bool ufs_on {false}; bool urr_ptables_on {true}; bool write_all_tracks {false}; bool write_initial_source {false}; - +bool dagmc {false}; + std::string path_cross_sections; std::string path_input; std::string path_multipole; @@ -207,6 +208,17 @@ void read_settings_xml() verbosity = std::stoi(get_node_value(root, "verbosity")); } + // DAGMC geometry check + if (check_for_node(root, "dagmc")) { + dagmc = get_node_value_bool(root, "dagmc"); + } + +#ifndef CAD + if (dagmc) { + fatal_error("CAD mode unsupported for this build of OpenMC"); + } +#endif + // To this point, we haven't displayed any output since we didn't know what // the verbosity is. Now that we checked for it, show the title if necessary if (openmc_master) { diff --git a/src/summary.cpp b/src/summary.cpp index c371eb56c..67a9a7f07 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -2,7 +2,7 @@ #include "openmc/hdf5_interface.h" #include "openmc/lattice.h" #include "openmc/surface.h" - +#include "openmc/settings.h" namespace openmc { @@ -10,7 +10,7 @@ extern "C" void write_geometry(hid_t file_id) { #ifdef CAD - if (dagmc) { + if (settings::dagmc) { return; } #endif diff --git a/src/surface.cpp b/src/surface.cpp index aee21287e..b95339386 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -257,7 +257,7 @@ double CADSurface::evaluate(Position r) const } double CADSurface::distance(Position p, Direction u, bool coincident) const { - moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); + moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); moab::EntityHandle hit_surf; double dist; dagmc_ptr->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); @@ -267,17 +267,19 @@ double CADSurface::distance(Position p, Direction u, bool coincident) const { Direction CADSurface::normal(Position p) const { Direction u; - moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); + moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); dagmc_ptr->get_angle(surf, p.xyz, u.xyz); return u; } BoundingBox CADSurface::bounding_box() const { - moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id); + moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); double min[3], max[3]; dagmc_ptr->getobb(surf, min, max); return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); } + +void CADSurface::to_hdf5(hid_t group_id) const {} #endif //============================================================================== // PeriodicSurface implementation From 7b453312c329da86e202221859636ca77ff3f026 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:01:11 -0500 Subject: [PATCH 063/175] Replacing the next_cell call in tracking. Moving it to geometry.cpp was a mistake. --- src/geometry.cpp | 20 -------------------- src/tracking.F90 | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/geometry.cpp b/src/geometry.cpp index 2dca114cf..ccfb1ac25 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -55,26 +55,6 @@ find_cell(Particle* p, int search_surf) { for (int i = p->n_coord; i < MAX_COORD; i++) { p->coord[i].reset(); } - -#ifdef CAD - // if (dagmc) then - // i_cell = next_cell(cells(p % last_cell(1)), surfaces(ABS(p % surface))) - // p % last_material = p % material - // p % last_sqrtKT = p % sqrtKT - // p % coord(1) % cell = i_cell - // p % cell_instance = 1 - // p % material = cells(i_cell) % material(1) - // p % sqrtKT = cells(i_cell) % sqrtKT(1) - - // ! Show cell information on trace - // if (verbosity >= 10 .or. trace) then - // call write_message(" Entering cell " // trim(to_str(& - // cells(i_cell) % id()))) - // end if - - // return - // end if -#endif // Determine universe (if not yet set, use root universe) int i_universe = p->coord[p->n_coord-1].universe; diff --git a/src/tracking.F90 b/src/tracking.F90 index 5e1e019a8..b5282d209 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -318,6 +318,7 @@ contains class(Surface), pointer :: surf class(Surface), pointer :: surf2 ! periodic partner surface + i_surface = abs(p % surface) surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then @@ -471,6 +472,21 @@ contains ! ========================================================================== ! SEARCH NEIGHBOR LISTS FOR NEXT CELL +#ifdef CAD + if (dagmc) then + i_cell = next_cell(cells(p % last_cell(1) + 1), surfaces(ABS(p % surface))) + ! save material and temp + p % last_material = p % material + p % last_sqrtkT = p % sqrtKT + ! set new cell value + p % coord(1) % cell = i_cell-1 ! decrement for C++ indexing + p % cell_instance = 1 + p % material = cells(i_cell) % material(1) + p % sqrtKT = cells(i_cell) % sqrtKT(1) + return + end if +#endif + call find_cell(p, found, p % surface) if (found) return From 5ac964a73f07505b754eb51aff915ada064e714e Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:01:37 -0500 Subject: [PATCH 064/175] Removing duplicate material setup in cad initialization. --- src/cad.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index ef937a346..f67f271a0 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -43,21 +43,8 @@ void load_cad_geometry_c() openmc::CADCell* c = new openmc::CADCell(); c->id_ = DAGMC->id_by_index(3, i+1); c->dagmc_ptr = DAGMC; - c->universe_ = cad_univ_id; // set to zero for now - - if(DAGMC->has_prop(vol_handle, "mat")){ - std::string mat_value; - - rval = DAGMC->prop_value(vol_handle, "mat", mat_value); - MB_CHK_ERR_CONT(rval); - int mat_id = std::stoi(mat_value); - c->material_.push_back(mat_id); - } - else { - c->material_.push_back(40); // TO-DO: add void material here - } - - c->fill_ = openmc::C_NONE; + c->universe_ = cad_univ_id; // set to zero for now + c->fill_ = openmc::C_NONE; // no fill, single universe openmc::cells.push_back(c); openmc::cell_map[c->id_] = c->id_; @@ -74,7 +61,6 @@ void load_cad_geometry_c() openmc::universes[it->second]->cells_.push_back(i); } - if(DAGMC->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now c->material_.push_back(openmc::MATERIAL_VOID); From 1f447675f1a25907f4766e32d25d3cd9bfe11f2c Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:02:45 -0500 Subject: [PATCH 065/175] Removing ldflags argument from libopenmc link cmd in CMake file. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a5a187dba..bc510946a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -500,7 +500,7 @@ target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml #=============================================================================== add_executable(openmc src/main.cpp) target_compile_options(openmc PRIVATE ${cxxflags}) -target_link_libraries(openmc ${ldflags} libopenmc ${DAGMC_LIBRARIES}) +target_link_libraries(openmc libopenmc ${DAGMC_LIBRARIES}) #=============================================================================== # Python package From f8d4d56aa806cb80bb5e15d8c840236229524ff3 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:11:48 -0500 Subject: [PATCH 066/175] Removing unecessary inline. --- include/openmc/cell.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index d69547721..1a549e449 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -111,7 +111,7 @@ public: std::vector offset_; //!< Distribcell offset table explicit Cell(pugi::xml_node cell_node); - inline Cell() {}; + Cell() {}; //! Determine if a cell contains the particle at a given location. //! From 5ed66df7fd9105c8d22946ac7527481bd8f451da Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:15:13 -0500 Subject: [PATCH 067/175] Replacing missing doc string --- include/openmc/cell.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 1a549e449..37bed7975 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -135,6 +135,7 @@ public: virtual bool contains(Position p, Direction u, int32_t on_surface) const = 0; + //! Find the oncoming boundary of this cell. virtual std::pair distance(Position p, Direction u, int32_t on_surface) const = 0; From 28fcf15459c561e3fe47738786d25ec687db5b7d Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:25:55 -0500 Subject: [PATCH 068/175] Removing superfluous include dir. --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc510946a..cbbe045c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,8 +9,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Set module path set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) -# Make sure Fortran module directory is included when building -include_directories(${CMAKE_BINARY_DIR}/include) #=============================================================================== # Command line options #=============================================================================== From 86766dbfdd6c041b4389e929462da23cad6893e9 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:34:47 -0500 Subject: [PATCH 069/175] Updating documentation on contains. --- include/openmc/cell.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 37bed7975..880b1c3dc 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -112,8 +112,9 @@ public: explicit Cell(pugi::xml_node cell_node); Cell() {}; - - //! Determine if a cell contains the particle at a given location. + + + //! \brief Determine if a cell contains the particle at a given location. //! //! The bounds of the cell are detemined by a logical expression involving //! surface half-spaces. At initialization, the expression was converted @@ -126,10 +127,10 @@ public: //! provides a performance benefit for the common case. In //! contains_complex, we evaluate the RPN expression using a stack, similar to //! how a RPN calculator would work. - //! @param xyz[3] The 3D Cartesian coordinate to check. - //! @param uvw[3] A direction used to "break ties" the coordinates are very + //! \param r The 3D Cartesian coordinate to check. + //! \param u A direction used to "break ties" the coordinates are very //! close to a surface. - //! @param on_surface The signed index of a surface that the coordinate is + //! \param on_surface The signed index of a surface that the coordinate is //! known to be on. This index takes precedence over surface sense //! calculations. virtual bool From c9ff5f1530f571714bd3ad1eb0cd967947d7ee95 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:36:34 -0500 Subject: [PATCH 070/175] Removing duplicate documentation in CSGCell. --- include/openmc/cell.h | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 880b1c3dc..1f3bbe7a4 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -154,35 +154,12 @@ public: explicit CSGCell(pugi::xml_node cell_node); - //! \brief Determine if a cell contains the particle at a given location. - //! Determine if a cell contains the particle at a given location. - //! - //! The bounds of the cell are detemined by a logical expression involving - //! surface half-spaces. At initialization, the expression was converted - //! to RPN notation. - //! - //! The function is split into two cases, one for simple cells (those - //! involving only the intersection of half-spaces) and one for complex cells. - //! Simple cells can be evaluated with short circuit evaluation, i.e., as soon - //! as we know that one half-space is not satisfied, we can exit. This - //! provides a performance benefit for the common case. In - //! contains_complex, we evaluate the RPN expression using a stack, similar to - //! how a RPN calculator would work. - //! \param r The 3D Cartesian coordinate to check. - //! \param u A direction used to "break ties" the coordinates are very - //! close to a surface. - //! \param on_surface The signed index of a surface that the coordinate is - //! known to be on. This index takes precedence over surface sense - //! calculations. bool contains(Position r, Direction u, int32_t on_surface) const; - //! Find the oncoming boundary of this cell. std::pair distance(Position r, Direction u, int32_t on_surface) const; - //! \brief Write cell information to an HDF5 group. - //! \param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; protected: From 6d0ba5343664fe064cb205fa68000552b4dad731 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:46:56 -0500 Subject: [PATCH 071/175] Removing necessary constructor for BoundingBox. --- include/openmc/surface.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index f5b30e413..f28ad28b7 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -47,11 +47,11 @@ struct BoundingBox { BoundingBox(double x_min, double x_max, - double y_min, double y_max, - double z_min, double z_max) : + double y_min, double y_max, + double z_min, double z_max) : xmin(x_min), xmax(x_max), - ymin(y_min), ymax(y_max), - zmin(z_min), zmax(z_max) {} + ymin(y_min), ymax(y_max), + zmin(z_min), zmax(z_max) {} double xmin; double xmax; From 4358aac6ca8f4430a90bfa47dd15e5a7eb3f8764 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:55:55 -0500 Subject: [PATCH 072/175] Removing some old commented lines from when I was figuring out the fortran interfacing. --- include/openmc/surface.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index f28ad28b7..7a1181719 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -415,10 +415,6 @@ extern "C" { int surface_bc(Surface* surf); bool surface_sense(Surface* surf, double xyz[3], double uvw[3]); void surface_reflect(Surface* surf, double xyz[3], double uvw[3]); - /* double surface_distance(Surface* surf, double xyz[3], double uvw[3], */ - /* bool coincident); */ - /* void surface_normal(Surface* surf, double xyz[3], double uvw[3]); */ - /* void surface_to_hdf5(CSGSurface* surf, hid_t group); */ int surface_i_periodic(PeriodicSurface* surf); bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], double uvw[3]); From 62c329fcec16060319d44e79704927259ae88ebb Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 16:59:20 -0500 Subject: [PATCH 073/175] Fixing comment formatting. --- src/cell.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cell.cpp b/src/cell.cpp index 047798a24..f0ae46898 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -633,6 +633,8 @@ void CADCell::to_hdf5(hid_t group_id) const { return; } //============================================================================== // Non-method functions +//============================================================================== + extern "C" void read_cells(pugi::xml_node* node) { From ff4d6976825da08dbc1d149c3cd6d62485a4ca69 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 17:00:31 -0500 Subject: [PATCH 074/175] Fix to small change in geometry.cpp to remove diff. --- src/geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry.cpp b/src/geometry.cpp index ccfb1ac25..857dbd32e 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -55,7 +55,7 @@ find_cell(Particle* p, int search_surf) { for (int i = p->n_coord; i < MAX_COORD; i++) { p->coord[i].reset(); } - + // Determine universe (if not yet set, use root universe) int i_universe = p->coord[p->n_coord-1].universe; if (i_universe == C_NONE) { From 6c31843c7b96fb19d5bcbecd5edad970f3ff2575 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 17:02:56 -0500 Subject: [PATCH 075/175] Removing commented loops. They are no longer needed after more geom moved to C++. --- src/input_xml.F90 | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index d3531cbe5..4334bd45b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -586,10 +586,7 @@ contains do i = 1, n_cells c => cells(i) ! additional metadata spoofing -! allocate(c % sqrtKT(1)) -! c % sqrtkT(1) = -1.0 ! rely on temps from elsewhere univ_id = c % universe() -! if (.not. allocated(c%region)) allocate(c%region(0)) if (.not. cells_in_univ_dict % has(univ_id)) then n_universes = n_universes + 1 @@ -600,38 +597,10 @@ contains n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) end if call cells_in_univ_dict % set(univ_id, n_cells_in_univ) - end do - - ! ========================================================================== - ! SETUP UNIVERSES - - ! Allocate universes, universe cell arrays, and assign base universe - ! allocate(universes(n_universes)) - ! do i = 1, n_universes - ! associate (u => universes(i)) - ! u % id = univ_ids % data(i) - ! ! Allocate cell list - ! n_cells_in_univ = cells_in_univ_dict % get(u % id) - ! allocate(u % cells(n_cells_in_univ)) - ! u % cells(:) = 0 - ! end associate - ! end do + end do root_universe = find_root_universe() - ! do i = 1, n_cells - ! ! Get index in universes array - ! j = universe_dict % get(cells(i) % universe()) - ! ! Set the first zero entry in the universe cells array to the index in the - ! ! global cells array - ! associate (u => universes(j)) - ! u % cells(find(u % cells, 0)) = i - ! end associate - ! end do - - ! Clear dictionary - call cells_in_univ_dict%clear() - return end subroutine read_geometry_cad From 9d0846f87f43d6cea397dbdcbd020d1a0fea78b5 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 17:16:35 -0500 Subject: [PATCH 076/175] Removing commented call and duplicate call. --- src/input_xml.F90 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 4334bd45b..d1800cdfc 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -689,8 +689,6 @@ contains call read_cells(root % ptr) -! call allocate_cells() - ! Get pointer to list of XML call get_node_list(root, "cell", node_cell_list) @@ -758,8 +756,6 @@ contains ! Add cell to dictionary call cell_dict % set(c % id(), i) - call cell_dict % set(c % id(), i) - ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the ! specified universe From 5ff3fb7f6217321084322ad1b0538c5539a8d957 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 17:17:02 -0500 Subject: [PATCH 077/175] Removing variable assignment change ro reduce diff. Also it was un-needed. --- src/source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.cpp b/src/source.cpp index f2800c1cc..666bbb783 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -316,7 +316,7 @@ Bank sample_external_source() } // Sample source site from i-th source distribution - Bank site = external_sources[i].sample(); + Bank site {external_sources[i].sample()}; // If running in MG, convert site % E to group if (!settings::run_CE) { From 8f0374d9b69cb8680ae782fdaad86a8e08736107 Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 17:39:55 -0500 Subject: [PATCH 078/175] Less whitespace --- src/summary.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/summary.cpp b/src/summary.cpp index 67a9a7f07..1eeb28185 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -14,7 +14,6 @@ write_geometry(hid_t file_id) { return; } #endif - auto geom_group = create_group(file_id, "geometry"); write_attribute(geom_group, "n_cells", cells.size()); From fa7c0404932ca5561f690f6260c0577b248d565c Mon Sep 17 00:00:00 2001 From: shriwise Date: Thu, 6 Sep 2018 17:54:03 -0500 Subject: [PATCH 079/175] A little more cleanup. --- src/surface.cpp | 1 - src/tracking.F90 | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/surface.cpp b/src/surface.cpp index b95339386..e0dc35227 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -178,7 +178,6 @@ Surface::Surface(pugi::xml_node surf_node) } } - bool Surface::sense(Position r, Direction u) const diff --git a/src/tracking.F90 b/src/tracking.F90 index b5282d209..ceee0b919 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -10,6 +10,7 @@ module tracking #ifdef CAD use geometry, only: next_cell #endif + use material_header, only: materials, Material use message_passing use mgxs_interface From 882c95b77deb8ad247e39dc78126995bbe81f7de Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 07:39:10 -0500 Subject: [PATCH 080/175] Including an alternate value for setting a material void/vacuum. --- src/cad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cad.cpp b/src/cad.cpp index f67f271a0..9ab4e91f9 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -73,7 +73,7 @@ void load_cad_geometry_c() MB_CHK_ERR_CONT(rval); TOLOWER(mat_value); - if(mat_value == "void") { + if(mat_value == "void" || mat_value == "vacuum") { c->material_.push_back(openmc::MATERIAL_VOID); } else { From 467b6a252e42f73f59e93320eed9e392279324e1 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 08:05:50 -0500 Subject: [PATCH 081/175] Corrections after rebase. --- src/input_xml.F90 | 198 ---------------------------------------------- 1 file changed, 198 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index d1800cdfc..695eee02a 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -224,204 +224,6 @@ contains call k_generation % reserve(n_max_batches*gen_per_batch) end if - ! Check run mode if it hasn't been set from the command line - if (run_mode == NONE) then - if (check_for_node(root, "run_mode")) then - call get_node_value(root, "run_mode", temp_str) - select case (to_lower(temp_str)) - case ("eigenvalue") - run_mode = MODE_EIGENVALUE - case ("fixed source") - run_mode = MODE_FIXEDSOURCE - case ("plot") - run_mode = MODE_PLOTTING - case ("particle restart") - run_mode = MODE_PARTICLE - case ("volume") - run_mode = MODE_VOLUME - case default - call fatal_error("Unrecognized run mode: " // & - trim(temp_str) // ".") - end select - - ! Assume XML specifics , , etc. directly - node_mode = root - else - call warning(" should be specified.") - - ! Make sure that either eigenvalue or fixed source was specified - node_mode = root % child("eigenvalue") - if (node_mode % associated()) then - if (run_mode == NONE) run_mode = MODE_EIGENVALUE - else - node_mode = root % child("fixed_source") - if (node_mode % associated()) then - if (run_mode == NONE) run_mode = MODE_FIXEDSOURCE - else - call fatal_error(" or not specified.") - end if - end if - end if - end if - - if (run_mode == MODE_EIGENVALUE .or. run_mode == MODE_FIXEDSOURCE) then - ! Read run parameters - call get_run_parameters(node_mode) - - ! Check number of active batches, inactive batches, and particles - if (n_batches <= n_inactive) then - call fatal_error("Number of active batches must be greater than zero.") - elseif (n_inactive < 0) then - call fatal_error("Number of inactive batches must be non-negative.") - elseif (n_particles <= 0) then - call fatal_error("Number of particles must be greater than zero.") - end if - end if - - ! Copy random number seed if specified - if (check_for_node(root, "seed")) then - call get_node_value(root, "seed", seed) - call openmc_set_seed(seed) - end if - - ! Check for electron treatment - if (check_for_node(root, "electron_treatment")) then - call get_node_value(root, "electron_treatment", temp_str) - select case (to_lower(temp_str)) - case ("led") - electron_treatment = ELECTRON_LED - case ("ttb") - electron_treatment = ELECTRON_TTB - case default - call fatal_error("Unrecognized electron treatment: " // & - trim(temp_str) // ".") - end select - end if - - ! Check for photon transport - if (check_for_node(root, "photon_transport")) then - call get_node_value(root, "photon_transport", photon_transport) - - if (.not. run_CE .and. photon_transport) then - call fatal_error("Photon transport is not currently supported & - &in Multi-group mode") - end if - end if - - ! Number of bins for logarithmic grid - if (check_for_node(root, "log_grid_bins")) then - call get_node_value(root, "log_grid_bins", n_log_bins) - if (n_log_bins < 1) then - call fatal_error("Number of bins for logarithmic grid must be & - &greater than zero.") - end if - else - n_log_bins = 8000 - end if - - ! Number of OpenMP threads - if (check_for_node(root, "threads")) then -#ifdef _OPENMP - if (n_threads == NONE) then - call get_node_value(root, "threads", n_threads) - if (n_threads < 1) then - call fatal_error("Invalid number of threads: " // to_str(n_threads)) - end if - call omp_set_num_threads(n_threads) - end if -#else - if (master) call warning("Ignoring number of threads.") -#endif - end if - - ! ========================================================================== - ! EXTERNAL SOURCE - - ! Get point to list of elements and make sure there is at least one - call get_node_list(root, "source", node_source_list) - n = size(node_source_list) - - if (n == 0) then - ! Default source is isotropic point source at origin with Watt spectrum - allocate(external_source(1)) - external_source % particle = NEUTRON - external_source % strength = ONE - - allocate(SpatialPoint :: external_source(1) % space) - select type (space => external_source(1) % space) - type is (SpatialPoint) - space % xyz(:) = [ZERO, ZERO, ZERO] - end select - - allocate(Isotropic :: external_source(1) % angle) - external_source(1) % angle % reference_uvw(:) = [ZERO, ZERO, ONE] - - allocate(Watt :: external_source(1) % energy) - select type(energy => external_source(1) % energy) - type is (Watt) - energy % a = 0.988e6_8 - energy % b = 2.249e-6_8 - end select - else - ! Allocate array for sources - allocate(external_source(n)) - end if - - ! Check if we want to write out source - if (check_for_node(root, "write_initial_source")) then - call get_node_value(root, "write_initial_source", write_initial_source) - end if - - ! Read each source - do i = 1, n - call external_source(i) % from_xml(node_source_list(i), path_source) - end do - - ! Survival biasing - if (check_for_node(root, "survival_biasing")) then - call get_node_value(root, "survival_biasing", survival_biasing) - end if - - ! Probability tables - if (check_for_node(root, "ptables")) then - call get_node_value(root, "ptables", urr_ptables_on) - end if - - ! Cutoffs - if (check_for_node(root, "cutoff")) then - node_cutoff = root % child("cutoff") - if (check_for_node(node_cutoff, "weight")) then - call get_node_value(node_cutoff, "weight", weight_cutoff) - end if - if (check_for_node(node_cutoff, "weight_avg")) then - call get_node_value(node_cutoff, "weight_avg", weight_survive) - end if - if (check_for_node(node_cutoff, "energy_neutron")) then - call get_node_value(node_cutoff, "energy_neutron", energy_cutoff(1)) - elseif (check_for_node(node_cutoff, "energy")) then - call warning("The use of an cutoff is deprecated and should & - &be replaced by .") - call get_node_value(node_cutoff, "energy", energy_cutoff(1)) - end if - if (check_for_node(node_cutoff, "energy_photon")) then - call get_node_value(node_cutoff, "energy_photon", energy_cutoff(2)) - end if - if (check_for_node(node_cutoff, "energy_electron")) then - call get_node_value(node_cutoff, "energy_electron", energy_cutoff(3)) - end if - if (check_for_node(node_cutoff, "energy_positron")) then - call get_node_value(node_cutoff, "energy_positron", energy_cutoff(4)) - end if - end if - - ! Particle trace - if (check_for_node(root, "trace")) then - call get_node_array(root, "trace", temp_int_array3) - trace_batch = temp_int_array3(1) - trace_gen = temp_int_array3(2) - trace_particle = int(temp_int_array3(3), 8) - end if - ! Particle tracks if (check_for_node(root, "track")) then ! Make sure that there are three values per particle From bd791ca2569f9d82ff1c2bf66f9854f3eed6699c Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 14:10:42 -0500 Subject: [PATCH 082/175] Fortran style fixes. --- src/input_xml.F90 | 12 ++++++------ src/tracking.F90 | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 695eee02a..eef112b3a 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -389,14 +389,14 @@ contains c => cells(i) ! additional metadata spoofing univ_id = c % universe() - + if (.not. cells_in_univ_dict % has(univ_id)) then - n_universes = n_universes + 1 - n_cells_in_univ = 1 - call universe_dict % set(univ_id, n_universes) - call univ_ids % push_back(univ_id) + n_universes = n_universes + 1 + n_cells_in_univ = 1 + call universe_dict % set(univ_id, n_universes) + call univ_ids % push_back(univ_id) else - n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) + n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) end if call cells_in_univ_dict % set(univ_id, n_cells_in_univ) end do diff --git a/src/tracking.F90 b/src/tracking.F90 index ceee0b919..84ab56cf6 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -319,7 +319,7 @@ contains class(Surface), pointer :: surf class(Surface), pointer :: surf2 ! periodic partner surface - + i_surface = abs(p % surface) surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then @@ -475,16 +475,16 @@ contains #ifdef CAD if (dagmc) then - i_cell = next_cell(cells(p % last_cell(1) + 1), surfaces(ABS(p % surface))) - ! save material and temp - p % last_material = p % material - p % last_sqrtkT = p % sqrtKT - ! set new cell value - p % coord(1) % cell = i_cell-1 ! decrement for C++ indexing - p % cell_instance = 1 - p % material = cells(i_cell) % material(1) - p % sqrtKT = cells(i_cell) % sqrtKT(1) - return + i_cell = next_cell(cells(p % last_cell(1) + 1), surfaces(ABS(p % surface))) + ! save material and temp + p % last_material = p % material + p % last_sqrtkT = p % sqrtKT + ! set new cell value + p % coord(1) % cell = i_cell-1 ! decrement for C++ indexing + p % cell_instance = 1 + p % material = cells(i_cell) % material(1) + p % sqrtKT = cells(i_cell) % sqrtKT(1) + return end if #endif From 1fb69d0dc95e1fb79e44e3ba7a0ca0c2d5464394 Mon Sep 17 00:00:00 2001 From: shriwise Date: Fri, 7 Sep 2018 17:56:32 -0500 Subject: [PATCH 083/175] Adding a simple CAD-based gometry unit test. --- tests/unit_tests/cad/dagmc.h5m | Bin 0 -> 1233192 bytes tests/unit_tests/cad/materials.xml | 16 +++++++++++++++ tests/unit_tests/cad/settings.xml | 16 +++++++++++++++ tests/unit_tests/cad/tallies.xml | 31 +++++++++++++++++++++++++++++ tests/unit_tests/cad/test_cad.py | 10 ++++++++++ 5 files changed, 73 insertions(+) create mode 100644 tests/unit_tests/cad/dagmc.h5m create mode 100644 tests/unit_tests/cad/materials.xml create mode 100644 tests/unit_tests/cad/settings.xml create mode 100644 tests/unit_tests/cad/tallies.xml create mode 100644 tests/unit_tests/cad/test_cad.py diff --git a/tests/unit_tests/cad/dagmc.h5m b/tests/unit_tests/cad/dagmc.h5m new file mode 100644 index 0000000000000000000000000000000000000000..63a29ee62b5134745be52c1b07d6e3199265a11b GIT binary patch literal 1233192 zcmeF430#cZ|Hr3QQfbv*Gu4ogBzw$3QKXWntSzEQp%7V;rIek>zLPzB)_LraC0lk9 zin4@Ig#S$EobNGnZ`Zx|cYnYCy>4?~w`ZRBoO$MX&U2n~zUTY>evTP#E}b;hP1JeP zmzo++nWtU(mj3xhUba_sD-qqNp9hjR3S^r^w&{xajRH^lACG55xDGkKd^ukqS67~- zBt1UelCSadRPZ}B3aYpNsv2-}ZSO6;V1IJew3TL&c19~BCORfY`kuB&H~PV!+$!*t zWZJJbX}|HN_<)rsC3*X!_WP_RE??b#|KyGMhks4J{nB=sMEW&)c`-qQqowadBSMFT zM#faWm+nVK4Gfj;M2BJ~{XAyu@Jc5AJS;pqCTiqZX!rE_=;7(*BJF``yW=ZKOMmx# zko_>Z^T4I5|I!+$Y8>;fflCZ0&o}M|l&T!Z+&bg(N#ww8tMD7z9-d9Y`?Q}U#i}e9?}?`*eKKBu}tchYpn=C`c@|@9ir3z4(#%dx3ZZe{nyc z3f7%NE&LH3C;iEOtS06TK+ka@J|&`Jfl!I&g5Pqh!Z-WO!34qwO3?cmBkys`e}Y9R8^NI@G~GPVI{7_WLJp z#y|Kg^6i&TuEn2rXk?$-vmsGYBL{{@2E`DImA2!Sf3Oa!YQOU1!;ji;OB4LV)$R8W z-hiK^xP1FX`10)w0+Zl zogTHS_M1k2H`4%@{89V$4#wrG+b^xzf7e#N{nB=Ji?knF8=XD8I<)r~;O;^IZI_4^ z_=8(Kk5GhpL`I|EJ^*c>!%6$5zc1h3fBPsu-=|ge1FH@3wQ|OI`=frqKOC2%^;~U- z{d{fZx2~wFejtyuANt+@PCuZ+vn4+ehTRhM=YFxJ{gZ$DUwkA3sQKuIWbiL`sNERb z@fRP-0Qy|SlIM!{Kl0C+%$NR$J2W2VCg+FM;5k&Dg#xbzPebDE7#0*eAbcRNvfstm zgvjUkWLFSBqO@O;9x5JV$@^HI)U|6QiSS9UU0T1m4%B$kxuvw2WNsc5qZA&o{KvE}-Nt?Z?)C|dt?+s&)J%o9DgwzPEhtGWiNYoNLYs%xOS2C8eIx(2Fipt=UCYoNLY zs%xOS2C8e|e^CQce^BL|pG^D}hzCwV5res2_$=r=Uw)tZS9JIy;u}Cbr&>IxZ{!Qi zzk(0Q{3~I5@R8$3k(8UtU3veC1`m7Y6nHf&{Z`R2K_g=-Jy-bK+7gEZ_DP^hK>ZhV z%L9)hF8`yyRpsaAG{@g`BM11AA3doVE=c_))qeCJ)%?%(xx62pPcF}v z=lr~?cv^`xc}nuqCeQbe`hoO;xIDcd)%^gjkAKTw`F_BNT(|>iKeQhHJMlCYS2t=w zf9cn^w0&lg_D%Z%`S$+n-~M?iji<@?n;OKfP*l+5sY@&nqOTYr)lf)+Ni@xwR-+_3 z_1ktjT>PiXg5=L%WnaxBb|H_%6~F(D z-}AmIJFBD}{;vsK_yinC zyZll6u()Rg`JXdsJlW*_8{_UTa zQu{!DzVrv}1Br9wx9tOcgzJ#{VdVG!xP1_2jU|S83aa1Tp1;aIXf=Qy)PcVFL)#zK zM|W~GnqMNn5A`8wxVY`2%5PL{FD2PaZ7Uv+kJm1!e9z>#qXux9ejTIWfBZXnSc)z6& z-rgeR$~MTB<8Q?KC>?K~k#ZT^WXs(m`(-;YCqK`#ogiDzo9qvtgn1I)@EoSemh&h3 zv5BO>U%a8ueOMQKV0ylqB;mDNdtX-{cZs54oHdOv8Mv{B`!JV~Ckc4bbi{P*yEW$R~@xsfkaZ~jmXP`f+B1%EAvJde!oR;%>O z4GbL=G%6xS;*z5^P4Ad=MJVb0wyivXqC$7t#f`KhS`B~oxI+8GSTat?_lKUYJ-fB{^rYS4|GYm` zBhLlB{_5@Ts{z^{s&&QXZAm*~{hNG$NNf6c_J_Y-yvqJCgV-Ctw?9NZ@OfAFhrjQB z|7@kI>JR-%JEGV7-|7#ODy=`J=A!nYi@T3|M>h{wU(zG~ukAx4@?6mCuipN?8le55 z{QRft{*c!6@9YnMy?B-VA?JtB`}g*T-u}2eoljKThrjQ>|172C`$ImturSh&=ylTm zFnr*E$|Xfc2StpME{Q{1aZ6h8cW$YDm==J)Aa5UbcJ=Buz{S0rt7i{)FNv-8pY(^) z`7~|czdc`;eu`h(y~&#@Hq?Hw^{=7;!Sr|e5(V$S;YIsH+n)Gp-AFsCx<8~fNL$hm z=F7icT+$AI+fPrYJ9PWU{q*T%slPCqI#YRp|5QIctp~c5)`v9ar>ICP7~j9D<5=2l z@U!AXZ`|L!K7QSwQqmt^=kFaa;|JjK^!cwIFL8bRTmH(Amvp>HBkhRR1065v!{J6h z_>)^YUSsVlv^+9kB*nLQ@b>dOt*i$T}>UQQ+bA~Nd_-I-G55EN(=dqs`p>}xnx{s$f4p7U z9K`L)8|Jjq%KoRctCG-vZPWOVF8oLBist*#?H_MfF$Z-k&rtHuS$y~Ur?e|KIx+h0 z+^gUIxCRs?SsBtBPVH!Fzt6?Vu%H(HQT%>&B>t`H`R0%7{AVmt)qGQJnC#X5x8|Gv z^YHJalb@sUs!IQC4~ciyb%3Mvqdz*|q@AI3zA2r1+LGfd@%WYbOm>oe>HI-jj?PV` z`}jFPl6SH%I*-a4g88!uy#1r+MSqLxZXC$ZC`ryxMe<&HUh$IurRRm`H$2|2tw|t1 zp9mz+vE*yjuRl-&Kk6UVq)Bs<7wu=O{c*TH{w;sy`$s;xaNCixH9-5vzbbx3`cps}#Sy@zS^S z<6ms49g!zjKk^0X?*@*N|K#V~|Is{v>Y>>7kLsi|59wA`9j#ehkAK&Bz@MoP96yq6 zSylT7b4Yyz$~36IZ+-mwzgy-|xr&P9-!UXt@uTsIBjsr;s2;CmZvRieQ`LBND^~W> z|6Ajgyq<&F^BpDngw9?*Bpc&@KW?eT$zH$w9v!#R$nzurIo+qvmC<-ge(vp$`e|=+ z`E)C_6zJUL`?*xr{j|ejJZ{C)sZr$-|Gxe7Z|8x~dZ1h8&y#IgRo6$xQCuGq8OL|8 zzi)k1F>X!9C;xlLtt?WWK3~=2)^|7mU+}i7aceHo-O(!etH&)ozfmTBA097>=&+=H znDiyD%L=TdJYFX8v(j?%^EBFy^Saz^^$b_ z@6^7dtFOCf=K;Q69@2~W^Yd2h&*PJtkgnS)owxp)k4#!be*UUGg?zD!4cGybt0+J) zy}$gazg_NU`SeG20ByH)`^W8ojI(&$qjvz;+~0TH`)xab)&t#sX9rCFzD-nZ2W0-k z>f_h#fD)pI{=IfUQWCBm`g~Q}0pGWlpZ|STc0ih(uKusK1L*iAuj8lVmoy&b>gy9Q zz{j;m`wl(+-^Q<;8Nb~IXz%Gyo};Qt)8{KMxvCOB7ys{%U)(>ezy7o1mu$YN{H){AbI4^RFJi=+WiZfstPaL0$(e zuY;3cpV6yBhss0Kc%!@@SAJe6KTgW$aeTM$Il$G^m&$@=cxB!P{>0Va*Qfme>90Ff zo(J1+Qn^puDDOHT{CI8d)a_l5jTk^lO9Ca{D z_woHfm0Ys>i`S3r1!*UxK$){l)#b{&u;)`=@lAbz6wfG>o*T z|9qTnS$RMO$(@sq)1!k%h6e>lgbs)ZjT{^k_B+-W{Ox(C1*urN{o~_m);T7(Wh>yXwlnZ}u0sCxL&v;^B>6NGbyYukfHskWNf2y{(aDDt+ z{>s~1d~)G|q#eu=t5Xp1@7quRw%>%-1Klz| zfo#jFdfZAQ^?_s>(%-i}etp~;z7wB*7`cic`3ZO#xM20TC3D;VH9J*}TSlZE(TezQ zja%~nF3&H=Egbj%UyoaEyXckw`j(Dcx8&+czBGNV{CCTL@^kM0_s6YU|B`V_wq;d4 zZaw=)ja#_Yw?cATu8Muk<6EN2&)HU<|7f3npO&j?D_@T8SGBF`IF#e>@vO*}M_x`G zegpL&w_g|G&*@($vfqls1h#~mkuCm|$D`$~s^GsU&*5*%9~aJ#9OoDN^n3Jkvj2O9ze19;bCq1@w70<>y*?Xq->yTJ8UOzX71On@TNvh|8x z@_>sP9(S*JFF?D`F4eOBln=c0e)8?&w*u6lLVNp*9Z!Luoxit6^lJfHu(qpX%aCWl z^&O+0%_|n5`r}-mysuLXe5q5H`EG>*lwZ?Pqt5x4z+DAREf(hs(5T4~aW3sjfVZrO z*)-w409l@m9cQ`t4RD?G16?a_3J`bvSfhon-vS@q>YJV3RRQYNQTN2s&ZWQ~J8vC) zB3pnaOglTM!K(MbPrVvdSN*gAxh&7?*6zax;Q67^vx|-j(7@ZRw`F^j0XNUkJ{PiI zfJ!Zn9L!!@4t(+>UB%Hm1SpIjzpHuKC*Y?H77Z3`6rhK5Rjw*`s{pP)P{VG}3IV#^ zwogC%HD7=SpLQPavQU8Z4Z1DaTKW~Z(aZJ=jwB0EzvQgJhpc&swiA*5jE$G#1!$!1 zr@F^4Fy7=q&g*fb1t>Y9W79#S6rlVW*Lquz4;7&08cz>wFjoYwedc+cb%6rpc57IE z+-b%Sg`bGF>?uI+0 z4ZnZ8rGo$|2m8Gk5~u>@4aOwyw6+$Y4mq=Wm8+-%pHftGcZ-1lITv|sud$W!e!T*> zU#cNMlkV?vnD12s$|vb2#LOw@BbV4b>(qCQw~Vx#`m%_RYzmYwYAjZR@|KrIGJ=8WZ|Aw4^& z=Y3_|MbD;K7$*7Mekqq@S7<_cr|G>CO?&atgDr}ELfdEoAHIEs)$Wdbb8i`4n3qw&;7>b)3m7UH9J z?1d$&snq6Xi*<}gznW^;;glsR9tWi={3cC!;yvz0PY3^dRj} zh0zek8xEc4=6k{dos2x*bNpV$Bj?u{{BWTK8sasfaO79U=PjwZJ#&x+nt0`c(&x^4 zaQvM+FV%h2!UCBUX@Aq5$GAbGOHTsSEYPua%^eQjX526&^0W0VbJXw*S5hp{hvTIC zYED6$%+ZLbE6X>BGoI)7X>rCVbF^_q(*-3NjIUlD)q7M&b7Zr5U^DSY#{2F~c{NAd z9GUD~QK;9>0FK}7Y?tv0_svkd7x%PZPGMZA6yG>I-3;}u@!G`w9OL5-Tx#(u+6>L_ z8auMCRvkFbv*>kML))1l^{Zc|Pw`>gN28IktC|@qTl(sJ|3!?~PwY7`?usc|o4Re! z{@aY}emL~3_EJ;iyg2pX3^PMG{^yqI&y<2q(O9J6pWC1D+^w2h{Og;d_$%?6%T_b4 zFCII(c8Lk9`(kXL+((St#px`ozuyEoxvV%d-O31#Z}U1SEIrNyO=+8%yCsq zVYh^-Yx^-iI_SA)3r}OTvBtxW@0K#&TP-izUfUS$uM?-f^Csirs)uhbxMGCn56()w zu4e+rzp-*=LD+mFw7~yczhE!MFAv{Qd#8^Pn$`TgqhB)PZ7mO;9;|DGo|tsox$6|; z6Q0IRTzJJ0joa5Ke)w0$XB(I9Za&u#2^5$0oZrF}es{+*mxo@ShG^My-^T{S8Qfaf zV%yh2k<+&4-tEfxNvBSFpDPT|=jIA3%_cM6%ys1RF9!^eh4+TYXZslcx@Xgfgpmel zLXpLz(&vn?|6C?YZfJl!Opi4RFgJ(ms(9J0xK4pST6=AMeSL4nFOTZ2X}3xrjofl^ zyG;V)o!nA8oc7a4o^y2<&)CCwv+4GBMYZ)&Qbf};?Vm8du$$_jrDyffzIFF3J@hT$ zcO%=ZTY7V%9_pUBedeZ)jJJAV8?~;P9-6YFUAfOl#+w*>&iYoYi?+3}?bU5H;|Z}n z*1TM!i!Qvak(PRq@rR?!1ETzNQFu(^0lQC(kJ>vrY`TUn($opwRjaNgoXF%~>(}PP`Q+@pw$P-gHX7F^tj{7V z#*Y|WF*Wh5jZTAGt{8oH&L=%Bl&~N{V^eR&H!s|= zDu0wFQZ!t)YDom+sx=GySl-k?!ET>+G@QtIO5BA3ds}FrT8a_Z2h3r7`iD_nHY~1% zR12SPbzIH3_}boM??0%cE$J(+t7pW?YkAa>C{AX9hQ&V^N{hfIR}K!k!t96qg>}zuNcqHyyCs)d=2!if73+UFN_b= z(cq7-TLWF*Z>Qo_O91ukI{S0CoXM)F-GLDUb&VN6q34pe=AH_w@cQaIvM%FK_9lqm zHCI8ecdE^ZY|6OqqZWzh=PILwnwtAm5#y)gckQcRq=YWIU!2q0gK-7L_j(2$l~BqF zpQ|@&2N9o}IcXAU8dSP~)+T z59_{oY|>gD;^(~G(PIkZ!Q%riU3>dYH0iz;-*y(`V-{rJzqjhEsJJ9x(xOF-&wY9P zdQ*=tBHf;!Q&+BHyxeu#ki3tdMMrIiHAd--_qA`^yJ+nvQTw?QjN>vGZ)SWlIG|g( zXxMEp8?Q{p(>zCYYWDG?=>EKZR!78)kH1hed)n#`q62frJUf1d@$Gs+2YuY%i*CF) z(=G5K<39QR_t(97Cu(1MvBBbNjOX23sWN%VTTv~=@cx5tGtR3wMd>YiBZ}*J`Q*h1 zjOW}=?fK>MYtf_|3!E=LW?cQK%DR5$FGXX{ZrD2T8RM&4uUn-*q)5~gZ`$C zABt=nV3D7@vB_O@uzx!RofZKg`t+^tO4>{^| z^SkrxA7Od-zUEEw`WNqxdP?T&^nB8~y1Gprdrv%Tdg+dSlKDF2>b(!m?(jBG-1%xv zJ!Q#!opM{pZV`c-9*c)XKls>QGGC{>Vyo8IT73(|ncVnchLZU@<%;jmCpOc5F5W)K zbNbX*jDH;3!TaLLV)2{`Q@pQXGmOV#Oav4_}e5rHtic)dpb)}4?9L8s? z^=?^F`d&OWaYs#y^Nb(cQ!n;a*N@^?$;z+0o@9LFl~>LIYs(XXyx6k4jzhM)GY-8NAseOsX+6u8(my~7|>lk;4DCb*z_#$4? zppIX?WsIjTkJOKH|0Xv07H;rj9^)t1uT@v^a|F53j6d09^XjoOXH|E*&DmCr$89tBy)#3F zb6OKnT+xv6=$Pet?u}Ks34voTU$SI;v`XmZ=GRrZ+Cz7nx7B5QiJfoOs@NLbr=piO zZpw^@a$P#ao2hXT!M&Q7yl3N=$?li8r@>t zKHPTZIc0UO|M7RFOR^YmH=Y~ z_?`2j%py~5Zra;@SBs4pkBymYG$34?6TeJd;;q7Xs}Zki#O&AR9L&!S$;fB+*y31& zGxd~oxEBkiIH?|D{Oi~c3uC=>IK652$FG~q_?=_NGY2ly;XEA^oMsGSJo#J6n4$t5 zt}LjFcV-*LwTE^$Rddwk94HSb!kMln^y7! zGVWd;a5AS@kL!2AMclW7+3llE)dm$b)#rBm?e+Vd&G-keohj4f^tlB6Tbo`iWqh&Q znFTvf=yRfNpDr{BXFPdWY~FyH2Ardc_p|KgjDPC5GdI=CfJ@JKWpPA_@k^&nA9$r2 zaIqcEEm6v0^OxG|L_ss}7;yago2IQ>#<(D1^hI~eI^4>qmU=4&G2YJf+x+PvbvQHC zxuf4WFy7fmS=fG49d32II?vX8V)L@3RvXL56xHG0x+JgLd6Mxq%1X)g8yRxfG)6x& zoyqvALXnSelp!acruC_?2jh;#^R9fzFyuTsHncP_Wn6Vbr{vmi4Y}dkE^F66V)Mz&iDzi0F4MO|ziTpJs6s!jawgdAkN%XHy7K;0)Vajoxnw7gBXa0?Z zb?Ig&TunKD#Ybn)O=4Ux_~R4viKg7Ql|?VPwv6jP@1A{opDFk7gkQ14XXb~g*s&y~ z^o1$+st)RCn#s7jPr%a%Ycno4?o{057{*^e%wE<$z>G6&q-qiB@Ex!5WYmb+W?bo2 z^ZjRwnI9>tMUQr$PndC83A)#|Y-F5UJ@@4O4`$rb9XYDnL5x3bkayG2&Yat?Bq%5| zVZ2xOfbQvi&ABZtSE&uY&iq~DAH1wNd$u`u=X{1*-&u?wS~vXRS+O~HV{6=$+pdg% zt+jlQZ;3g#=fORrM_-s zT*UGD8e$j5T^5vWEp)Kt=AcP?50^7PXNFF=c0nIYE;7RYn%54-rwzGX$9}pccRbzM zazZfU7q1OEcWkF6x7%xZch@?MCv5a@zWA0UH*mZ-{Klc)?r#EG^Eori{J~%9G9Kd^ zz2mJ1pX-!eSZtik{Li&~KCEgufX}6de7iCA1@mLOUB1?*#t6yzbX;(#y(i=2&NLsF zkRUnEIR!`Goy;Hp!DDpliUoWwc|_7Jac#zZt{HamU(e_KuiJYjMKOPS-ry_EckktM z0rPh?-*t)k?PFi0RBSoL=W^>0Yt^n1?(MMU*rECY?zq{R!uESu+(aug zjQg52sAJwyz{L#+4QVu(#b3(aM_g&)CEyObKIjm|u{h4X{W_0d_7-sYlP|cmGiKba z@mE#RAOV;7Hm=#q5sEO6sIU(HY&Sx3{{4?Vo_|gO`0Mir<9EdgxF_9j@c9D9w>e)9 zxH?V1@}p{#yhbw_(+-U28wXak`9nb7JgnNqz25@LkxA#p4!T z5NkOd5^#}QVsGF7$l`i87o6^pcwE5o-yO7DwB{om$6|4~Q*@Sq%ZSL*PV(d0n6f!%EdoJLF^i8Co6@< z&v_}}vU8gpuYdG8@c#KL-T|wT&C-G@3VkAq7>TkM%XRjU%K3UI`NBu z8zy+!<7~xM;QQN5c#`>5z%6_*@l7f}8@SuxeCOnE0&d_!v$5YgallXZbuD@;;d#yX z_piTq!!P){W|dq_+YddCK0Xd``n#_9cY)LMbiwBdoL<*Ld|kk4Jvice08Z;|F0MD= zw4UE~uB>O^^uDCx`vN?H+{Xj>J_4ury%^tj;Iy5z!0iM$ZC8zOy8=$z;U?S;fzx*T z1h-q@xul&(;C2q2J{KGDa{-(_N5=R$0#2X1G5EOyPM_1E_&EhmpX-D8xdu-Afz`Ml z08aZ2KiqEsr~OQG+|K}~{n8cOFLAW}l#qTb5BFohX}_0``#s>apPYjGN#OTMzj`0{ ztH5bLd;s^uz-hld8u#14HAz3e0{8R4>9}wPj|;%*IMN@FBfv#u+{we^4)E<{oSKBk zDd2Qm+knS4;H6|7yoAR=;B?${#N#G#I?i6f<1BDGF89RaGH_oqj`zajIPfwu?oY?# zK5%L$bij53aB5c=VY>o2wL|7&I|MkjTiRp01vs^H46&U9d=9aT_F%gRIJKkpU^@!9 z9kIJ~u-yfGDzVd&v7H8-+I1P&t^=M#>_9QL1A$Y!F#_9-z&jB;b2hd!fm6G52)0Xs zQ#*Ddwqt>N6T7z?wtIn(BzAHzwv&N##IAmT?P}l DH?Qq~c4Q#jX!gf3GBgD?X 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%0A>SC#kk=U>+j zSw06?z#QPe{XhBs|Ln=7n~tyW>-YRyF$XaB>-m8>fVp4)Hp~Ic{r9$H4q)#0r!R8= zbHAUD_VD9Uu9&-S5UvKv_2Z(t- zm&zVu4q)!mdFBA-{=VG79KhV)uU58{_k^er%?}NX;Z!rh(cz@qV zG6yjC{b3L00Or1*^kEKQ?)%UA%mK`OzheJ?{Ca$UYs(zK<9$EOm;;#m{`od@fSBiV z)~s6oejCs4`*RcK03PrA`T6<#c|6|t|Bsjhc)Xt%?=uH5_w!{5a{zNck7_dqF!%H8 zDCPj>e%_tM9Kf93KV$!YX71En{WJFe$Mbmo;~c=_hvvP1_A_$;^ZWAs|Jh*X z0Onqg9l;#H-0L^z0OtSZ`~S0JnFE-6edrv(-0R8l`M#3O{Of%GfA%qR0Q1xG{r}lX z%mK{*%J=_g)AQ@wcpk5ZKgsvS#QeZ~|9{p!zkZIn*W0z219*O~&z%F9dp%#DIe@v> z|2O6Pfa3XGFR*VY=B_WC19%?SBkW6x$Gd(B`T8a1u6LXRcpleBZ!-rlcRl4Cz})p0 z`>^8q>HRb303J{8pE(CGcRlDFz})rYrOW}$>HRb30OqbwodcND`)AGp%w7Mo|35Q# zz3d#o-1W6{0CU&l&H>En{WIqP=JfuVa{%+CAIQw@6PyE>+dnu5Ft@L84q$G-;T*u6 z-am5=U~Yfn9Kf93KXVRXPVb*N2QatKaSmW^|Kl9MoZdfk4q#62Z@-k8Cw)}R>HRb3 z03J{8pE(CGw;yv3U~Zr09Kf93KXVRXPVb*N2Qataa}Ho`ALtyw-2TuxfH}Q?<{ZGB z-am5=U{3F!IR`MO_s^UInA?{+2Qa7i&zu98Cw**Yp7ggdr}xjC19&{Wf94#(oZdfk z4q#62Z~q+6Pw$^O2k?0NZRY^y^#1nY@jUkD&H+50-am5=U~WI}9Kf93KXVRXen{p1 zKQpKI&zu98)B9(y=l2=JHRb30G^-w zE;8=Jh{toEMs_Z90FU?Q>d)ES*MYAK^T+f3|Jlj;{{MLXD*1gT*~y}$G8c>Ga$ z@1Hpb@OVEL{hTys|9{5*|9BpH|Ey|$A70Gq{j(AIeS0y#E5ENV`!T=IFXrt3&zu7k zZTeFdsZRy!X!*=Jy@O^Zdd7gx~V}6l2bPjP7TMIlaI8A7cIo`z4$M6m9xb z7B*kD>AuRWdVZf}Jf7Y^a}MC~Ln`mzh{xBjyx$|{+!yNpkeH8WKZ$by&rk24?VjI< z8jr7EdA~}`7jRvBXuiKC=JfvVhlx48f97>`(WXCTVJ`b^x^&od-)%ge-rxN>F+U>j z{WGuYJ}mTtYeBc z{V5CoW1Vw$zW+ZS{|4(K=Kvl*kabi))>Y=;v+nweb(r}~)@i@x_ie}X4`6@S!u&q( zn4il!a3kwN&oiI>WB2Fxk;mgtXPsF$zwbQeBP#Dti+R(hKW)s9tGxd<=G`jq*Nu7W%KLj`KA`e`;FwRMH~c<- zj!4Xt{l+o>`+-f*C2@ap%ulbppE>5^EAM}f`OTI0OUHbA<^9z$zoqhi?3lN$ynj39 z$$syc_oNqIlRqaW<})krCy#lf%KOh_UN7(c-LD?=Pb=?lk9n`k`{84LLFN7PF+V)- z{oQXL^C^#PdM=Oq^JBh8<^B9IKdkp2gZsVv<*cGje|CuZae41w?i?Wh-^;@559iPQ zaSmXCbmj<@-T0kKdlTk#hj^fy|kl1DM~>T*^6>`9S7a&H>CvGxu^1VBU>6nR5X1 zrTOny`IGr`fHL#>%;7fAp92*0N0{5CzrQCl=W`C=c^WepbPiy?7js1C0OnnpJ1)(i z0~G(>$l4Hd&cve!@iJDlk3B2 z+)tWbPcGxRKk4=7IqXwOuUBVPzP~m8y~``#4;%BI?3+oipOgD-25<33GudjGIG>2sFw+@CM<{r~a&^!~v)fajUTbAJxZ_y5P^ALY3}JLb;;iaEW1 za1P*k=>3Cp0CV@n@*JRe9(w=qTfYB4=JfudHT!Tq550eI4q(0u`+D2w`~Ty4=>5ap z`TqZy)B6YK0G?+&&l~BT@Bfd-)B6YK03J{8ADjc2kKwsLt@Hi=@jOrS+@EeqUwQ)1 zS9v7qSBrS=&yPtT`!LUM>6i4kPx8E%*7@^Z;@{hqec`9EPu#DwC;P}RNc!a6c>c@; z_Mv+`y?<~HVE!`u+9&7Fw~2r6l{^n;Is4*0-sk7snDpoL{=qqb$Cu~(|HHdUKksvY zoCA2g`~IB+nA7_Q=K$t!^L(LnzK}eRDD!xF|KJ?J{F}6&;4-@;CY_r zxj*glpF=#J-rwgn#oYTkoCA2CRy_CTnf!H8IG*SJI0x`}djH@Yz?|McI0rDN_Ycki z%)Rf$Ie@v({bB!qX6|!;oCBD9AC7YXbD!Vk9KhV?{x}CPr}q!e0nF+BgL43L?>ll1 zVD58&oCBEq+#lxv=Jfu-Ie@v({o(m(nYs5_IR`NJzAWbe=Jfu-Ie@v({c#RpPVXO_ z1DMnM2j>9hKKI8tfVuarIR`MO_Ycki%)KwpIe@v({c#RpPVXO_1DMnM2j>9h^!~v) zfVt28aSmYabAOxznA7_Q=K$vP{=qqbxzGJ^4q)zmk0ZGc(wyEuI0rE2x++v<4q)zc zf1CrDH{|(^&H>E5&(k@8x%Y)S2Qa7i56%J1>HWj0+=puJeX7m@%<27ua{zPigWVG`gi z$J6@<=K$vS@%&il0Os`m!8w5WJv^WGx@3PEy?<~H;PI?`gL43LdjH@Yz?|McI0rCi z9Ufjv_T$m}hu+ElJ$nD(9KiF?`-h8|1DMkzgrAfBg!KO5o@D=_&ncLh>{s-;KkqRI z@ci`tVOX*s(&r|eoa~=`kmoHoOZHpR`-ct5{!E|auq4^fN$(%NO!j~JoQTVl{h~f! zx;WWi>T@XSCi_w8t-``&|EkZqn3(K$^|=_WlKrthN8@eg0Dj+m?#2np{#&2Z!E=D( zepjFC(KgxN>vKQ`Ci{VXZpf5m|FF*)S)S}S_PHcglKsg($K>2(KeNw0c{bVq>~m7? zNcKznT$P#0{%W7Ya#yk++vm3M{Py^L@HsCVlKtL37p70LKiucYypilD_qj7WFbDAG z;&W=6G6yjCxi;S<``djEPXA;-ywA-Up6s9ZIXnHB19*O)%kvp?0CS(?GmJTa`R4im zQM5Iz3b%sWz-n+ynEwCyzi*NJ|9L*o@Bi+3{Chl~?s1;iMDvJoze zaan@P#<*;P%ci(&hRf!-EXCyxxZDw!JK=I?T(-dFF1T!o%UyBV3YWX#vNbN-;Ib_) zcgJNrT(-yM9=Pm)%Q9TEN!DUBW?u*O)aLJ7@MRI@sci9=2<+u#EJOGzn zaCsmuyW;X7Tz13d!MHpGm)&uBC@v4f<>9zI0+&5-c_c26!sXGpJO-D?;_^6L9*@ft zaCsswd*bpWT=v3cZ(R1lWnWyLjLTDS*$>!Tn@$M<+!{8msjHQDqLQT z%WH5s442p9ayTwW;Bq7`ufydiT#m-&^|-tNmt$~wBQ9^k<;}Rf1(&zt@-|%Fj>|i6 zc_%LK!sXq#ya$)};_^OR-jB-%aQPrE$KvuKTt1A;M{xNlF2~{WF$+(68kIN5m`5`Xn z;qoI~evHfcxLknCPjI;qm!IPDGh8mh<>$CujLR=@xdfMA;&Lf2zry7*Tz-wqZ*ci7 zE|=r-J6x{7<@dN;iOU~w`6Dj>hs#yC{0Wyo7_O>o&1m(6h5 z9G9iI+yR$6;&LZk?u^S8xZDMoEpfRkE?ePpH(a*HWgA?!#pUj}Y=_JCxZDGm9dKEO z%ROQtZmwj;A z7ndjF@)TV5!{w>CJPntp{3a9Er>8 za5)N>qj7mXE^ol)7+l_n%bRd{GcIqz<*m594VSm$@(x_yiOaiic{eWa!R5WUybqW6 zk2xhnpp=g3HZuSrwOC;IbMnx5VXExZE0-+u*V~F1N+ycDSs8%bK{Xh0E=6 zSsRyia9J0Z^>A4qmkn^)5SNW`S&YjPTsFpK6I?dMWiwnh$7LxlcfjS2xZDYsJL9qi zE_cCYOI+@X%T~DD4VSHP*#?(wak)D#+u^c3F89D?2V9ona!*|Dh0DEhxeqQo;&NYH z?uW}xxZEF?opD)?%Ye%RaM=Zy2ja3TE)T+GH(VZ!%R_M49hZmV@-SQ;j>{u(*#nnH z;_@h59*xUmaCs~)kHh8hxI6)uC*ravE>FT`FI@J%2jlWG zTn@qIP+VS)%PVksB`&YR<<+>n2A9Kdc`Yu7<8lNpN8<82T#mx!Xk1>8%NuYx2A4PD z@+Mr~jLTbac`Gh&!{zO`yaSha;_@zB-i^z9aCt8-@5AN&xO@PY58`qxE+4|>!?=6| zmyhCd94;Tj<>R;drEL^^d%h|ZBz-5NZ*Kqkd zF5kfAo49-nmv7_p9bCSP%lB|O2bXhk`93Z`z~zUyoQKPgaQQJV=i_n#EMaxcmy2%W(NMF2BL$x42x6%kOZx0+-+8awRT*z~zs) z{2wk?;qoV3{*23CaQQ1PSL1RGE`P)2T3r5)%Rg}WCob3F@-JMj$K~I++btcJ@iak&*Px5ni*xU7!LZE?9BE^FYjCN68?a(i6X z#$_E`*2QH#T-L{B16(%5Wg}b`9*fK4aCtl~Pr&7gxa^6`lW^G!m%VY>2bX8gdrEL^^d%h|ZBz-5NZ*KqkdF5kfAo49-nmv7_p9bCSP z%lB|O2bXhk`93Z`z~zUyoQKPgaQQJV=i_n#EMaxcmy2%W(NMF2BL$x42x6%kOZx0+-+8awRT*z~zs){2wk?;qoV3{*23CaQQ1P zSL1RGE`P)2T3r5)%Rg}WCob3F@-JMj$K~I++TyBNSt#P>xF012mTU>63%Nn?>iOX8J+#Z*;aajkKb#Yk_m-TVk0GADM z*$9`#xGceCV_Y`DWm8->!)0?^mf~^;T<(a=op8A`E?eMo7hJZ)<*vAFh0EP=*&3H^ zaM>1@yW_GQF5BaB4_tP@Wf?B_#N}SN+#8qs;Ibnw_r>LYxa@?>{c+hDm*uz&xI6%t zU2u6IF1zCLAY69C<-xc-1ee`$c_=Oq!{y<)JOYqgBwY5wWp7;e!DU}uo{Y;=aM=%+r{eN7T%L~0{k1%0+(0f@+w?j zjmv9rISiNA;&M1HN8oZKF0aGoC|r)l<@LC{0heQNc_S`w!sX4lyakuH;_^0J-j2&V zaCs*#@51HXxV#6K_u}$CT;7k%2XOfyF2~~XAzVI;%SUkeC@#n0@-bXKj?3}5d;*tG z;_@k6K8?#~a5({&&*E|-E}z5YBwRj^%gMN$g3GD6d;yo!aQPxGr{nS^T+YDd%eb70 z%U5tY3zx6rayBk2aGBxqHC(=q%QtZOCNAH?<=eP?2bb^S@;zM6!R1_BzK_cfaQPuF z=i%}rTz-tp`M6ww%TI8*5SO3g@-tj6!sX|gs7)wo=P%inOh7MH){@(*18 ziOY4k{0o=sarrkcH{fz3F8{&hzql;gg7rV#EMXN~ZjQ^UxZDDl)o{5bF1Nzv*0|gT zm(_8(EiSjiWer@`#APj9ZjZ~_xU7TAy11-|%lf!%fXjxsY=p~VT$bRnF)o|nvMDZ` z;j%d{OL4gaE_cM`PPp6|mo0F)3ocvYa#vio!sTwbY>mq{xNM8d-Er9tm+f)62QE9{ zvJ97d;&Lxs?v2ZRaM=-;`{HsxTz10c{TpobSF1S1pmtApr5H7pn@?cyZ zg3Io>JQSCQ;qq`?9)ZgqxI7YFj0e_Wn{%QJC#7B0`m@^V~Wfy*m#c@-|N#^p7*9EQtlaXB29BXBtq zm)GHP6fQ^O@_Jm}fXgwsyb+f-;qqo&-h#_pad{gq-3MNS%OdxQ*TiqL;Bp!+U&Q5fT)u?M8Mu5Imosts3NB~i z@>N{U#$^RAGhDug%hz%F1}@*k5)XhRa2`{2Z5yarp%gT~Uvaq_muqnO8!p%4@^@VRfy+N}xek|q z;c`7L|HkD8TyDhWKe+rCmqpe1;Dehbtb)tUaak3YTi~)9F1N(xR=C_6m)qd7Ixe@x z<#xENfytcA<%aakLeb#Pf1m-TR2AD0bq*$|hFa9NDY5?nUMWfNRB#bq;GHpgWt zE_cA?j=0~|{18~^|mj~jqD=rVhWj9FYd>A38V%QJ9!CN9sy<=MDA2bbsK@;qFgkIM^iIRKXz;&LD^FT&-; zxV!|HgK&8%E(hcCGF%S9{`>c_l8d!sXStyat!UaCt2*hvRYtE=S_>I$Vyz zgs3|zj9%bB=*1(&mM`6@1F9@wxU7oHEpS;4ms{d;D_m}k%WZI39hckUaywksz-3Kb*23lXxU7xK zI=HNh%X+x1kIM$QY>3N7xGctH2`(GsvI#Dm;<6boo8z(+mpkBcM_lfN%bjuA0++ks zvL!Be#bqm8?uN_OxNL*Vwz%9Km+f%b9+!LIvI8#5aJeTg_rm4gxZDSq9dWrYF89M_ zCtU82%g(qg$7R6f|8aFz;aU}10HhI7K|nFFyStU{?(XjH?(PnY?(Qz7O9_JxX#^=j z;Xd3MAJ)@+Gi$A_R}tY{&;B#vGBYl-;4&*Nv*9v3E_2{ACoXg0GB+;s;4&{R^Wic- zE(_qYATA5xvM?@-;Ib$#i{Y|3E=%CDBrZ$gvNSHs;Ib?(%i*#-E-T=&A}%Z8vNA5K z;Ib+%tKqUbE^FYjCN68?vNkU3;Ib|*>*2CKE*s#oAub!?vN0~3;Ib($o8huKE?eNT zB`#axvNbN-;Ib_)+u^c3E<50|BQ87PvNJBb;Ib<&yWz4sE_>jzCoX&8vNtaK;Ic0+ z`{A-bE(hRpAT9^taxgB3;BqJ~hv9NKE=S;UBrZqcax^Z-;BqW3$Kmp8Tz-SgZ*ln@ zF2Bd+cwA1vak&MT zTXDG!m)mi<1D88-xeJ%Oak&SVKjHFcT<*o?K3wj{$tpu%bU3T8<)3mc^jAi;PPKw-ofQvTqd}OA4o7^U?N;5#$^&* zCdFkkTqeimJ-AGP%X@K|5|{Vk@_t-CfXh_4OpVJ2ahV2}X>pkjmk;6cVO*xivx z8@PNEmv7KF7x0rFD~=pGCwX0;Ibet3*oXbE{ou@C@zcP zvN$eF;IbqxOX0FKF3aGuEH2C8vOF#;;IbkvE8(&-F00_ODlV(xvN|qn;IbwzYvHms zF6-d3E-vfgvOX>w;Ibhu8{x7sE}P)8DK4AgvN6O!{vNjF2LnNTrR@pVq7l4!{vHhZouV6T>gN|A91+}mz#091(#cKxeb@wak&GRJ8`)Sm%DMf z2bVwL@@HJ`#pOO+?#JZ;T>gT~Uvc>xE`P`6L0lffe8vT%N$?NnD=7 z7_O>o&1 zm(6h59G5L{*%FtnaM>D{ZE)EZm+f%b9+w?(*%6nWaM>A`U2xeIm)&sL9hW_D*%Oz& zaM>G|eQ?uw<+r%}4wv8Kay%|4;Bq1^C*g83E~nsfDlVttayl+&;BqD|XW?=-F6ZEKE-vTc zay~8>;Bp}@7vXX-E|=hPDK3}cayc$n;BqA{SK)FsF4y34EiTvLay>3L;Bq4_f57FB zxZH%x&A8lx%dNQFhRf}^+=0uTxZH)y-MHL?%b#%hGcNbyavv`DCE)U`IFfNba@+dBk;qo{xPvG(-E>Gd|4_uzcw}aCseyo<{O_wxIHm@qIAE)(N2 z2`-c3G8rzDUDqN<<<%76PgUhtIOoz*daQQGU)8q0H zTt14+$8h;LE}y{Vleo-)%cpSpG%laP<+Hea4wuj4@&#PJh)e&wr8NAo^Sw-dZm&HZ z^MqmVVchpP@$r`l;$2GiUgD20U&iGtxO^3tui^4_T)u(JH*xtEF5kxGJGguom+#^7 zeO!Kk%MWq+5iUQ*m|;<6Dg z8{@JGE}P=A87`aSvIQ<%;<6PkTjR0~F5BX=9WLABvI8zV;<6JiJL9qoF1zBg8!o%! zvIj1E;<6Vmd*iYXF8kuLA1?djasVy|;&Ko!2jg-GE{EcB7%qq7as)0%;&K!&N8@q~ zF2~|>94^1cLTTu#R26kJZlC=< zxcn8Dzv1$CTpq;bAzU8D?VgT%N?`DO~=6%hR|#gUhqHJcrBkxV(VN zi@3am%Rg~>8JAaZ`4=v);_@0UujBFtE^p%UZ(QEOqz$H7*~-Wg1+j#br8NK7`AM zahV>MkKpoATt0@&$8q@tE}z6@23$Uc%cpVq3@)F=<#V`v9+xlR@xl>;POpezJ<%Tarq7|-^Jy7xO^X%AK>ysTz-Vhk8$}4EbR_d z%bK{Xh0EHwtb@zCxU7fE`nYU>%Z9jYgv-XbY=XWCxEzMd;kX=u%aOPoh0D>n9D~cTxEzPeuW|VeF2BX)cewl>m*a6c0hbeT zISH4OaXAH-Q*k*Bm(y`M1D7*#ISZGwaXAN_m+Nu40hb$b`2#M0#N{SjZpP&nTyDkXHe7DUga1pK-Ytm-}$JAD0Jk`3o+8#pQ3f{2iAEad`-rhjDoXmq&4V4421o zc>oF3;fdEH2OC@;ojt;PN6aFX8e}TwccI6%d5D&hRf@?yn)M` zxcnQJw{UqIm;d1MUtHe7aajnLg>hK~mql?|441`mSpt_OaajtNrEysXmt}ET z4wvO|Spk<7aajqMm2p`GmsN3D4VTq%Sp%0faajwOwQ*SomvwPj50~|E*#MUfaoGr$ zjd9romrZfm442Ju*#eg>aoGx&t#R1~mu+#`4wvn5*#VawaoGu%opIR(mtAq$4VT?< z*#nn7aoG!(y>ZzGmwj>B510LMIRKXfaXAQ=gK;?omqT$m441=kIRcj>aXAW?qj5O~ zmt%1`4wql!@*7-!i_7nD`8_Vj<8lHnC*pDvE+^x13NEMOavCnD<8lTrXX0`eE@$I% z4ld{7avm<{<8lEm7vgdeE*Il+2`-o7av3g{<8lQqSK@LNE?47n4KDfZL4t?)?={yl zm+Nr39+w+%xe=E?;POXYZo=heTyDYTR$Okw<#t@|z~xR{?!x76T<*c;Pq_RUmwR!! z510FKc>tHc;PO{o{)Wrnad{Azhj4iqmq&1U6qmGj~3@*>& z@*FPDkWn5mtuc`q(g;_^OR-jB-%aG461sd4!rF4N#L zEiTjH@*!M4jLY=6d<2(|;_@+EK90*LaQP%IGvM+mTt1Dx%xT-L;8EnL>dWgT4B#brHQ*2iT7TsFjIBV0DdWfNRB#bq;GHpgWPT(-nz zD_pk5WgA?!#brBOw#Q`$Tz14|CtP;MWfxp_#bq~KcE@E8T=v9eFI@JoQunOxSWs61-M*@%SE_c zjLRjsT#CzOxLl6Q6}Vi9%T>5sjmtH-T#L(fxLl9R4Y=Hh%O7z0BQ7`Lax*Ts;BqT2 zx8ZU-E_dK^CoXs4ayKsb;PNM2{*24LxZH=!{kS}U%U^K$D=vS-W4Jty%M-XfiOW;C`~#P#ad`%pXK{HBm*;VL0hbqXc?p+);_@;sui)}8TwcZH zHC$fDmnm_1A1?352UcFE+58adR#t&%SUnf7%m^jm|;<6Dg8{@JGE}P=A87`aSvIQ<%;<6PkTjR0~F5BX=9WLABvI8zV;<6JiJL9qo zF1zBg8!o%!vIj1E;<6Vmd*iYXF8kuLA1?djasVy|;&Ko!2jg-GE{EcB7%qq7as)0% z;&K!&N8@q~F2~|>94^1cLTTu#R26kJZlC=?VgT%N?`DO~=6%hR|#gUhqH zJcrBkxV(VNi@3am%Rg~>8JAaZ`4=v);_@0UujBFtE^p%UZ(QEOmrvvJ8C*V#%ja{2ml<)H37461nFW_wahVO5*>RZzmpO5n3zxZZnFp77ahVU7`EgkQ zmj!WI2$zL%Sp=6waajzP#c^2zmnCso3YVpESq7J7aaj(R<#Aa7mlbhY373^|Sp}C> zaaj$Q)p1z^mo;%&3zxNVSqGPOaaj+S^>Nt%mkn{*2$zj<*#wtOaoG%)&2iZRmo0JG z3YV>M*#?(waoG-+?Qz)wmmP80374I5*#(zfaoG)*-Er9impyUW3zxld*$0<>aoG=- z{c$+}mjiJ*2$zF#IRuwOaXAc^!*MwRmm_gG3YVjCIR=+waXAi`U*qx{Tz-p7|2uHs z2kiTQeb2A&|CPQcI0^s#IIo*Zz{gzuM|)EC5<@-?I{~l7{*U%#>`9*!_wD|9c<&$2 zdujL1KOg_Ry_a_H{Nww_^IqD$i+}z6>nh`4&u{n}5dZu9Z|Tnc`(^(+%eJs?+<71#c0Ur(ZiTEg}Pr^q+eKI}*>QnIHP@jqqgZealDAcFpL!dqb9}M-G z_#mjy!UsZqHa-CAbMXF9pNsc{`aHZZ)aT=UpuPa_4fTb1FQ_lVdqRCN-UI4O@a|Aw zig$zhGQ2C)m*ZWaz5?$I^_6%hsIS61LVY#f0qSe;_E2Aow}bjRye-t%<87e60dEcU zjd&}l|A4oI`j2=EsBglXLwz&e4C-6(rcmFCH-Y*#yfM_bU;3IQ2z<91NEQr+ECw%*Mj;!ye8E5<29gu0Iv@9U+`*B{}rza_22L+Q2!mT z4E2L}C8!_5D?F}y6)kK<*aegZEI^^;7w|$*zlaxv`X#&o)c?fuL;W(I59(L&yiorO&jaaOS+zr{smo6ME{(wC#HW!*OSmcrRz!QpV0MW^pENKN4VWP=YR3*_I&C8{|n?R zxczFFyJyeKowQ%$E)R44Iz2aCzd^ql=CSAE&U^R&=FYja=j2Y>Z*iA{xqh4ePngG^ zojdQ{|Cc-G(w>bwX}`l=R_6L$dVc#9V)no+iv=|ByTH-A~J%b7}v8 zJ84hH-9ylM?C*zr_aElYxwOB>owTRt?h)ub_IJa*`;T(xT-x8^PTC*i?s4cm_P4{m z`%iG^T-x8_PTHU3E(3HP`WyJ{TH}%F72;yC+#nC_Y!m-`^(|p{g=6O{vUlVcP~NrUt#`g*o*zeaPR(W z+&P!_*O|Y-z5WLMdAj~4{jD&M{WUpJRW3=Sq7i?n*=FvELu=-7mwP zb7?Qjyj<9e{XU-Wz5C_4b1v-_n5X1kuSl;H=CM}}bDv|sm*+}*74E7+=do7{bNB2i zc)qk(=dK2H9(&C&ch6pn`91t`^xE_~VIF(kF!wq3v2~fI*+|Un7e0h$UGT; z9K8{}ahS*6B+Pw|y(#l%VK4Ti{PDeazd3i#rM(67mSHdUR$=aQ?5&x%345_8;m^~1 z_uF#kT-w_)Zy)wz?-1rb$KH{7r?3}$=P>s<_Abo3hP~Lkg}KkMC+4q*w0GyO2Xr2L z&oFn--ivwfuoruuF!wq3zRVNx=c^~g?cO=}>uvejyUf>l?D^<%UV#25``)=1=LOln z#J+d##d#t2FS75QdvRWv{R`}S=U$u_VgEe)-nkd&McF^czIX1$c`^3SvhSUHabBGL zGwgfkUYwU;|1|sFxfkap+5dxm@7#;?QtY2%-#ho>yfphK+4s)9I4{Hg3HH5nFV4%d zf1G{q+>7&a>>p#_JNM$eJo`u4_s+dIufYBh_Puj2&MUHin0@cui}OnCA7bA-_u{-V z`v=+g&b>IV!v627%X>>ps?JNM$e zCj0x@_s+dIuf_g8_Puj2&TF&3mwoTti}O0{|IEI3?!|ds_J3mEJNM$e9{YRP_s+dI zuh0H&_Puj2&Kt15i+%6hi}Qx;?_}RQ_u{+}`#ae8&b>Hq%>H)vy>lIF$o^>dy>l`TJj=h&ArUl#Ua zUmoT@$Nnk*JEVODcPpXu*jI(Qd-m1L*Mz;;*M_;zv9DvkKJ3N5Asn!W8W0!KF7Y9`IfL3`_?e`IrfkF^ON>%+--->W8V?x?%8)T-xc;^|0w)F3f$7{Y{=L?dQ3>0G-GFM!0wXB6rTE{Sx!n zx!3=sUk>xwuY|eJvA@Q1rTs7Nu0rRrzZ&k{zs8+&X}`|=74G#L^qXNG`^(&U@BZK1 zIhXcZ%wOVOzfJ!q%wvC%JMZ29mpkXueuw!B-0OGg2_F3ae-Gw7_UE~C?tVh_0;qS!#wuKxbxoqG~79t_O#3&$(X@8Qt4A6P( zX~MnxPjTm5+8^Xj+Mnj`8R$Ir)ZyO!XSs7O?Wwqv_UE{J9y*WxfpG8s3*0%E_WQY$ z_7}N(2|ADczHsmU%iKAa_LSU7`zzeN3Z2J(Z@72=HSU~CdkXHP{dMl%fX-vTC)~UL zCU?%IJvn#M{uXy{L+7z43-|87!<}lNsS>3T)_A-Z0PevqzLrvFaY ztI&U=>s9H$()DWeU+8*u`T@FLgT9}x*QD>G>$T{6>3VJY&vd;G{U^F!m%fLt*Q4*I z>-Fio=z0VCPP*QZzJsneqHm|`jp^IydK3Cqy55w&g|0WFZ>H6_?!3;K_Ay(Rqz zy55Suk*>F-j2SOuD7SJq3a#!tLb`2`YO8KiN2Dqcc!nP>s{!} z>3UcCGP>T4zLc(ar!S%FJ?M++dQbWyy55VvkgoTpFQDsv==14%U-~?{-j6<)uJ@qF?%>H1LmG`c>FK9#Nyr%$2lBj}Uq`bhdDx;~0N zk*<%XPoV2#=;P`7So-&LeH{Hey8bo&Te|)Y{TsUeE&Xe{{vG}MFpqtle;nxkcr?5&>H0MKFuFdSK9sJ{pbw$zGwFlr z`Yie&x;~pekgm_651{LF>HX>YJbFL6KA+x~t}meXq3a9jz3KWQdM~=ZnBJ4FFQNCK z>r3g~>H0EyH@d!@-j%Mepm(9`E9sr-`YL)Sy1ts;k*=?yccANQ>Fw$II(j?0zMkHe zu5X~Xq3avzt?Bv?^j38JM|w-TzKPy~u5YF{r|Vnj&FK18dQ-Z-joyT=Z>Kk=>pSR; z==x52L%P0;-hi&}rq`$Id+7D(`cL$_bp2;~9lE}kUYoA(qt~MA`{_05`T=?ky8a8j zI$i&jUX8B*Mz2cOf2UWW>j&wT>G~mhCAxl?UXiXJp;w^mN9pD1`Z0Prx_+Eqmad80uVDS9co{s+AzT|Z4PLD$dFi_`V9^kQ`V9K9%AKTj`0*Dufu)Aft=LUjES zy&zrxlU{(XU#91$>sRRc==xvuymb94Jr7;KM$b*xuhVnU^&9k@bp0kh2VMW0o}I4W zqGzM)x9M5w`akq6bp2m?X1acdo{6sCrDvq;3DW%k|L6OPt|z2_N!Jt6zo6@h>7Uc} zB=pbddQ$qQbUhjU6S|(9{xMy@hn^zLWB-Ud@7=$bJLl5=A$QWAlDiL>>-W*`5A)dH z=gxcgAK=cpw7jdGG!++&P!_7r2x5XSsV0I*SMopWi=!~9`B7C`^C9)F6||lC+1!+NiP-V zu_xlrd-qFo=Um#$Fi*(6UY1@i%wtc$o%imS=gzsbS73gZ_Y~?C>6OAf_B-5p?|x?sM$j znfC~LvG)vfpJVUEym#1(y-%3?9D85p{lZ@C{lnbn*at8l81`Zx6y`q1KA8ECuowH# zF!wq3Va$hzz1T;DxzDkWWIihF#XdUBeU5z$^RZzs_HkkEbL?L;|0e9k{%x519D8bdd1pq>Z60`P7K0P%nm`hI(=Q52%;GPeHvTeiG`X@DorkjUR`48T=U3%i>3&UJgG3 z_44>(s8_%bLA@e=5bBli-=SU^{|)L@@L!=`75@e5)$jvQua57BdJTLZ)NA5S3$iaz7p!4 z@D)(+j4y|J7knAiyW&fs-VI*@_3rp$sQ17ZLA@uw5bC|~1yJve&xd*+d>+*M;&Y+i z51#||{`hRD55Q+ZeIPy)>VxnZP#=s>hx!nF8q|m4Q=vW#p91ya_++S$z$Za{Bt8-9 zqwon(AB~TP`WXCssE@_JgZeo9Td04He-q|*f1U9izYfXHp0t0@e0`%31k!d~pF!`$cC*Dzlj z_F`Wb=03;1p81Bb7yHIA_c`_-nEx2|V&4?zKF7Y9`IfL3`_?e`IreSLw}-vhcZ9jm zvF~KQE9}L-JIsBKJsUqSN&6n|euBLC|Cu}I(!Q7ZzOWa27M}0D`}?_bF6{@H zXXal2h5l=p$DWBh@7@26JLl5=JM)8KFZPT)-+T8Dapzpx4>SLYd;JLgXqd+B;?8^b|K-lP zwBKR=CinVX`WtjT0iXAj5IT?jb?%(IpNKo>(w><4YuxKe=&#cCr1WHA9{VfYdGCI5 z?wm{e%iKx(J=~>$&SQTm+`E4-ch05#Med|MC3p8h=dr&K?%ltiJLl5=Ja^Lm0C%aN z^VpvY_wJ|W&bhQd%bm18$Xy!fJoab8z58job1v;qb0_WTxO)gXkNv4|@BYKwIhXbf z+(~r_wyfxIgkOYuVf+Hri{R&>UKBqE^3e}{Ti z{5Pmq!+(W(b^I5o*T4@zy(YdN>b3BFP_K>eg?b(QXQP_%%P;ZKFg?cl53)GwAo1xwU-vsrR_>WL;h5rEc*7!!Kx4}0+ zy)C{T>h17#P;ZZ~g?a~k4b(g0tD)WrUj_Bf_)4gE!B;@NE501+-SA~l?~X5pdJlXF z)O+HKq23E$1ohtdLa6t_7eKu)J|F7+@Oe=0kI#kr0DKPA2ja7#J_w%$^}+Z|s1Lzs zKz%4a9qPmIX;2@IPlfsjdf`Y5p}&sv*NN}Z z{q?55o_&k%uZ#V4_iJ>2-{9{{o~Qf!Du3VhB;Bv0_;s2jbltD(B&PdyAivJ!*OPR= zF6Gys{5qCjC-duJx?flG>t}xb&#y1~bws}o>epHQda7TS_3OTVeb=uO`*mo)-t5<{ zGxF<5zy6&W&jS5=|F`&ea9r^3@v%@JkB@=+1bj5qC*q@^J_#QQ^~v}Ms87L%Lwzbf z4C>SHp-`WW4}tm&d@$5!;)9?*3m*ve+4umc&%ygceJhtivP@j+Yf%*cxH`Ev6 zy`a7b?+NwAcn_#A!Mj6!Dc%k0%kZvHUygTy`U<==)K}u2puP(42=&!?2dJ;X+e3XV z-VW;P@U~E2kGFyP2D~-YH{z|J{sZ0;>ObNwpuP!j4)x7=GpKLDn?ijn-URB~@WxQz zjyHn(4!j}Mcj678z6-Ap_1$c^TGSm;^m7snIuL$+Scm=2*!OKJaC|(Zg$MCXHKaQ7y`U$)= z)KB82pneK33H3kl5>P*l7l-;8ycpEa;zgl;4le@r^LSyXU%(4N{UTlv>X+~WQ2!Ip z5B1Av&G6-@tP~{U)9r-h#JbZT|nbfAKr83jHqb z_eE8p`+Zb?pH>;V-`C~$jg_GL{cV2#TtT|uZ|C>(<)!O>|6d-u-!JI*Bj%v%e*a>2 zy5H~U_fux3>wf=bCi=5{pP1jz{Q}+ZM}L`l2D;y`@B0AK(|xai?=476_x%UHUm+FU z_cZt(h?I2SC*k`llGAnHZ;_0y`#y}Mblvx7B%$lRZzC~X_x&7+=(_LoNJ!T+^4BK; zUC%`Ky&!sKy6+Luv(SC-h@O@1drI_dbl+>DXQ%rf6g>ys_onDM>Aq)0&qepWEP8Ib z?{U%d(0%WVo|o=>V)T4;-z%f%r~4iny#U?!*60Q4zUM|SMEAWodSSZn(b0?0eeaH5 zl!TN^`yL>@1l{)r=_TpDXGkwa_q{}VX}a$*(#z0&?~z`X?t7B-a&+IT zq?f1r9wxm4-S;->73sd`Nv}lry-<2(y6=(FtI&P#lwOtYd#dzmbl+>GSEu_PEWHNZ z_h#ue>Aq)6uSNI0TzYM~@A1;>(0%WhUYG8B!t{D{-z%oqr~4i!vrS`yM#G1>N_?=`HELXHIWL_q}v_Yr5~T z)7#K}@15S3?tAj|c68sXr?;p39zMMT-S_tC9qGR3Pwzxu&3mHs&h%Auy$gLMUGGX? zLD##{m(%s`^ksCt2Yo4B?@3=m*L%?y)Aio;MRdIneIZ@%OJ6|O`_bpq_5SpEbbSDQ zE?pl;pF`IN(Pz{3!Sq>leF%LfT^~xHLDz@Tr_=S}^l5Z`1br%9A4#7=*GJJO)AiBx zNpyV-eIi{SOP@gh8vh1PgJ0A2@9E>{`gr8r|Z+`!|3{S`cS$)gFb|=&!i8g>$B*C==yB>K)ODMK7g*zrT3@n z^XUEP`h0p{y1szkhpsQA_onNM=)LIrVtP-yzJ%U`t}mr`r|Zk;-RSyqdRMx>g5HI$ zucUXT>#OLU==y4UN4ma--hr;KrMIW+>*($1`g(d>y1s$lhOTd2xY=}qbSHhL4fzMbBfuJ52XqU$^94e9zWdIP$?n_i!;@1fVD z>p#)!()FL|b?EwDdTqMCk6w$e@2A(K>j&sH==v}8>U8~AdNsQK8@(!B|D9fit{&NKj==yPbS-O6LUWTrpq?e}ar|6~V`XBU?bp15F z1YJKvFHYCb(u>jcbM&Hg{XD%0UB5stOxG{c3(@sU^n&!u_!XF!eigq4bJB0%H(^%# zE&MjjNWY8wIYpn){hTE~$LU?VpR4vTpKtUiUH5a|9-;fWaDMJwI=b%X)TO2SxpsbT zUMjlo=j=T|_wxY#yusvjKcCRgKTJ&5{k+6PbU$Cw&u{c|8vVRSKTp!njr8*;{d`M5 z$I{Q)^z%IZ+)h7N)Xy*Vb4vXjSU+#p&z1Fagg@o4v!8G5=RSW<_j9YI{R`$_hP~Lo z3Ui-h&&WJe*o!@LnEM=i7Uo&QUhLVz+~?S{GtUwBV$T`oKF6MmdG4?md!8`&IrhBF z^M$?G^M|?5u@_)oFzm%%D9nA1y)g44VK4TgVeWJ6#h4cld$E@YbDv``$-Gq9i@kK1 z`y6{2=4HcP?B&AT=h(|LuMqZPuNdY&$6kqf<**lfl`!`?_NvUQg}vCThq=$O*I-^V z?8ROy%zci%HuE}RFZQ}&?sM$*nAZ<`u{Q{FpJQ*xyiwSTy>XcP9D5VyO~YR7&BEO0 z*qbwN5%ywl8RkC6-imqauoruqF!wq3w#?gwz1Z7_xzDk8VBRt8#oj5*eU7~|^Dbd8 z_O4;>bL`!icMp59_Xu;JWADklSJ;cacbNCZ`@wm9UbEhxK9{Z!pwFS}1L?Er`XKr& zx;~gbldcb;&!Fo=>C@@@F#0sQKAb+4u8*Kkq3a{*lj-^>`XstOnm&=PkD*VX>tpHT z=~M8ja0Ff2hts8f8h68(>(l8&>G}-%5V}5-KA5i0q7S0$v*`or`W*TIx;~fQpRUiN z_oM6c=?lU<_Jv{YbL@+lFAjULF9~y>V_(XAS=ftxd6@eg`wHeO!(QyG!rbTBS2JG| z_F`Wf=03;1j`{kq7yE`V_c`{B%zp@bvHuw6KF7X^`R1?}`<5{GIrgp0w}rjfw}-jU zvF~8MGwj8_E6jb4eK+$xVK4Td!rbTBe`dZn?8Uw>%zci1Kl1}&FZN%;+~?STW&T^( zi~aX7_c`{1%nyaV*bj%f&#@n2el+aGek{y=j{P|E6Jam*lVR?2?5CLj5%yv~9p*mA zeunwkuowHeFu#aj3f<@1`||UzwExN7W#~NiD`D=Q{V(QM!(Qyy!rbTBuQR_9_F}&o z=03;%H}hLzFZSDE?sM$_F#k8~#eOHueUAMu^91St|M@x2V^0|7$?)W`A%7q5!BfCm z^pyC0umU|5o*EXTr@_<0{PcAALohe}VLUy|PJaY{6lSJBfj=<$6tVN(DfJTuhT!mKZdF4pW|P^6!c7ZW|)Yc70(9mr27Bg?;Lne zc#EDJ&jYX1^}O_J^k#T-xP>n5o9WWtg1b%3^_KJ>>3S>r4|KgXeIs3OL*GEx+tSz5 z^>*}ibiF-&EnV+GUqjbB(pS^i&*GJMP)AdpGNpyWQeIi{SL!Us`$I{2s^>Os? z>H637@94V!H%H3<|Fn|8x!pZ`e6AkMwu z2YUQ*qsJd-di-&z#~;Uf{Bf_xe@^uH&y^nkIn?7nw|e~NT#r95=<(+fJ^s9-$DgP4 z`16_`e;(B1&zpMuc~*} z#KkX{64<{DbNB3HxRdtpxEsw}|DHaIu8*gWr0WytBk1}>`f$2Fi9U?3Po@v0>r?1M z==xOpV7fkyK8UVQrw^p-Gw1{8`b>I%x;~5EkFL+A_oeG|=zZw=TzYT1K9AmuuFt3U zr0WalJ?Q#EdUv|Mh~AB^FQ#{;>r3ce==xH6XS%+O-ifX+r+1|5E9f2Q`bv6xy1t6u zj;^n!x25ZA=xylwT6$}`zK-6CuCJ%Jr0W~#E$I42dULw|1HBnt|B>F5u5Y3@q3fIJ zjp_OpdLz2NmEMr9Z=*M$>)Yw|>G}?OJ-WV=UYD-#qSvA8yXm#*`W|{My8aWrCSCuT zUW2ahrB|ox`{>o^`hI#yJs(}aM9)jt|D@-k>zC=d>G~CVF1r2~JttkiO3y*p zuhFy9_3QL(bo~ZBD_y@y&qCM#re~(>x9FMZ`fYkfy8aLSE4uzK{Y$!jhyDd!zf1p| zt|xfp|G#efjIJl7e@fRA(LbT^<^Vr|z&U^RodxN>2hMqReV}G4H@7+(wopWh_jXP<7h`U#r>kre@hk5L;aOb`Ik8tN)+F#~Q z+8^caG3Y$@m%_dKk8|f-+F#^O+MnR=1?Kvb^bBDh`}5p+@BUNVIhXe5xRds$xqAjW zkNw$j@BXvgIscD7m%C@6`_D0d+UMfW!xzFl_NTb>-u)N3b1v-}xRdsmxO*8okNwGT z@BS;?IhXb)xRdr*xqA&dkNxp*@BZuDIhXdwxRdrbxO)>ikNweb@BUldIhXcFxRds` zxqAmXk3D_3cmG}PoJ;$|+)4X;+`SK-$No^bcmD(KoJ)H;?xg)g?mmLfV^16I-T#<7 z=hB{rJ8A!fyHBC>*dGk{?tjLeb7@b_owR?>-51b#?5V=N`(JYBT-v{4{s8xSM*979 zJrg~1n8$t}ciy|7g*)fco|Sn@?)7Z+d+B<1dX6xUJq35(yPuOg=hB{w`90k0x#`L2 zdLDY-FpoVMciy|7k2~kmo}YPA?)3unf?*ze67IZrzYurMr9Cls(q5RmBG7s4iNd}6 zMY(e>?ZucUU(HFHf%!=CS|7o%iln4hoiO(~_8UA`+Us&x4?2(idboGLK6lQgy#e!vVK4SZVeWJ6 zjhQzId$BhSbDv{x#=Lphi@imd`y6{q=B>hB?5)Gx=h)jYZyWYvZx`l1$KIZKhp-oW z$1wLf_D;+@hrQUlgt^bLcV*r!?8V+a%zci%2lJj`FZNzx?sM$DnfD2MvG)ygpJVUG zynon>eL$G|9Q#1#gTh|ygTvhC*oQD58unrz7Un+3KAic8uowHtF!wq3QOrk&z1YWu zxzDkWWj-$K#r}1e`y6{#e%`tU^=$Z6sAtFjf_e`83ez8gI|Pt zUi<>o^Wo>Ao*zF4^#b@=s29Y~K)n!t8tR4dKcHR&KLz!o_(`Z2!%slHIDQ=JCGcZV zFNq(8dMW$})Jx-spQ(T4 zP_K&bg?csoXQ)@le}Z}qd=J!X;=7?<3*QCx+W1bW*THu{y)M2T>h_>WL;g8u;ZruasvH^VnTy*a)f>MihfP;ZH^g?cM|4b)rXtD)Wo zUj_BH_)4h%kFK+f+OpufEea@LD=1*0fFc$OC}1HWp@f8VH%drINk~X{qjYz7N=PW( z-4aSj2&ljr<9p}y#~$N+f7Y0D?R8k#ZY&DJi#wmymKhcrht|2QMP! z_V7Yd?f@?!<&N-tQtkxLBjxYmxuo0~oq&yHFN6LfXv7|g09z)7Q;L)T! z6dpy&!{Cvm`~y6Klz)VWhhFdh&KSx64#~rvsUJl@I^0D+CiFf>KbC%6xQl*#=zWfU z0{z5r7yYEr`yBmb`YGWq`l+G!Ir?ez)5Bf#GeYlk^fT#ag}dlyhu-Jt=g`j$chS!a zz0c9lr(Y26qF)$#pQB$yzc}1Qza;cNN57PQS-6XSdFXwPeg*x?a2Nfm(EA+yPxPz9 zUG!^0?{oBP>DPt3=zk8q&(W`^-w^Ji-xzwIqu)gTOSp^v*UbJ4mPTEJGE9|}B!Oq^)@1)-q?xO#g=ezfQH#>V%zlT02dwDN@U+AO%h@E@y z_p`G%^#|w=hP&uLC*bzt7IS_s7`ToBHGQ@3EIp;7^7= z`W)=sdw+_Zy{SJ`nb;`poR*Kk-*WAN||x++-_NM*@{hRFNoA@{I@-6(|p^yG`cJ96Zhn>Bt|CjzX_VR7~t9bbi{%+`_&&bZb z_X$${@9RSLrv4uKSJ=z<;xpjog!n|EkN#zL?!8aU&fe6&#Lm>;$L@a8KKk@w?|l+> z_NG1^J5!&OT{6->`m|y1{R8amP5q1PO#OrG9wP0def0&)UsZYbs)IY-RQPMv8 z=fmFn$Jp7M`sdi0`p4NlLE1d<(mwj9!`}O+*x8%<)a*=s zN_MG8`{+}J{eSoF>HoXKr^K77@lTUa(aX=^pACKVPqK6G{d4T>O??V>rv7<$X-NC% zlZU=A7kg<`}FMWP5q+A$mC@{?*V&{~$Z}-oM7q-qb(9&eXroE*ZW22L8>^N1v3Pd+#%`vp4lg z*qQpb*xgSrzm3lv`snXt=id7)?Cec_Vs@rJE4xJW@;mra0y_^G|0589XzxyoT&kny&-oeWs;BVvQ5Apxv<&W_H;N_h7zwz?N_*-~67yc$* z&W*o;m-FEN!pnK_*YWZv_-lAMAO0#{&X2!>mkZ$k#LETom+|ta_)B>CGyFxoTnK*w zFBiuDftQQmf5*#3@#pdK=lFAYxfuQ|UM`M5gO^L-f5Xcq@u%_f7x+_nxfK2+UM`J4 zftSnRkK^UC_+xmv9R4U?E{{Kgmn+~8F@LwLCo{vckij6Z;vtKj$J<*N97c)1#W zFJ7*W--DNH;CJKYn)qFKxfXsWUapPbftTyxx8voy_-%OkOZ-;6{1tu+Uap7VjF;=< zf5poU@W0^YhWJf*`D^?}yxa)C0WUYkugA+x@IT|_rucPu`5XLNyxa`G1}`_qug1$Q z@IT?@miSe8xfOmTUj7!p0x!45FUQMm@XPRWTl`YI+z!74FMo$$jF;Qv7vbd&_=R}6 zBYpv1?u4I@m%qo)!^@rVbMbN){2aX86+as~JJP`8Rw?ynF^<0xzG%7st!z@Wt@*dHm;i`FDI#y!;2g2wuK`FN~Kj;tS#BOZd<5 z@@4#|c==EKmC#3Dkez$)ud=f@^#$0O`fKd+)63WKe}z8!eC*tNe}kR9ssDtXslUlC zFTH#V|99x4&%@5W_y4f7H}$#Mnfia(<)W8w(BdsCm2ovBZd`hUN_ z_7S~&5B}cJNB`nb!>`Z+Mc2AP_(Ps*K@1J64Z|dJO^{=us_0O?;p0tlXW7vD2hMm2se}$c? ze}UbLq( zd++nHvp4nm=^tk=7r++`ee{p9bMO79?CeebXY`M)m<(BmHo41kV{s+DHEb_x9e8 zVrOsahp{vDquC9mm&f3T;N`LS!FYKbeh^+Bj~|GaC*TL*<%#(IczF`OA6}k}?~9kG z;QQd^srcS_c^bYKUY?HciI->Kd*J1n`0jXl7QP!^o{jH{m%G4vclQ2wF@n3{JV*cE ze^;R&3IE9be>;5aN8x|q-ko=`AI<$R?%jD8`!U=P<=&llu^-F*5boW17yEJC59Z#T zcd;MO{UGk$c^CT$+z;g5op<(g=(BV0zeoMt(0iw!M?XK@MZX~QK1aWheo?rKesSo1 zjy@ZIAEtf@yQQRk^vgo;oqjp}if|YG%Fz29{VMvO!d>*ML+^9+Yv|wQ?^|ArUl;o5 ze-6FR(XXf95bmPi7EGtZkq_VxhCcd3 zq4zoZw|K6pKg{k3X&?R3(0ixP#Pd!4F?PpE`{>^cd+$%Mvp4l8=}(2b=-=S^?!7Bt|Cc^3d-*p0PUxe5k)3<*@3ONu^$DK--~Yeq1@`hi_%wL=UVOsP zNB=xK_ueOBXK(5g(?7>vz7KzY=%as@oqO+-u(LPy&#*J~N!cYM?W2D>?7e@0oxQ1l zkUlkg`5}BNy!K~(jioN_e{z<(21U`A_qff!kz4s~D+5eY5 z&*!^`pCX^Y%PH}xLLdF(?A&{wnw`C=e~g`}f12Ghq{hQ0UCva>h!kFYcK&#`-+ zw2%Jbu=hRJzXt^;y_uCGDfX8+z~G!P}eqJM^ah zUHolQ&IV@>ef0l^-uoPQdsF`py{Uf>|9Fe}K0)^|$Cv{fGFQr2G+_GxX8l z2)*|o?#{WUeMd05_xhQ;|ls|{hk#aHkEGZX< z&yaEn_%~8637;nAFW^(8Tnau(%BA5Gq+A9*PReEBW29UTK1#~v;UlD60X|I172!jq zTnRo%%9Y^*q+A8wPs&x{eWY9s-b>2W;XR~W1Kv%_HQ`;PTnpYw%C+Ggq+AEyPRe!R zZKV7qyp@!{g13-zJ$N%I*N1;4o8%enlyn&P(!|O@83H&oDH-*=c z@;C5WQf>yXA?4=qYEo_i|3u0y;Z>yE3SLRd-@+?Mxi!3;l-t0|NVzS%l$6`SOGx=U zcrhurhZm7@2Y4YVcZ3&^awm8`DSr>oBjwKUTvF}=&mrZm@N81<2G1hp?(j@f?g7sr z<(}|#Qtky$Bjw)kR8sB(Pa);L@MKc%2Tvm9{_sRn9so}u<$>^cQXT}4Bjv&HSW+GW zk0Iru@MuyV29F};AK;Os{3ASql!wC)@nv|~&kg^P&&#pb%RbMY?2qq{Bm39uUzhCP zpMM{+|2+Krmi_1FKPTCL-u`oy{rBU)2ibq0{(F=C_wT=F+5cYr??U#!FaJA|{qNEL z?qvV_^}kcu|K9!YTK4CMKM!PoKKb)T_UE5J&t!kT`twru=eIwPWq&>J=e_K&AO1Qa z`|FLruE_rS!rUg%KrN5ucNZR9{cOA?62ScIxYL_y}z!@ z%lUcY|2rVBz_%vlmGHNuyb5kb%0Iy^NqIHgf|S?5%}IGJ+>Dgh!QYVb&u~*xUJo}R zn%ig&UCaX1G2nZ-MKP@>cjOQr-rCNy^*dx}>}Vu0zT@ z;o79U3$8`VyWyIoya%p9%6sAJq`VKVM#}r)s-%1Xu0qNO;mV|Z2(CoRhvAB(d<3pQ z%17byqM zX7}J_zs{Bb@7Lx0x}RU)^Xr6u9n!Bi`gKdcF6!4m{raq52lnf|em&Z+d;9fmzkk5* zQ}Fu{{Qi?{{B!pEV*Gxg9C*Lq$<)6`|9-fO{)5o_9Q}v%ABDTc6MPDoQK1W}hzD~G{zHaD!j{ZyfufkpQ z^+NA+^!4c*guCb)hTiAszou^#?xJrTdY_|jLf@zd~fAH3g3FZaby;a={CpNyCLsPQ z_wqpe1iU;5@1HY}2jj)>L+^9+OX!z|yXcpN-sk9-)2|43(XR}>&(W`<|0&!>zdH0jN56)C zZMchmUFdy|{%892;V$|Oq4zoZjr5zsUG%?%-sk9lrQaOxqTdpFpQGPOzb)KFzdiIm zN56x9XSj=gSLl6?emDJ|a2NgF(EA+yKKlLPF8TwZ_c{85^oPP-^oK+5bM!~(kA}PG zkA>dn=#SH%2zSw+4870MpQ1k20i~d~b|9~$9@ALKD`1RM+Uu1WQ zw2%IB=)KebNq;5WMSnH)K1Y9z{(88J{;$yc9Q_UYo8d0{TcP(k`oHP_33t)|8+xCk zzfFH9+(myk^#1u~{~UIG{yqBVzWwv%webFVdH-B~1-$Pc@I42`@xE`t_d0xr_dO84 zXCgn|_fq)Yi#&MWli_oGj`#f~z8@tkUiN(|S@6Dp#rL~p!pkr4=XBr1 zzX+!#U&YJm@EP%0Vc(DSFy8ljy+?mP-uIv7#3#V#f^(C;?=3I<3F&+3^1}s4-=Fs> z{2A$c{^UY<-wP-g#`_*Yxd`6(4$4LGzNb+B9PfJ#gD4lr``$#k1m5>7$|do> zmr?!#?|U5OQh49{D3`|jo=CY2-uFt%W%0g;QZ9%0y_Ir#yzjY`E8u-Erd$#4do<-r zc;CAzSH}CEPPq!+_j<}z@xBLCu7>x$p>lP+?-`YA;C(NtTodnmOyyd5-+L<8#`~UB zxeng*fozK2!*67PFk<*)F*=T)wU_r0)keZ23Hl^fuF@2uPq?|W+HukpUuR&Ip% zJ-BjXyzkAGo8W!VuG|#wdwJz=@V>`aZie^0zjAZD?+KP$;C-*K+!F75h~-vz-&-ty zi}yXpa%=ob-a{$3!LPu}ZSl+Tay$Goy!;)0DPC@mUxJrA;1}cNj`&4*xf6aNUj81x z055mO&&SJM@bmC;SNvSO+zmemFL%e!#>+kMv+#0H{7k&u3qJ!d_r_1h%YE?E@N!@L zRJ_~|KLs!M$4|z~1MrjZ@<9AVygUd$0WS~6kH^bH@Z<3EQ2bcDJPbbuFaLlajUNt= zAcy1Sk@z3+@+kZdczHB_7+xNOABva9;)menarnV_c|3j)UY>v-h?ghg2jJyN`2Ki# zGQJ;Po`Ua-m#5<2 zUWxw}FR#M4!plG5TjJ%__!fA14Zb;EUW;#rm)GIH!OK76o8sm5_$GLH1HLg{-iU96 zmp9?R#>>Cp8{*|(@eT0uW_*3TyaitmFK@+vg_pPCzr@Si@pbX?4tyQFyc1s=FYm(F z!ppnyHSzKud=0$37hfGO@55Ka%lq+F@$vzD6})^9Ul}hS!dJq}hw&Bh@)3LmynGa2 z9xormm&41)@n!My349s6d=g(8FQ3Af!po=eU*P56@Fnr`8GH%6d=_6EFQ3B~!^`LK zpX24<@kR0SANV48`2xN$UcQJggqJVjKf}wH@t@-5Kk)_e@)djmynGd(A1`0S=flg_ z@t@%3zwmkS@(p|*ynGX%8!z9&=fcZ><3GmB|KM}t<$v)X;pN--5ApIH{0DgXF8+PI z?B_bZhnM{v$Q*dt&yCEE_wy(He9NqOKPS`A;d~44=Xv^hp|9ip+)+Q*^cB3H%j)O8 zzKHj8YyDi@r}2JHwV#81FJAU@v+u$CIop1Yx1ZN7`?=qKzPFzf?&pyEdE>I5TkhwR z`}yjAe!HL3?&r+=Ire^Dy`OuZgU{PM&F6)`2ft4q$A18SNFK)Lgg++t;77nC$sYob zf`^gvXm}_okAa7f@>qBIAt zDNloYk@9r7Cn?W>dyw)>xH~D&g1eFOY`7~a&w;y;@?5wxDbItyC*}EYCsJMjcO>P7 za0gOe1h*&U#qf8eyaaAX%1hz4q`VAnL(0qH)}*`w{+5(i!mUVo72J}Pe}Y?(@@lv_ zDX)Q>k@8yj8&X~eHznnt;U=WK9&Sv^8{kHyyb=DIlsCZ*N%58*SzS;(aLci?x)#CSOyJ`rBdj!%e}bKvjA z%kSau!OQRC6X4|!@OPj3-yaN>Kg8d`%OBxy+AfAR9i__``U)GX4-=u7W>^m#g9r;N@!g{dl=Leji@0 zf!~XlYvT9dlq6c)1>aD_*XT--4GL;5Xyt zhWKCc^4IuZ@Ny&kCcNAjzY#At!EeCJP4VmT@;CUO@p3c#I=tK*zZNgIz^}o}E%B@I zax45#c==oWD!kkpzY;IE!LPu}ZSl+Tay$Goy!;)0DPC@mUxJrA;1}cNj`&4*xf6aN zUj81x055mO&&SJM@bmC;SNvSO+zmemFL%e!#>+kMv+#0H{7k&u3qJ!d_r_1h%YE?E z@N!@LRJ_~|KLs!M$4|z~1MrjZ@<9AVygUd$0WS~6kH^bH@Z<3EQ2bcDJPbbuFaLla zjraTJ{l3olefDzvzI-`;AHN*G?_Z98PC$--u0W1|4ndB8ZbA0XISl9TbJ)xO``>Mk z`CbqFh|qhdAIi?uk7PH5ULJ)XjF(5_2jS&`u-=`$IflLWrhY8_0G=n0!}rI_jBkUNm*89D<)!#<@p3Cz@6O&_#@>5V-;(E; z`sM6akoM8H2z&2Wva>h!&DojyRqUG4%Rk}2!OKlyy*qnzHGA(({TlivJWpPWZ;Y4M z;Tz%QpYdPg<%Y1{oxQo9z4xYm1APOYCvU{p$IF}W_3-j9_^}Ht3@ww$JfNmHDJ9vdvgbS?@j$q`szGS-i5D* zmv`f<;^jT~DtNgvtaoQ`?q%=2sozImiRa1t@fGp%0el6#d=OtAFPDS$?(EG&?7cVj zWqFRNKg{k3X&-%=u=oBbJ9|@Knw_aX#;z2-d>sD;UM>mi-PxNb*n4m4Ptup*dGaZI zalCvQUkoq*hW{Kd7lrli?9DUmy*Kq|>5K3@`5eA5UOta6gqMHEe}Vy{W%SpNHqk z*YLUV@^ySJy!;pbW4xRb*1NMeZ?N~?)Ze84i08?-@E_vkzwsa7<$v(+yqCTA zramEk7M>?3!e_?IiScja<@@k&;pI%Q-krU9KYQ;@eG>XNd7hjU{{~)8hJPI|KY)J? zFTV=w-PxNDviIK9XXH7i{vmb`llIZS687Fd!p`2*XJBXQA7%G4z5E#dCA^#-*1NMe zA7}5qsegh#9nX`K{qyYXO?^ssrale3r|9Ju@K569 z6tLc%z4;=0?@fJL`s6%MPKSR2FQ>;pj+bA;KZchdh4t?2&6nAGZ|XD9Kf?3mSMU$x z<&5};@batp2l4U)u-=`$`5JrgO?@(+W9naL_XcSnebTV^{!MoFralQfQ=f_5{q*u% z`1|m3Vp#9a-h7+A_ohBGeIlMGXTc}L%USXF;^lYn_u%COu-=`$`7V3!O?@`{yDug9 zzyFi7OWxjA!#4|t+4n0BX;(t{w6z9 zpOf7Udii7gUwHXCtaoQ`=3?)?sn1P+jpxaE@K^D2Ui=lj{0aU~ynGqfyR$d*vG?B8 z=cm8K^W*~fi+H&p{sLb96#oZa{vFo4vo}9u@4cx%&vQ(DA$EmH`{>Vwz4t}f*_-;a z>`Z-8c4z42&+)(E<3 zy{Ruvf0XCRW$;Jva#{Rgyj%`{2rnOm_3rG=^6b4g^#^#4sjtAUB55D}{;>DH5<7cS zzmJ`%ugq>Qy<7#q2QTl2_3rG=s_eZt_0{Ni@jSUYekWe8f!~3bYvQ-#GzI z-qdekXX+cWTTd^4jsF=huY>jO?9E2(y*KrZ>DTf+xe0y^UT%tCjhDZ{|Ad!U!FqT0 zW;6EQoBHPTD|w#W0>1(;x5O{U%dPOs@bXev@6O)*mc93;ehJSp^{v^pA?>4I9QNL~ zWoK{d7qK(-?bt1(m%qa=z{~Sty*qoeJ$vs>eFyq^JWuY3pNp3};pgDx@A0$o@+?^I z&fe_I-g{Hug?=W_le^+);N@=k>3F$2ei~k$3hUk3n?2ZjZ|bM;98=$uT`$r;`pIGM zeQ$R5rhXDTQ{RW(M0&X|ega+|59{68oBh~(Z|eKgkK=jr0Q^|IJP=B% zy*qnzFnjM!{Sf+*JWn2qAAy&L;fLepAMiiof91-rK z9~$=Fk7Q?W>W8p1^`qDgrk6+K2jS&`u-=`$IflLWrhY8_0G=n0!}rI_jBkUNm*89D<)!#<@p3Cz@6O&_#@>5V-;(E;`sM6a zkoM8H2z&2Wva>h!&DojyRqUG4%Rk}2!OKlyy*qnzHGA(({TlivJWpPWZ;Y4M;Tz%Q zpYdPg<%Y1{oxQo9z4xYm1APOYCvU{p$IF}W_3-j9_^}Ht3@ww$JfNmHDJ9vdvgbS?@j$q`szGS-i5D*mv`f< z;^jT~DtNgvtaoQ`?q%=2sozImiRa1t@fGp%0el6#d=OtAFPDS$?(EG&?7cVjWqFRN zKg{k3X&-%=u=oBbJ9|@Knw_aX#;z2-d>sD;UM>mi-PxNb*n4m4Ptup*dGaZIalCvQ zUkoq*hW{Kd7lrli?9DUmy*Kq|>5K3@`5eA5UOta6gqMHEe}Vy{W%SpNHqk*YLUV z@^ySJy!;pbW4xRb*1NMeZ?N~?)Ze84i08?-@E_vkzwsa7<$v(+yqCTAramEk z7M>?3!e_?IiScja<@@k&;pI%Q-krU9KYQ;@eG>XNd7hjU{{~)8hJPI|KY)J?FTV=w z-PxNDviIK9XXH7i{vmb`llIZS687Fd!p`2*XJBXQA7%G4z5E#dCA^#-*1NMeA7}5q zsegh#9nX`K{qyYXO?^ssrale3r|9Ju@K5696tLc% zz4;=0?@fJL`s6%MPKSR2FQ>;pj+bA;KZchdh4t?2&6nAGZ|XD9Kf?3mSMU$x<&5}; z@batp2l4U)u-=`$`5JrgO?@(+W9naL_XcSnebTV^{!MoFralQfQ=f_5{q*u%`1|m3 zVp#9a-h7+A_ohBGeIlMGXTc}L%USXF;^lYn_u%COu-=`$`7V3!O?@`{yXpV;zZc}} z_&azx2mUr*eh>dIUj7HxyR$dnXYakK|C{HS`VZKBNZLn#E9|}hh@HKuzsb(j=VW(- zUj7*W7hb*&>)qL#x!8Me>T}ay<9Tu({8hZ17k>pWe}exLFJFfB?(EHc?7cVj`ROn5 zJh=e=B3>?tzkruN#s7hqe~0z%?9I>EdvEH`^BhxOh+SdQKKgTE?|l(=_NM+UJ5yhj z-5GlMbNp|3`82F|XKxl`@4cxnPJfE$$tCb7@p4K03B3FT{y1Jf2J79~o2A%$Z|Y0a zALV&+8T=8vTo!*AFPFm~!pjF?y*qoeJbUj={Q;h1>MO9TNZLogKkU7)#LnK-?_+1` zE3?~6FIU0u!OOd0y*qoeDtqrueKq=BJWsBU--(xN;CJBVn)vN_c^j;EXK&VG@4cz7 zO}~}r$#w8s@N!-JX1x3*{#U&G3#@l%Z+^wzdsDxO=a~9>?CO*D(QgcU?;EhQH}xCX znfiw8*3-*h>tMY*d$SRH?@fJU`n5byZh~Kfmz&~OoBAm{$JF;^*Ne1|esb7*-Am?QewaU=&%+NVM})iRhlaiP zBiY%T`XTI0{U~;W>E+S*L3nu}taoQ`j$!Y;sUJ%}fal5M@cr@fczi#+JOSSqFZY4< z?(EHp?7cVjljwW%Jb5y{7hax%?}?YE;(Orb?y%mSy*Z7&_oluZ&oTAW+07vBqwgB_ z-p^!bZ|b|SGxf9Bb*7hR&%m*?Z#T*%&gQ@@D5Ezgq|)qL#d)a$$>i5xC;(79Zd_}x`0AB$wAHl950{77sJcH z;XlXAMPa==d-Du??@j$#`XW3}K8G)im(Sx1;pN})pW)?CVZA$h^AGmkoBD!0$JAe7 zcagM@zChS}e~F#Fsn5^O)L&+ok6!*0{|R2s3+vt4n^)L-Z|bko=izzsHGFQod>x+) zFaL%A7%%69_3rG=8|=L|^*8B1;(78d{D*k?Z~O;%`5*lIc=5j9`@efWoK{dv#~Sv30~y;uju7_@bBQ|tg!yw(0g|;d+$wsLi#N1?qSkC`d7l<`$yQ>oB9mwO#P$mUZ$5H!@q==)5Cgq_U7a4y*Kqw(5K^h za&mlHyqp66B3^zH{{mi41MA({n@_R#-qfe0f1c;bsqoL?<<$6R@$%F7XYlgVu-@H& zy*tu-^BH_|Uuf0leM+(n-%?7e@UoxQ0~$+Iej?W0c`_TInA&fe4~VQ1OWxjA!#4|t+4n0BX;(t{w6z9pOf7Udii7gUwHXC ztaoQ`=3?)?sn1P+jpxaE@K^D2Ui=lj{0aU~ynGqfyR$d*vG?B8=cm8K^W*~fi+H&p z{sLb96#oZa{vFo4vo}9u@4cx%&vQ(DA$EmH`{>Vwz4t}f*_-;a>`Z-8c4z42&+)(E z<3y{Ruvf0XCRW$;Jv za#{Rgyj%`{2rnOm_3rG=^6b4g^#^#4sjtAUB55D}{;>DH5<7cSzmJ`%ugq>Qy<7#q z2QTl2_3rG=s_eZt_0{Ni@jSUYekWe8f!~3bYvQ-#GzI-qdekXX+cWTTd^4 zjsF=huY>jO?9E2(y*KrZ>DTf+xe0y^UT%tCjhDZ{|Ad!U!FqT0W;6EQoBHPTD|w#W z0>1(;x5O{U%dPOs@bXev@6O)*mc93;ehJSp^{v^pA?>4I9QNL~WoK{d7qK(-?bt1( zm%qa=z{~Sty*qoeJ$vs>eFyq^JWuY3pNp3};pgDx@A0$o@+?^I&fe_I-g{Hug?=W_ zle^+);N@=k>3F$2ei~k$3hUk3n?2ZjZ|bM;98=$uT`$r;`pIGMeQ$R5rhXDTQ{RW( zM0&X|ega+|59{68oBh~(Z|eKgkK=jr0Q^|IJP=B%y*qnzFnjM!{Sf+* zJWn2qAAy&L;fLepAMiiof91-rK9~$=Fk7Q?W>W8p1 z^`qDgrk6+K2jS&`u-=`$IflLWrhY8_0G=n0!}rI_jBkUNm*89D<)!#<@p3Cz@6O&_#@>5V-;(E;`sM6akoM8H2z&2Wva>h! z&DojyRqUG4%Rk}2!OKlyy*qnzHGA(({TlivJWpPWZ;Y4M;Tz%QpYdPg<%Y1{oxQo9 zz4xYm1APOYCvU{p$IF}W_3-j9_^}Ht3@ww$JfNmHDJ9vdvgbS?@j$q`szGS-i5D*mv`f<;^jT~DtNgvtaoQ` z?q%=2sozImiRa1t@fGp%0el6#d=OtAFPDS$?(EG&?7cVjWqFRNKg{k3X&-%=u=oBb zJ9|@Knw_aX#;z2-d>sD;UM>mi-PxNb*n4m4Ptup*dGaZIalCvQUkoq*hW{Kd7lrli z?9DUmy*Kq|>5K3@`5eA5UOta6gqMHEe}Vy{W%SpNHqk*YLUV@^ySJy!;pbW4xRb z*1NMeZ?N~?)Ze84i08?-@E_vkzwsa7<$v(+)z z{&+qQ|19}jxQjkj*n9sxJ9|@~lAWnf!|o}1`33xwcsT{EcV}m++6_?7e@JoxQ0~!p_uZVs}5i{1*N`yqp-;yR$dnX79bJ&rF|) z=gC>{3Gs4P{JnVj9sE6bIRUJ9XK%jC-g{G@js7kvXNT{Qat`=5DZdB*OUnNQ@6O(Q zpF8hO{onMa{sa7np^yGn=)M04Z*S^v(wq96_#34BG5i-PUk~1$y_t(U?@fJf`fH?| z2fj+mdEqOh{0aOgDPIoWoxPclJMT?>e)>zKTmZgE$_3#Ir2HxT2Pyv^ygPgIGw!@M z_2=nLeIb0|&_{nR^xhZ2+nf5c^rpTj{tPL94*y2Vr-OHAZx-XudsAPW{uC*ffKQTg zN%#aQe*qsS%fLrSxh#B`l*_?~Ncmv!?(EI-+<9;6573+X z3iyhlkA8pXy|09~H}(7IO?_qjUQ(_C?;+*g!Mn3Jt8(YPsjo)AiM! z`i-IYz5(9e)Ni0S^$qdsN%?E|XHs4lygPfd5qI93`o{EYNx2EUhLoGat4aAA_$N|c z6}&rpvl(~ZoBHPTD@nNpyn>Wl!pljy6}*g;mj>_7-u#w3?@j#@dQ;yT-zN0YFAlx; zZSnS|ei6N?Z--w<%HP2YNO^wn?(EI>+<9;6JJ8P~<&N-NQtkxLA?5Gk*`z!xcz5<@ zXYRZ=^Bo`s0C+4Z4}`~%@*sFLDUS-?oxM4jJMT^X z5c-j%JQN;5%ERE{r2GT?BPl=fzu%Tlpm%3)KE|E*rheGV|2uH+Uzb0=?B9ofy|RDb z{{8vS%YP64^OpVh=D#1=f6xB=^uG`PyYs&z2Ph$^JU$uV?=H=&!r&c+PTi1=%w2O1K3nuY#MCtI0KF)4*%tCZxO$ZcMHx zH;@g<&EyucZs4tO9a7!~*Cuz6JINY>cfr+3c{f~*+)M5wE0c%GBV^gYN8vK0d<-s4 zo*++>B?F&=OOWzuxHx%+JWCcOFOV0>f`Ko=1xWcaoS(cxUM2Gez6R$Z6@&m`02CIw#h>o&>pa(bTg1m3R?`E{p9@qYcxugfLF%YGd%DPGRR^ONBHdZAy3 zOpKTPx@97~oR#M!#QXJ8zwVj<@7It0y0l+^mi;=mU$2&P@_fI(oeR!Q`t^1>58kiO z%X#sBJwG3upY;0+3c-a*zyCrmg7^D1xm-%75I_xrQt8hF2-s}@|F^!v-|!SzYM|4wdz z_xttahIqffuMyms^!p9vCV0O;QErO&`x%?T%}Kw%vNha>T*CJk$Zhe9@p3!-B7A$e z134crcf`-b%boCZ@txr=;*1lkolE{^WSPJODoqFAv0z#Seyu zkfZR!;SuC8ygU*=6fcj$55bRt$C3l_@;LkeygVM?A3qVEME1c?hi8!8@bXN2SG+t6 z-vvJho=bMZ%k%IZ@$!6p2mC^K5!nvE99}`T#LFx3E%5Rxd~^J2cn#SUFR#Tn!OQFL zjq&T@4P-<7W_Sx(7cXzc*TKu%@U`(f;GJX*yu1rv9WU?3SHtgx_mP$Hhv6e+S-gA{ zUj{E9!>Aij4b z6W;fy_+FNbc-i;3yn>f~?@I=}?~Cz0H0klO@2yFPmwnGoTD9QeQ#58yquorJc0N9P`-ESQM~WZ^1WQi@UrjmN{W{= z@%$us-xub4$P(ja-&>XlFK6XB3Gu!k&G)V)!2A9<-%IEF=Vaew=lkm9oIKz6+vS3D zlfG|H&V%>;d~#mA@AJzC=O=x?U?I3L>H8PuB6#1|C>O>1e#c^Pankoq$|dl=pHeP~ z_kEV7;L@b;*Q@|nBz^y=TnX>{O6AIU-)~wKu15O4Rk=Fe_p{11@V?Kr7F?V3{j&Ao z`lRpQl^fuFU$5K{@B4il!Hr4ZH!L^7`+j1%Dc<)PH-np#zF)aD+=g7j`vv8;_{Dg+ z9exqMJ=}qukC!{*=i%i}___Gba2IkGz9-y^oPw8o<0s?gKKM!aesF(sJYF7vABUF* z;>Y3#!$ZhX_~Gyfau{A7i64rWN8yLy$G~IBfp~cwegIw`kMED42u~vW;HSeg$ZmLf zCcZ0Po`vs%p99Y&JK^Pd_>OpaKE4BfA-srehhGk_AY0<)mG~BTc@@4nel@&?Y>JoH z;+x>*b@;~k_3#F=A$~Kwg{+I0x8m#Ig|Cj6cjK$!_rm+g%J{?Z z5wa{^K8i1cmyh8~<4?dR$&z^a6utyrK8-JqKLej7i{dZ97s-Nn`4YYWUcQXakG}$6 zCG+CtYxq2P`8qx~{sw%L%!$7Z-yw70<-7Roc-har%!c>#GW{IRta#ba?aYFg{hZIt zct0Q1&mGN#_w!TzT-Jn{T%Ydc-hY_PlT7V@|=WtKOf!CT~C1b^W*(odOv?&_H*q0 zym~n&&-e4~bHTaE>uLV?^*%Wd{u*A+i@%D`2j?d*;|sxs$@6%*2>u*iE{Z>kF9sJU zPvhkh_)~bfB>p766kM7-hOYouBoE-_O8EVFxiWqqzA9Xe+>Mv3<9FfZ8u*>~T5xT0 z8@?V~pWK9(8{jwM<%akT_(pJJavff7f?tc5o8s5to59V=RruC$8*&L=Zi`=xm)qeN z;oHL<$oY7=BYqxU?u4I&e3C4QmrvnK;N{c!;`lT0S+Xep0(_Ayh?g(n3*hC;`26@Q@KrJ| zUcQFUgO{)4bK`HoH_4p%+wdJS2VTC5&yJT9@cla3@b|(A$*g!e5k3oEPK?itzaLIQ zX2L%NKTKxC%a7n+!OM^0GvFVGpCHrY<>dHucsT_=E&eGuC7A~QEc_gq8ZSSOPlcD$ z;8WsXgwv8K@NznQa=e@#{{;SJI0N}8{&n~bG8tZe6Q2|>XTm4JzYS+56XWG9_(XU) zD?TCqT{s(=0RI8}A^G?73I6Z@V>2gX@!<@NxtEM!eh*zX9I}ZcMJj%T4fW@p4oA8hkUj zIk^ho8g4@_!OLy&i}7+h{33jNxC1#KFL%Vx!^@rUbMc+wF61nHPq-I31uyr;PsYoA z@RRWU;Qr)zygUFu4lfVHkHrs$hmfQ2@=*Lp{Ll>l`+5HZIfT>?`~UPm;s=MF&x!qT z?goXOcd;MA-N3N(F7_k28xVHh#eNib{lm_?*pKF}U)XsU`!U@04Lk2*KbE^bVdq`! z$8py??7WNpc!@?%IW&cd?(xUE8qpF81@eYZG?f#eM;It;5c{*e~Sn+pzO4_KUb{ z6?Wdmeld3~!_K?dFX665*m)QGrQ9_SJMUt@jJsxG=UwcVbN5Zyc^CT?+%*k5?_$4_ zyCz}hUF=tJ*EsCFi~UdBH3~cLV!xWZufxu}*stNPVc2;W`?cIP2s`g$zmB{5Vdq`! zf99@U*m)QG_1t|GcHYH)19xABop-U{$X(sA^Dg$AxT_O(-o^eG?rMjfcd`GKyINuA zUF!F?ka?xcd_5gUHP!{F82GlD;IX&#eP3`Wy8+9*dO4o zOxSrB`-9w-4m)fjn z?0GLdzrnrA!JhZR^PAkO6zq8~Jio=giou@u!t>kQs}SsYFFe1)z4F1H_rmkL+$$IC zc`rP_$Gx(_p7+A@``jxN?0GLdf55%c!JhZR^M~9k73_I0Jb%Q!lEI$$!t=-6D-rB@ zFFb$3z2d>1_rmk1+$$FBc`rPF#=WA!p7+A@=iDn2?0GLdf5E-N!JhZR^S`)PDA@B} zc>Xu{3I==L3(sG2@6%wb1qxr06Lh3646{Qvu2xq?0Kh3D^ZKPUIy^Imu!k^4Eg@1FO<^GMv! z&VBd17oJDvem3sA=e_Ve3iq>e-#zbz=TW(zh5PP#FFb#j`d)^DrV{rcy?z`u`@H{5>KjyxB-V4uTaX&rx-Sb{}9-I5= zxbL3#!t?jJpO*XXc`rPV!~Hbech7s_d0g(N=DvI03(wWRh6La6a|L*yC{yKvD?j^w!@i~8qe}c!r?F{&PxSbJ?j@y~=Xt6v*D3(J3Af;w{zeTaXTme4sPedBj9#!{4LK**?I7PaXT;m2DkI! zuW>s+{ts>!z+d6^r}#_UE{Ok)+lBDIaJw-60=J9c&vCmb{tUN^;ZJe9IQ|5;OW==j zyCnVyw@cv~_ zyW_v&b`N|9Zui8u<90868*cZ;x8immd<$;(#W&-2KYSBz_s2Kl_5geXZV$xQ|@!7cjH9iZsr{ObkdpiC-ZhwQ%!0m7Gxc~n)NCf*k{M$_bKd@)u-{AK5_;lQ! ziBH4rS@_quJsY2j+jH^deGqSp+lTNrxP2IJjoZKDt#JDY-V(R}z+2$J zD|mI>zKU1F?Q3{d+`f)i!R;G(W!%1rSHkUEctza4jaR_!J9v5AzKfT`?R$7x+`f;O z!R-flY21E@m%{BwcuCxTjF-UeCwOt(eu@{v?PqvV+5 zjAz5`D0o)fj*4f&?RW9axE&48gxk^ajJW+Co&mRG;Gf`jO#EZqj)kYk?bvua+Eg;jwW$ zJsu0UKgMI?_9u7@+|Gc%huazP=(wE;kA~Zs@po}M3mz4>v*J;3I~yJux3lAsa61Pc z5w~;V@8EVWJOXa##@{mSJoLXzJ1_l)Y3HL~GwuBJKTNv-{fcRSO21^<1?j(;b|LyN zrd^nR!L*Ce&zW{n`We$MMn7fR#px$Zy9E81X_urQG3`?HL#ADte!#TL(D#{kS^6H+ zE=S*G+U4mxOuGVon`u|1Z!zsk^i8H+nZCiatI*e(c2)Ws)2>EeW!ly0D@?lveVJ+3 zq%Se;TJ%MxU7NnZwCm94nRZ?J9Mi5xpJm$h=`&2b0ezZjH>6K7?MC!Trrnr6!L*yu z$C-9h`WVx0MjvI`&FMdxb_@CsrrnZ0!n9k_zccOD^kJsmhCal!+tLS_c02k2({4}i zXWAX;eN4L}y_acsqW3WE&h&1k-G%;*X?LY}G3{>jPNvpm#9sp7eI6-HYDF zw0qNAnRXv~3)AjPZ)V#4=uJ$!KfRG@51= zEd3MH9!D=^+T-a3OnUD%YJ(-@%w5QN>nD$h9Hq-u^p2f7M z(KDI$bozUy{S7^XX@5(97o6+f_wn4b{pb77vHkV>>$3g#^WVev_rrg0+uuKbpKO1> z{e89l@8f?5+y9>aceDNP?|*08KQI2du>JGppCj8pkN&x{{qyUeQ`7-G^y! zqkA*$?Q}1uy@T$_w11_0Fzuamcc#6I?#8r#qq{Qg-EAEMhb?Zb2%ru{qJnrR=QTQTiF=$1_TPr3!uK1w%d+Q;Z-O#3+9 zlxd%!n=tK@bYrG{if+WTPty&V_8GbX(>_brXWHlJdQAH~U6*NJpzAR0i*#+KeTlBc zv@g>&nf4XB2GhPuS7+MS=xR*+I$f1%-=M27?VEIErhSX9#I$eI6`A%Ox&qU_OP6Qb z_vms=`#xQkX+NOLFzttQX{P;%F2%GT(O#3-qlxe@9i!klK z=)z3p(D|75zjR)v{g%$dwEccqZrt|!XSs0O z@3-Z|ZNER41GoKtUUuB}`+wPR+wT`<#cjX8m<6}}eq?6c_WPHaaNF;9X2fm3Kbirz z{eJ2vxb62}KgMmpUz;Ac{r+w`-1hsyX>r@{AE&`>zu%l1xBdQfD%|$_*(q_`?|-Mj zZNFch9Jl@cdNSPh`|(L}+wb2e!EL|a{}FEc{6J#d_W6WFxb5=~331!!D-z(g&u@H) z+dd!i0dD*JNqpS)`IdON?ejBnaogu};^4N=|GbaeK3^0Yw|#yo7H<1|R7~9V`KuVX z?eksl;kM6@MaONQPm6}zKL7SEZu@*)RNVIYy(qZt^MR3Z+vg7>;kM5=M#Sx0d|&?^ z-1hm*2)OO@pFYoN`+TX-i`qWF>hq|!&&T?_tL^i*K2K}=e6P>z+CD$*^T4*xC;Pmy z?eot*&usgAwa-i2KELhr*mf~~-+bQNE{^*=xm^PHd3C!a?(^_=DctAn?b5i<^V?-` zUl(AP#eE%tT@Lqk2X=Yf*D2T)a9`J8SHyiCgk1^ubrW`F+}ByyRd8RIVOPa{9fw^F z_jMn3b==p9*fnrpS7O)1eI1Hj3-@&^c5U3(x!84ZUl(K7#eE%(T@UwlH+Fs8*Xh^| za9`JBH^hA%klhIPbwhSz+}9b|O>keAWH-fq9h2P*_jONpbKKWS*)4EiS7o=veI1tF z3iowec5B?%dD(4nUl(S##eE%_-46G4XLfts*QwbZa9`JEcf@@ioZSicb#r!S+}GLJ zU2tEQXLrSY9iQC|_jP}Ecih(r+C6YzS7`UdeI26R3-@)4c5i$euY0lk;9GIKFTMr0 z`{A2$yFb1Ow+G-GaeE-X0k=QH*W>o*_&VGkgs;WzFYsS*`%8QcZV$#+bm3 zSK{_Cdn@8fmmzCmeIKv$Q{4CQIt${ykJniU_kFz1!np6_br!*WAFs10?)!M1#cnx7@ zK3-=D-1qT1OX9wd*I5epeZ0=nxbNe2mce}=ud^)f`*@w@aNo!4ERXv>US|c|_whO_ z;=Yg9Sqb-jyw1wF@8fk=!F?aEvnuZUc%9X7-^c5$j{81dXARu<@j7ebzK_>g3%|(w ztemy+3%Iimejaz$#n0i+diYt~Ss(X(yv_!=@8fkg#C;#Hvk~t5c%6-L-^c50g8M#R zXH(qw@j9E~zK_@09QS>^&K9`u<8`*geIKv074G|Zovm@-$Lnl^`#xT0Tio~YI@{sC zkJs5A_kFz14!G~*b#}ykAFs0$?)!M1opImC>+FL2K3->6-1qT1yWzf%*V!HSeZ0;d zxbNe2_QZW3ud^4vjX$5x-uPDB*$3Z(JNx3Bac4h#6YlJfZ^WGg@C~?gAif@Veul5Z zouA`tapxfX7u@*;z6N)GiLb_;gYi|ka|pf?cMio@;Lc(A&$x3qz8rUsz?b39k@!;F zISOBbJ4fS-apxF(5$+s||Aafo;R|u+czglwoPhs`JHNu`VB zDfk@RITfFcJHN(f;m&FJOx!sg{~mXKgU`U7-{St?^^|{A=!i&wcm2=efVGrQGw^@6?C!cusv8 zd&`-ghdwme_x{i9dG6GQu;!0pxeAlzPqe~#O~;Gg04T6`dG zufqr6_IkWOZug^g_dIuQVBh;reIw_6c|3a)-UqigYj90_$D|l7hzKU1D?Q3{t+`f)i!tEP)MclrLSHSICczN8u zjhDmiJ9t^#zKfT^?b5XFp6AYc?0es--{-s(k7qx?OXBuJyaaAP!i(efW4st{Kf#OQ z_EWqFZa>2d?u^2| z_nmrF&NK0N_PcmS+>VB4!0qVxC%F9{{xNRHz|-S)OgtTK$HLR%c5FNiZoiMG#_c$G zD%_5Xr^M|PwCJvvJUNeNe}E^$?GN#!xSaq`g4+r4k8nE?o*4hH@kDrH z_n8UtkLV=K1h}0P{}8v6;UD03d|G$Ub7yk)z3@8fnF zJT`8p#be=iIy@$Br^jR9_Q&{pxcvzp9k(;!(QrE>{w{7urFHi_cV=SW`%XPG=TUe( zI}08ex3l7ra620w5x2AB@8EV0JOXa##NX!p|JPkR7yd79=f>aQb{_mSZs*1S!R=SH z?w;q)eC&JQslViLoO*ut3NSqn{qJDk`=7Gsxl{j(J*Qrfy%(I@h4AONT^N6c+ePrF zxLp)~g4@OL$GBY_e}vm5@Q1iv5`Tc(_i5cd&z+^%_r6mv&G|hZ&n|=C#qF~A9o#O5 z-^T6o_$}P7fZxRJiueuOu7qF5?aKHy+^&LO#qFy272K|dU&ifAwCKK& z{34HM*TgU2b}jroZr8@o;dUMTEN<7u&){}F{4{RY$4}vQ1NmiS@ZZiOGh z?bi4~+-`#(!0op9e%x+{@5Al(_+H%JL+kE&?(D$6_nmr2&Uf>8b|?Hd-0qC;!tE~j zPTcN_|BBn)@Ey3_9p8@IJ@9R~-4ox6+r98DxZNAyjN5(iO}M?0*4^{m*_VCqJN15? zZ{YFl{`h*_9)PdI?Sc4O-2M#z1-C!P*WmUbd^K)=fv>{tFY%SQJs4ks+e7f5aeFzf zyXU!cDEr=b>cco+#^c$;@uj#u0$+mLBk{$!Jqllh+oSQHaC;2C5VyzT3vhcJ{v&RW z$LHhr1biNDe}(^m+jD8%JiqFLDukr73dm26i zx2NOZ;r2K9xA=dJe}jMPK65($9X*3N4Y$9?zsBvUwCJ{ydZ^HZF_GY{{Zg0VR;r3R% zCvI=Ud*JqVygP31z`NmgS6X+^bLX$@d*7*d;c=Y$PWE;&JrBKeu5;&uyKch7U@@9cZu zsUP9IIge-mfj7hLKk=rxeH3qk+sE+6xP2UNgxe?ZhPZtaZ-CpU@cOuY8n1`jXYjhX zeHO2S+qG%kJ=pPwVb^?!3jm_nmq<9>=NQX73Ku^U%u%``*9Hp65=z40}%f z9($!Zx9{VnaQgvX61N}XC2;!@UL3a{gWGTL+_?QOo(s3%;yH0ULKdFi z#O-(R?6{qc)^h~s-iye-_nmqq&a<*_N5-?@b`(4_Zb!v4;r6?DM%<2uXTa^~_$Rpi z9{w?I$H3F$c1%1SZpXsY;&vKZch7TYZ1%nH)Kl{~PW^rM;xIiAJyo#p{kZIT?$lGV z=hWk|mx6OUKAs%6KfsgW_J?><+)jWe!R>_jN4T8`PmKT9cp^Np`^<#+M|1)o*T)IY zy_Y1o@1CBN^AFj#li?rWc5*yEZl}QG;dV+qE^ep7;{2koRfk(jYocP-uJWopJV*ZQUZ)n{;&z-s1_r6ol!})6-&(4eggWLJ=SGb)Y ze~H@#@V{~UQ~WR7E{MOt?Lzo-+%Aki!|fvYQ`|0!Kf&!{_+#9DMC*J?z`y{Qq=ee^1``&lz4LLu-!7p>GcMz2ApD&z<@v_MCcO_BL{E_ro{fc7J?5ZV$lM;r2j$EpC5?|AO0} z<7;qx5WX6>zra`F_DWiJ&vWOO?0es-59WLYk7p0Tf5z>h_;TDHhA+eI;rLSA9)T~x z?UDFm+#ZE5!tK%cPq;k>Ux?dd@dda&4*wCi=hM1-o;%00?|r8}f%ADhp8Xa618z^m z=i>Gxd=73;#%JU96nqwLPsL~A_Sg9LxIGP@f!ovZ?{NDY{9D}qhSuHt@7z76_nqJ3 z)BWf9c=&hB8Nt2Krv>}o|DHY1o%+}8IrW+BP37F4g-^ll+4yAKo`X-q?Ya0w-2MUo z3b*Is6L5PzJ|4G!#K+m`xxFBw~ynEaQg(_5Vud_4RHGuULUvX(Ykw{J5RIkeW!kg^SV5qeHO2S z+vo7wxP2b4h1(bKnz(%tuYuc_@anjI8Lx)hSMaL1eHE{Q+t={QxLt|X-Sgaeoqg{+ z^&6a5?Pg_pg@20Mf8zyk`z4+qw_oA; zaQh!TFK)la^WgRyJU4Fti|4}aoV4zq=gzn6d*7)?$jbAfJf8gyo*lO%;@NOJ5}p;e zBjZ_cI|`l|x1-{jaQj_6BW_2-GvIb~{1e=M5C0gq)6=?po;zc(?|r8plk;>uo*fHM zi`%jBG`Rgfo*K8~;HhvsE}jy%;r54kQru2}C&BH6_(!;%nAY9% z+?j}d?>ql<&J*!?iT&p>6Z+4glQ0wDc2fL9+)jpnfZNIO__&<{kB8eS@wm913Xg-^ zsqy!5I}IKiw`0+|d!9SfvhRJT9+Ss$>gm`^&-6U>7{R{xKW5K!r~V#$PW==1qH}I% zz@y=IM*Lme&V)zB?aX)-+|GhW#_gqIJoWIS^ z^PzMu=D)a|8-Ih_dGOb`ofrQHxAWnza63Q#61NNBf8+M2_+PkP5PyN&h4AONT^N6c z+fQlTJ=LyWUms_^U$vc``)k2p65>e8hcK?3VT;M zx2xh;aJw3Q8MmwBmvFlVei658;umnc7JeSLYvbo|yAFO9x6jbJd!9S%vhRJTUXSzB zJf2-2KZV;3@RPXR5I=$2jqu~R-55WH+fDGJxZM>06Ste;f8cg={0MHhz<miS@Z zK1A#8dG2h*zW1GaYt9eycy=570B*O%_v3aud>?MN$M@oP2Ye51cf@z&b|?Hd-0qC; z!tE~jPTcN_|BBl?Xx%-}o!!{?zEj`M<2d#1?Db%J9{RRm-}^n;^W3R#WzVViVs8uQ zc5i$$Zuh}A;dWnqBX0M@H{f=Ed_8Utz}MmSKzuE3e}?~p+iPguJV0;B`55a%N?Vi+&PVX?>qJBoPWpT+27#b;{P@N4gRhB%<1@d^bF=S-2NW_ z8niU{s|wA+l%l~xV;!3iQ7x?5xBh+ACBA0@L{;U93P6?KjTAidoZoL=ectQ z``&lzD>?s?$Fo=AU*Ps?d=PH0!9U0CU+~Xxdo4Z?x7XnVaC<%8AGbH){cw9D-WRtw z;eBwsH?6zpxpOo7-goL-IPb;d*<10RxV;VUf!o{h?zp`J?}ppI;$3ljC*B3Ocj29J z`!~E3ZtuoB;`ScA18(od+v9dST6fQL=RWqm@6`8m-j>I+58!QZ`yk#Lw-4d1aQiUc z61RWHTj2H)yg6?Ffj7hLKk=rxeH3qk+sE+6xZQ}>-SgaeoPF;*^@co-Q$NApNv7wa zHwgBTzzL!RzAoS-cKzpTle8_IbP(ZePG_;`T+n25w)%tK;@% zyc%v-rFHi_cV1!N`%e8T=T&$-`x;&ux3A-saQg;c5w~yR6>$3&ULLn^i7HQ{r|!JOysY$CKms2Y52vPD<eeXN<1e_<~@$7{7N4T8`PmKT9cp^Np z`^<#+M|2Wq0^ClDe~8=3@DFf1IUXOkQ{eG%J0%_$x8u;dd!9Q}vG0ASo|^Obc|1D} z9vipQ;<0c$9Uc?6)8jF4`(yk)-2McQj@udVXtGWL+7;-VOuHg| zgK1ZyuQTn+^fjhkg}%zPtI}7Pb~XAk)2>cmV%jz6i%h#FeSvA858OS^owc~ zKbZEBz}@rQ*_?accj_%T|D9>Kqz^OgR`emJ-I_kgwA;`Jn08xwKhthU?_=8S>Ag(5 z1HFf7ccgbS?N0P>OnX=0?s@L)%suZr^)8(6WZGTnUzv6{dI!_)PH$)0J?L#ryC=Ps zY4@VHFzw#-W~SYT-o&)~(i@p}KY9bx?oY30+Uo*$&vWMh?s?y-59E9;)BcS9g=v3I zuVLDQ=+#X73wjmP{*qqFvC)2Z;_N>6&^V~Uwd){~IQ#qf>w7;gmXWG-~8BBXR{TzQA-Y`^~bb!|J5<3a4%e*O0AwC&e>zpmT< z?}Pt4uz|f2F%I?VWU2 zroD^q!raZ=!|WLJUb+L*-bc4*+WYBtO#1-cmT4cP+c51zbZe%4m~O?if2UhA?IUyx z=AX=?%%(vfqnj}8<8))DeS&Vpv`^9vnf58V0nw6}lSJzDieR+SlkRO#3=rnQ7mkD>3bxbVa6pi>|=5Z`0+O_8qz$ z^B(g)vvkl8=u%AkAzhMbKcY)8?Z=V#jg(D|75YdSB}enaPB+W*qInf6;c7t{9pc{y?0@Bih%ZNFcb9k>1dVm93G zOZxrJ%((6MM>FBJ-%rhm+kXEw18)2M+D~xX@9%z$+kQVdJ#PE`<8-*~_nXt=w%?yl zgWG;TJ2me2!TtVv3f%Vl@yT)9@82iGZNJ~26t{hTAPH{!e8NY#?ehptwtxUUnjtKhz_#IB0_I+W^k4W_S)v1{VKj>fKq`??#uHty?m>^iuw>#^(N zz7EK)ho9kjf4e^J>x`PvO_{z9%Wj7Ix-Gjo?(4kl7Pzkqvs>c6j?8X_ALiF-x5j;) zn%xHXb!~QA+}FX`?QmZ=*MaWH^mTl8C*0Tl*`0A;Cun!UeO;m5758u~!sd@XK&j{kz& zgYY%D{RO@nx4*y%Hac+pF*| zaeFoX1#Yjw2jOe!byDz-!_5 zMZ6|%U&3qP_GP>}ZePKx;r3O$DsErHtKhfkJIr#peHSl_+xPG?xP2cljoT0KQn>vP zFNxca@DjNF7%z_7Pw-;6{S+^XKc`Q|Cpm8W`8~;S+t2$+ ziraoZP!ins^MpRaZ9jh~G4AIU`FThQaNEyM`VhDMyrmCt+s|i;kJ~BvyqI{n?dLzm z#ce+?Dh_V@`BLxWwx3588@K)Zs#v(~=Uv6b{hTa6e=9m}`*~f_aNE!KdKb6-Jg}&^ z?dOL@!EHZpEHZBU`DBrB+s`wLh}${*Tprx^^U@;Ve$JYo-{$AE*?!)epX+A(`EY&? zobBhy`MGg+0e(Gx&YbP%)%m$}wx4h3=h)eP9-g0jXZ!hieomh4=k58qdbXd>=jZSh z=hs()>E{C4C2>DT&@P4hxr26T+|Mbr%iw;lp-$m3DR9&$+Z~;C?QqT@&|nH0@gW1wQA`u8sRSopv4E z&-JwH;(iXOT@UwjLmSWynSPF`-3a${PwmFIpOb1g!TnrSyD9GHu-eUVKeyFxj{m{$ zgWUr6b7Ae4xSu0yx5EA0S-Umv=hU{P+cEvzT)RE)=j_@Ya6gyV?uh$2zIG?v&;7MK z<9<%C-38yp?}ObH_j8DQ(Y={lxNrBtH{*6+d=qZ>!#Cn~e|!UO55U*s_CS0cZhwZa z#qH1WUvPU6z6Sr29?V>c+e7dbxIGmA8MlYw%W-=+z6`fV;7f6PB)$ZiVRC*TX{h0L+I{S!V0 zw-@1~aeFa73b&WwBXN5vJ_5Iw;lpuzIX(=xf5wO6_6mFmZm+}#*4lUye@8^!|UModAv4mU%+eO_C>rVZePM{ z;Pz#_I&NRVtKs%lyefX3zQL@7+c)uwxP1$+fZMn6^0<8mFNfQA@v^vm4=;n;_wmxW z{Qxh8+Yj-Qxcvw(fj^<2GK=E&GrS0HKgSE>_6xiaZvTZB#O=TFPjUMtUI4dW;rVg< zA3Ps!zsB?8_8UA8{+9OVdFI4zfBt6<-1g^%X2)%RzGybw_UDmi#ch9nX%^h}=bdK8 zZGS#$CfxStsb<7&fBtF)+@IU(&x1{m+y4C6bhz!$n@x+`{(Rarxb4rgO^w_B{M%Hx z?a#|iiQE2s-4wX(&*M#w+y4CCWVr3m`%Q}f_w$AMIj)Iue;%u?Tr~MvoXW;iCI&S;( zx})K?Ki~UZ-1g^zN5yS_es~nz_UDa9#%+H-c_iGQYwpiWkAU0$e06`0y6w+n_vfzL z{`_`-PP^^Td-vzM+x~obe-6Cu&y)A(#@qho&!>{0Wb^J1J*T65~c1`>uZr8#u;C5~NJYJWs$2^1E_3_iV-2gv@+YRxP zxZMapf!mGo8 zUy9o!@g=xD3SW$mp~o^8;`TUv0d9}Sf5hzx_{3ZIAD6Y(E#dlEhuwoyd%Dk z-p_1@+XwKrxP1_BgWHGj*0_BbZ-v{x<1KOf2;Ks>|G=B$C+L&RhPZtSZ-CpU@%p%Z z2Cs+PXYsnYeGadK+voAxxP1Yyh1(bLnz(%luYq5ouQIFR_BFf;ZePbM?aO9lRWF-^I(~_C34|Zr{gC;}7Xa%o4c$7%z_7Pw-;6{S+^X+t2VK zxcwY2jN32pLb&}GUJ!pxzhUOV?SJvyxcwH-h1(JMoP(UW{SKZ3wVQ< z!tHo?O5Bc*r@%j?6EKtFc0xP}ZYRP&!tKO(V%+`+PlVe^@PxRX6i%s9B627e#7)8eslI~^Vix6|V>arIq?X%oeO`<=bzZQ@qckU5B>(X^Wv{@J0JcJZs*5e z;dTN1C0>v&#C(C3Ajqnq=-55WP+fDFexZM;#iZ`cQ zFpuDNOZ<1-ZiOGl?bi4q+-`#(#O=2D0o-nf@5k--_&(h3fbYfaj`$wDGu?%`3%9%C zJ8`=k{wr>G$9Ld%4}3dr_r$m1b}xJ@ZuiEw;C3H;Gj8|AH{o_ad?P-99>`pW+n?cU zar<-p7u+6%ufgpv@YT5eCB6!`2jeSodkDS)A4!j5F2?QA_#)gMga3rvWATN!Jq}-h z+vD*caeD$jAGg24=i&B5{0Dp*J)P<2huLxX95O#|Y+AnmL)_r=$)@9;$KYK5Iyl$A z!992CQ#p6)-{Mo4_ILDTragn6#I(PsCo=7s^jA!K7CnJ!&!)#S?K$)~rahM)%d~%> z$1v@A^k}9%pB}}uf22n;?FIA*roE6J&a{7`hcWF%^iZa~m>$Bkm(YWm_EP#wroD{* zf@v?O2QlrR>Cc(=3i>mqy^(0!TqTDlL@UPt$4+Ux0F zOnU>}lWA|Hdob-yba$q`neN84x6oag_Ex$J)80mRX4>27PE30T-H~bkN_Sw|JL&dJ zdl%h~Y5zvIW!k&xHcWdD-I{6drCTxWeRNBvy`OHuv=7kDnf5`t8Ph&QH)Yy~=_XA3 zce*jtK0-HQ+JDdunf9M_1EzhHuFtfO(e;@2ak?(kK0()E+9&DSO#2jFi)o*xYclOK zbPc9`mafjU&(YPG_IbK0)4o7gVcHkz%1rwbU5RO5rYkb-D|7{>eU&cHw6D?SnD%wL zEYrS0mtopB>C#O57F~*I-=<44?K^Y{rhS(#&b05*#hCVex+v3rKo?=!g#&lb^RxWl zH#H0X|Nk&KL+j^)bMNUj*mLUV*{jaEeF481oQGbGJ@>tTi9OGqdR6wE`epX2aBg40 zuLkF#S7y(B?_XojbEjU3J*R%1y&Fu=L$4U@d;cbTo;&pl>^b#Y?3L%-zK!1r&O>y)1i9{T_SwnVyGUCfN7>1NJ<3>ZRFp>JQl~#ku_me;k~LUXnfcz5j$g z&z*V+_MG}t_MS04550J>@BQcOdG6GUvFFrZu=f|!^U#Y1``-VXJ_Z)AP^^2K(Osmp#v&`lswU^|$Or$o>DXvz~`uAlUc* zJM4Mx)bq3F)FZMNiRpRh`GS4#M`q7+r=FKRryhm9s7%j8&lBu>|6TSxcj~#>bL!F9 zi_Y{s^jyKd_upgBbElq@J*OUny_ihTL(dWHdp{O?o;&sI>^b$=?7h$QJoIeAzW3v> z=ebjl%XwDz?Ra<=+>Vcb5S)jenLYQt{~>#xJM{#dXJX$@h-bv@M0n!hJoF6gx$pgt z*z??}C*k}P_U)wj$GDvgPad3yo}NATy`O?T&z*Wo&eO4Pr^3_Xc4|CLa2|RZ_T2yP zzWbd2cMng;OwGBS9{)Hv4?Puo?tA|e_B?m$88}bLzMT``$0Wp65>eQ_d5zZx_T11?QnBV9$N;7iQ0Mr(T5fqQSk;KjiV<_kJ<< zJa_8FIsbrty98b`I1fEOd+vL`6nmaK_0pV|3GRg+kH>f4`(@el+^Lu2JTCiodAve! z9(u*#+{e-5@VHLB5_^@Io`?Q^uij zHxABy9Q{51`A)qFdrg_1hu$nW_nzLI^XU9@>=t;-;5_tJ!MTs4x8^(=k8iiZ+Xm;M zw+qgF9KAi~9fEtIzso=0eeZW<&vU2ViSy3Ez0kV^=RS_!mGf@Fz0jlb>vZ4y-P!Zp zsrTT#XK*j{UctGKqxa^#PjD~vzQMVVqxa*ye{e7K0l~SCqYvaf3coM*XZYvAdFX?J zb00_lg7Ytfd!Y{w&V3wx2-@|?HN5VbVBjTRx@8F*65pd7-x1aLFFX#Hd zxaayC+;jak?z#RC?z#R7_gsI8d#?YDd#?Y5d#=C0J=dS(p6kzW&-JIc=lT=ebNw;y zxju~l{+>JaN9;NEhqzOJfIId3xKqD}JN3J`Q@?{d_1m~pzlA&Xo48ZIfjjllekkqfjjl% zxKlrdJN2WuQ~wip>VM!){Rr;Vf5)BrVce-7!kzj-+^HYHo%(*f3Rrz72QkTXCnp1$XM3ai_iscj_B)r@jGq>g#c* zz7BWlYjLOk3+~j{;7)xt?$lS|PJJcr)K}n6{b$^%FUOtwGTf;z#hv;R+^H|do%$l& zsSoFW-+toU9)T~!?UDEb+#ZGhh})y_`M5m>pNHFH@gHz|96lGf$K!KwdjdWix4*(? z;r2v)CT>r{zsK##_zc{hf`5nGQ}J(c`)m9g+@6L{$Ny`58a|!=+IzZ_bDxK=#s9r{ zn&*%7ns|6#8$ZQ;_q-RL*Wvz2?z`u`@VqYfPjKHo?}g{}xPP4c?s+dfuh0Es+;`7= z;duk@ALYJ#-V4tga{o{6yXU>|yb<^R;J$m_3(p&K{|NWp^Imw~g!{j9-#zbz=S{hP znEUQ|FFbF?{X^V$&wJr{bM7DHzI)ya&s%W+0QcSVUU=S;`}?`?p7+A@R@~pmefPW< zp10=yUhcc+z3{vZ_xEt$J@19*ZMnaj`|f!!Ja5PS-?;Cd_rmk`+~380_q-RLci{d` z?z`u`@Vq1Uf91Y=-V4t=aeoK*-Sb{}-kJN`x$mC$!t*ZN-^P9SyceE#<^ERgyXU>| zyc_qoaNj-eh3DP5znS~)c`rQg!Tn9#ch7s_c~9kYXxyHUkHYOA@sYT_03U(d3-RH&{S!V6w-@0Fx!M)Ja@%!Pv_qVa~GvFEu{-_7}+;9lr^gL5B8-^Y0xejWCH{6KIX`oZAb$I%aQo|?zE z597ZF=b;}7&V3yH56)BZ`1YUp(cnDvW5KzPqaWuyC68~Pz)uF}p`QxQeH=XnkL%P= zvv-E+dFW?@bMNWNd3>jSj=l3t&qKcuoO@4C#^XEni|k!udLH`a;M{w9QXb!_Ut#Ym z)AP`i1pD5<#-8U+{W|A2f_tHV#N)f~{hRE0?$mE_o|t|6Hhw2K5B+X%?&Ii*cwDD` zkG=a$&qGfb?0f$Kd!9S>hny#1-+qKY4$eb=5}f-u`iDHOQ-8|dGp6UEe-P|@|2cb} zJM|Zw$7kRE3;#Pf4?P}x?tA|wd!9S>SDeRX-~I=G9h`?AhduYb|Asx!o%+9=zt6t? z7LSnU|Igcb9(ru{Joo-P?0N3gBXS;#eLE5!IXDkJCVTFCKMH%EJM|dsIrXUQz034G z^!I{&??+?LbEh7i^XTl`@A=OQ&O?vpp8tIA$7Fi$)MIh}E_-%tJSuL#kH-nlLyy9q z``(Ysp65d)A7>Y3Tg!t^}!r@_AWv$E&8Q-8vqQ_sd;cBbc{KMwZ2pMyQmo%$p8oO(|7axpy* z{b8{0{oL$%?$jT!=hXACmzU{z==Xzt@8@IBbEkffJ*S?Zy#h?nL%$pBd;e4RJa_7M z*mLRy*(=2KJoMYazV{2W=ebkA#hz0y!d_9P=b_&W_Pt+>JmtxOzr+$?^r(T-9GEC1yzY^?wzbt#6JN3)#IrVbvUEk5>rJL%+zL z``)j}p65>e0((xq5_^@Io`-%u*!O-F_B?m$=h$=VRoOesxm^vf9-N1MhCTPaUxPi* zo%(6^oO(_6YB4%+#eMM0$m6&0}P?(XjH?(XjHM!LJZOEADh zNhMV5ZUG5-$M}0)=fge5d%oP``pr4F=O}DBd#$~mI-GOesbAonQ?JXp^Q_zT@N>9b zA3uxR4e&F#-4H*G+l}y#aJw=7A#OLpPvLe``~%!>hQE*7&GGkey9NF(ZnwnW!R=P~ z+qm5tKZ)CI@DsS*7Jm!3+u?8Gc63w{*0yW&T1 zyBmHOx4YwqaJvV75Vw2c2XMO=z8|-HndmO$Rx5wkFaC-v261OMfD{y-fz8tqF+)p7e%yc%wQhF8Vy z&+#g_eHE{a+h5?7aQjQVB5r?$SHSJB@$$I+4PFknzs1Yq_IG$0-2NUfjoUxqrEvR4 zyd-Y_gqOhWpYh_j{R>_Uw|~Wp;`VR&?_oW95zcwu{eN)Ib*EmKb58wF&i%!7J$j*V z-u-`b&UL3=kaJG`8s`eIZePc5g!Sn8Ip=xz|HC=goq9gbIrW>IyTx=pdfsr}{kJ*i zx>L`?Ij4SybGcc!|Hbcy_2{`c=Xv)h$ot>*8rPkAPR=>?dpLJ5)Ai^%!g=@K$2r%X zdUnn^_4_%OjdlA0{K2puJuBxt@BW84=ekqR!a1k@Fy|67U5}nQoOk~toO9i&XX2bw zf0T2Hn65|97|y#tG3Q)&>KQoa)F0#A<4o71rw`}d{{-h;cj~Wj&Z#HiTvDd%(O(Yd z-Jgtet~>RYIOo)pb1ntb_2@5#^X`9=bFMq}7dYqCQ*tg9)Ai`-!g=>U#W~lVdRopo z^`|-a4Ab@KX~KE;r{kEda#4f~>} z4(HvUj&rU%^=CNe)L-D-i%i#}KON4y|0T}3?$lpq{VC4dui&Y0J3XEutVd7DInTR4 zBj;Rq>X}%7lJjIGR(%z3*IUO22rPsBOTyT1tM zTzBe4S$~xCb}{@B+%Arn2LRgRf0OvgK{)(J)-Kke%{eI5dmGLTJJ^Fo|^St}3a?W+9UXAs8Id50T zYlQXa_i)bh?yt!?*PVJT)@z4-(G&3co_Bv8&bjW?>#}|~|9^kZw(H^b!+P|8Ip=xz zH{hJ>PQ4-Pjl#a@cX)lzyT38#TzBeCSijAAyD8o*tVeGi)_ooQ7O(5nTX3!=)Ai^# z!+H0&;+*SFy*2A?!oKKj!@94dw`0A1*cZJ+Sod}Gj;wbI`=WOa>%NZOh4rpsU-WKa z-Ph5(v)&`@i{3M=`#O3r)_aG2(ffpTUq|oDdcUwQdjGKQ>*xbm9~kyU9~9Po9eptC zL&Co3L&LhSqYqvO`s=&y!#Uq_$I zdQRR4?Roh8upWIuSod}Gg{&_M`=T!n>%NY@g!QFiU-V^R-Ph5Vv%Vtii@q|f`#Sn6 z)>nsp(bt4^Uq@fd`ns?$`uec$>*yO;-x&5q-xSt;9ep$FTf)BRTf@4qqitiK)hMSmx(`#So&tiKob zMbE+epXc5GKIdF_>L0M4o%8l7{KK#w{iCq%>*(2dU8jDUb7z>YN6#A0yZrVYL>sP|Q=oxu^&%6Iq z&bjW?KVv-u=k3q&t6@EQdd_*?{a#uO${tEv(tVe&DbDnqqH=J|bsejA* zOPsgA!@m#f(O=}8=iUDU=UjK{KeGM;=k1^HpTm0ebe!|N`+wn_>rVYw*3)v{{tZuq z+rQ&~g!SmpbI$Yb|C4jBJN3UbKU*-aL#q7elP1!a^AiV zPl4O_;}3-O=*c(L(x=iUD#=UjK{2|4G~Q*tg9)Ai^Nhx6`#igT_z^@lj;)Su?uGfdZ`KN!xtKQ-rE zcj^yt&Z$4kx#yU!N54OucmMO8bKR-m$2q5-hI46|u1CK&oOgdZ&bjW?@8O(Ne}Qu^ zGF^|JAe?vqOPq7vso!PYslSZB64s;t8`j;Q9(UcT-(lUUXTURt_2{?5y8AQXt~>Qx ztULA0_)Vsrh0Yq*qyH1u-JcD2-KpPT-Kl5CbAQ#STDvb&ipxa3Hm3dU6THhX_umZVA`eW@0oTP`a7mwmj0G$m!rR7+U4o5nRW&G zE2dqM{*q}|qQ79;mFcTYy9)g|)2>Q?#Z_ z!nEtqA2aQ`^aZ9}k3P?|>(l3$b_4n>({4zgVcL!8(@eWD{Snh{LVw7#o6@J4b~E|| zrrn%=pJ}(C-(%V>>35lSEBYO#-I{)zX}6(IGVQkX38vkSev4_hr{84S9q2chc1QYk zrrn7?&a^wz$C!2(`ZcEAl|IU}yU|COc6a(P)9yhZV%k0FgG{>@eSm5AruQ@LKJ-4O z-Iw0WwENL}n09}9H`5+K?_$~m>77h_5WRzG52m*>?IH9wrahG2%Cv{kTbTB6dNb1= zL2qK(Bk7GydlbEaX^*DYGwm_-I;K6AUdyz{(QBCYczQL{okeG&Vng>&wU>x)U?3)nIxi7A-WZ(F3&V6xx75m18bMA}ltJya; zoO54XU&FpJ;hg*8`dapl4(Hq#*VnOcR5<6pxW1l!Bf~lO#q|yB8xhXAFRpK7-|%qG zeQ|vg`-X*c?u+Z2**7$tb6;HF!oDHlocrSXR`v}J=iC?9x3OUIrqi&1MKS&&bcqHA7o$maL#>k{Sf=Qg>&wU>xbFbHJo!_TtC9T zF5#T};`&kcbq?p;7uR27U#D=+eR2I5`#Oem?u+Zk+1DYQb6;G4oqg@YIrqi&H`v!M zoO54Xf0KP}!#VfG^|#p9CY*C$TtC6S*5RD{;`&MUwF>9l=eqOlu-|ifOV*wGJ9rDG z{Vv^{X}?D|W7_Z2O_}xwbQ7k1if+ubKcpKm?T_e&O#3w5fN7th>oe`MbUmhhj;_nJ z&(n37_652&)Bc#Q#k4=6YclPNbPc9`iLTDHFVoeS_7%D+)BcpM!n8l5D>LoS=}Jud zDqWFje?eDZ+F#P;nf6z7Ii~$JU6yHoLziLN-_oU-_IGqCru{u#l4<`ymtfjI(#4tf zPjoS+{WD#ZY5zhOVcNgag_-tmbRnkwJ6(`z|3MdE+JDmdnf70FKBoOQotJ4}qw_HB z>vV3WeS^-$wEv-VGVPo6T<(u>UBAux9cB~u-KG6rOI_UW+4w!4YPjF~@q0y;aKDG- z_ngY%elN=JU6sQ9o|fMOD~8*CZ>%Wp_sskrTS46Kz4^VmytwW6@bch(Z_n=q=D=;g zN0=S=dxw6nF*9!aJ;+SB-<$M%nXlls-{X84_j~Go5B`2UH{VC{IRQQoz~>wkWZmZ_ z_#6nIGvV_j?BeYA`4e^t+~-x;C2^l`VVA;v9)?{S_xTxi8QkY>*ky5_&taFteV&J1 z9{2elb_Lw$h1eBwpD$up!hIfzT^aZJC3Y3u=bhM9ai5Q3SHpdtid`M|`73q}+~>8} zHF2NsV%Nfb9*kWZ_xUk)9o*;5*mZHAPh;1^eV&b7ANTn;b_3k!<=72zpRZ##!hIf( z-5B@zJ$4h^=l$4Cai0%lH^Y6Nklh^j`9pRK+~*b9EpeZ3WVgb79+KS}_xVY78{FqD z*==#3&t$j5eV&uu9{2fAb_d+&McEy3pD$&1!hIf<-5K}!RdyHL=Uv%dai5Q6cf*hJ zyb`-RegwCB;D>R$Cw>UGd*KIhyElFSxBKAxal0?R54Zc_dvUuzz6ZAl;Ja~qAifK? z2jM$$doaEOw};@{aeFAf4Y!BkTXB0hz6G~O;G1!KB)$o^N8uZBdo;cQx5wb?aeFMj z4!6hQYjJx#z6Q4^;HzD<<8gZpJ`T6n;$v}p9XRP=aeEU!0=GBg!*P2HJ`A_F;zMzJ8$JZLx8s9xdj~!Uw|C+LaeEg&0JnGJ{c(E_ z-Ve9;;(c*@AKnMI_v5{B`vBexw-4eyar+S71Gf+3-EsQ}-VL{p;$3n3HM|RMAHzH2 z_Hn!uZoiIq#O*im4!Hd$-X6E#!rS5Y3A`7qEphujyajH* zk2lBd5AbHVeF|@i+aKahaQh>?F>as68{zgDydiF%#T(%EIlMk@pU3Or_658yeu=)! ztcHJ1UuBlZzox%omcVb)x0va0`!=2yzeE4ad=|Iw;;C_eK9N7aC>3t|^Nv#D{(K~V z{!%jB_UAPv#r^qC{`{!NaND0Zl^FNuTlw>^65{@xE`JW#y|_O&%%4l<&mZ&WnE7+k z{CQ~pTs41gn?Ik;pC9MXsq^R2`SbGpxqSZoJ%2u%NX&n)NbaU-YtJ-Ph5}v0gsxi(VnD`#O3>)+>d5 z(JO~_Uq`RPdeyKmdbP0b>*&>4uMze|uNl^T9laLowZp#Xb;7!@qt|7_`Mei8aeI30M>z%{C=v~6PucLQmy<6B9y?a>qb@U#r_YC`@_X_L2 zj^3N~K4D+Agud3`asqPg?-Tnhjm{^AHw?3urK+rF-y&fNfKTznu=N3N59E3kiCuFw4?MLtycoI4(vpk-hPQfgJr=(Lc3*t}FPc!r4 z&(NuvIq_%d=a^aX=jk-ejJTZ^&w!_+Utqq3zi2bl;xExJGt=O&(CL|}aXSP444#qB z#7v3Xneiv_EOb_8QrymlC&5e8WthL_`tP521-c^hJG?4gjd>NXLDytn!F$tvnEP?3 zz7KcmeL1(6b-N$F2e$6utqsN8{^pdknq~x5wgZaeExT2DiuKt8se*z6!S|;wy1`621br zC*#X;dkVe`x2NJuaeErR1h=Q-i*b7fz6iHx;tO$m7QO(tXXEp6dk#Jiw;%oQw_}1N zOxJbqGxUB!?=N(EKcV**I=!E;8Ta=%y`Rwg3!UCi*u?vTnBGs=n09(Uq4yU$y`Qil z`<xX%kt{3Jxx^9@~={jLvplgTuFHUP>U+DCHLhmnhdOxA}7dpM4(EAIW-cRWLg--7$EXLnIr}qHUO-c^#+s6MBE4)B6bvvfud!T_8;FC(MsKy`L~2?(}}bytwlk?fr$$>$vw9 zI&a|KU+DCHLhm2+eaiQx_`YVx_dz?pZ`$#F){gJXc6=YVB7uxa9k#_uZr|q9plkxB6q|8KN>W|^hC&NC^>G!hk`Q+ie zucLd;|33GG^S+Mmx!HyP+xRMT7E_<||5=}l&kW~$owz=aeKW#2_r>-3?3*6Wxi79S zVBfTG&V6xxA^WC=bMA}li`X|MoO54XU(CMA;hg*8`V#g{3g_Gx*O#(yVmRl%xW0^i z6T&(7#r5Uv8z0WOFRrg(-?(tjeQ|vy`^JWI?u+ZI*f%Deb6;Fv&A!p$ocrSX8upC} z=iC?9*RpS9IOo2&zK(q(!a4WF_4Vu<9?rQhu5V!9uyD?OaeX8EhK6(Qi|d=%Hzb^M zUtHhJzQN&~`{Mc*_6-W>+!xokvTtBG=f1eUjeP^cIrqi&?dk zeJA_+hI8(V>$}+3C!BL%T;I*U-r=14;`$!;^$O?Q7uWZ)uV*;tzPP@ReLccC_r>-7 z?CT!Rxi79CU|+Xz&V6zHAp5$8bMA}lhuGI8oO54XKg_<);hg*8`VsbZ3g_Gx*N?KV zV>su&xc(aZI)roXi|fbO*FKzcUtB-VzINf9`{MfR>}wm&xi7B2!M--(ocrSXo9t^H z&bcqHzs0^*;hg*8`U&>64CmYz*H5yqML6faxc)Z#nul}li|g;OuURprD^}{*$ z#r4zds~66>FRq_qU)^xdeR2IP`|5;q?u+Z^*jGE8b6;FP&%RpWocrSX1@_ep=iC?9 zKW1NzaL#>k{S)?859iz$*DtcKS~%yvxPFO!Rl_;=#r4bVs}jz+FRou&wU>tC|3Y&hq>xc(LU z%7k<7i|b#ruXH%)zPSDk`$~m#?u+Z+vae(~=f1f99s5dzbMA}l-?OiHIOo2&{sa4p zg>&wU>p!xuXgKG-xc(FSiiC6Si|aqLuW&f$zPSDi`wE3~?u+Zcvaet`=f1f98~X}` zbMA}lzq2oYIOo2&{s;T=g>&wU>wmH@Z#d_^xc(RW@`Q8li|c>0FLyZSzPNskeYwIp z_r>+=?8_O>xi7BYU|)`K&V6zHANFMr=iC?9Z?Z32IOo2&ev5rs!#VfG_1o;r63)3V zuHRu_=5Wq^as6NRWeVrq7uWByFJn08zPO&C$bX;nWeDfo7uWA$e|q+N&V6zHUiQDj ze$TltuHVQ0m)Y+*_r>-5+5ZyzJ?Fl-{s8-5WWVR!7uO$T{|oH*ocrSXL+nq-e$Tlt zu0PEFwCwks`{H^+_NQUL=iC?9A7TIV?Dw4e;`*cPe~$g0b6;Ff#Qta5?>YCy^~CH? z&3@0hFRnkv{%6?lIrqi&$Jzfh`#tBrxc&tDpJKn~+!xoAus;?1J?Fl-o|OG5+3z{` z#r0(Df0F&4b6;Ff&i)ka_niCUdJ6U@XTRtEx6jw}zem{bxhL^typB^($$C=%chISr zNpSlq{0ZEC8h;$OpTQr)?bLW;+Jq+nMn@xSa*RjoVrA zTezJKzlqz~@qchT2Yv&$bK=)=I~RTpw{zov<8~hWFWk2UE{lJO+vV^taJxKy6}KzkpW}8#{4?CHgnx?LmGLXMT?N04+g0&PxLpmuh}+fi zPjI^i{xNRX#4q4>E&M!g*T&D`b{+gIZr8=n;C4OyG;Y_&Kf>(>_=mXN5I=?6jqnd} zyD|PgZa2Z-!|kT{ySUv9e+Rdl<8R}33;ZN*x5Q82b}RfX+-{A(iQ8@PH*mWx{yJ{A z!;j;3d;Az~cfeo6?T+|S-0p-Q!R^lYVchP5AHwaf_(9z6h9AJ~?)ZM(?t$;a?Vk8v z-0p?%!R_AoZrtvJ@51fA_)gsJhws4c{`hv>9)NGd?Sc4K+#ZB)!R^8LX51cvZ^G@N z_(t3whHt>_;rM#o9)YjJ?UDFe+#ZFm!R^ubYTO=!ufpxI_)6R!hp)ix@%VDwo`5gI z?TPqO+@6Fl!R^WTV%(mBFT(Aq_(I&ChA+VF>G*uyo`KK9?V0#o+@6KMircgC$GK0) zo`cUW_TPg2Dn1Lh=i)PQdmcUmx98*2aeDzi4YwEKQ*nC{J_WZICU2*#m-UYW0|kK!G1`!&1+ZXd(j*TC&h z@anjI5wC{Zm+-2%eHpKU+gI?)xcw?PikHXjFYt1>{Uu%&x4**6 z;P%&eY25w>FNNFR;w5qWJG=yLe~%Z(?H}-Bxcwtu6t{oEi{SRpcwyZB1uul#zv2aP z`!~D*ZvT$w$L&Axe7OB5o)@?O!t>zv-*|4^zJ}+*?dy0>+`fV5!0mtV?6`ds&xYH# z@T|Cf8_$BA#tF9{Mk)otOTTY3HN=VA}cV-93h~8Tu=xU6%fmX_uqFVA|#B zt4zBB{W;UFNPot(E76}a?aK5Ord@@;%(Sc0mzZ`n`XbY=PJhC*YtSDv?V9ujrd^9Z z&$MgP=a_aK`Yh9~OP^ud_2|<~yFUF9({4b2$g~^MrD zr`I#>5%fByJ(6C_v`5ivnD%ITHPaqLuVUI`>6J`-9KC{RkEfS2?FsZUrah5f%CslZ zOPKa#dNI?ULN8+4Q|X0Fdm6ofX-}u;Gwm7lJf=O9p3Agn(XTS?+4P*SuDjpY^PKHp z-@lISe_#K5+5YeIe~0bg5C3=D{{8dslkMMc|GwJ(^YNd9?LSZdx!L~n_n))vuNQw^ z*#7$R*OBe7M}OVf{`&RTsqL?Ke_h-D{_yvK?e8al-`M{C^Y@wU?^l0c+W!9b_p$B! zfxqu<-#>hxuzkPreZ}_u$@d}K_cPzOY~TNUpR;|x^nKCx{nhtT+xKJNcWvLleV?{{ zzxRFJ-ox*M-b{Nh-HU1OqkA&#{d5neeSq%Hv=7qVnD!yME7LwqcVXH`=*~?0DBX!^ zzeaat+Q;Y)O#3+9o@u{Mw`1CG&~2Ian{*qd{TAJtX`i55G3}FdOQ!uc-GXVqLpNvI z@6yef_Iq?wru{zMglT_3H)h(W=tfNYL%Jc;{)leCv`^FZnf4jF9@9Qc*Jax0=sHaM zJYAbFb+Khs5+_Ahi{ru{2jh-v>u7i8MM(*>CJA9Q}E{U@D|Y5zs%W!it!d6@P!Iyck4 zPUm9UH|U&9`yV<7)4oY(XWF;uY)tz$ot0_dp|ddUf9cFj`!1b{Y5VzKM%?!E!VI|W z=Zooa+s`9k!EHakd>Oa>yz?d8_Vdvfaof*RU%+iYe@%zmeqNgvxBYxK4Q~5+@bkFs z=f}_Cwx2gYi`#xaof^0OJo_2k_Ve$jaof+!pTccFUr&YGejc9^xBdM7N!<4H{uH?F z^?~HL?e&CYxb5|aq`2+%iX^!0^^GTR+v_2ZZ;~w8)*)q}Y0^{xkS+v{WZMdbroUZLgnuo!s_% zyVuoiug`lO-u8OF*X`}%{5tVEzg+_Nz5u%Td!LJ4 z1NXidyC&{^GG~_k9(hy-2nH#B)cK*eN1*E z-20yF#<=%M*-dcotFoKo-iKv3!@Y0IZjO7Om)!#QzA(Eb?tNr-E8P3e?AEyVso8CC z?`yN$;@$^mx5K?}&Tfx;pPk(S_r5&4Bkp~Cb|?HO_kq}*@gun11wV}2UGYP>-3>p8 z+uiX4xZMNakJ~-*eYo8V-;3M5@jbZR2j7j`eeqqm-4EZ1+x_t!xIF;hj@twAZMZ!M z--_FV@h!ML1mBF?L-9?xJq+K7+r#kFUy9q4@g=xD1z(KYQ}IQ(Jq=%o+tcv{xIF`(kJ~fx zdAL0bpNreG@mF!%`~BzWOg(;2z>eQ5u;cd-?D)L}JATi>j^B&0&&rP9%d+G5xa|17FFSru%#PnHv*Y*B?D)MkJATj2 zj^B&3~E`(vIJ&wBz?M z?fAV-JATj8j^7KlU?Oo(;Ee;aPF}Hl78y@8Fqn`(Hd0Zr{Z-;&yxvh#j9BV#nu<*zvg} zc6^SB9iMw*$LFNj@wqB?d=85ppW9-`=e*eQxiEHoj*K0jJ7dS^)Y$R4Hg(r#_c+(^RN~aCe zZhwxK!|khhS={~tFN51(;-zu>E4&nLe~p*K?QifBxcx0&9Jjy2i{bY7cv0N`0WX5v zKjMXP`zO2*ZvTuI#O+`30=WGvo*%b=!}Hzeh^QK+YjMsaQk8WdE8EjKZo0o;Lqarqj+lE zPJ};$+lld~ar-g+DcpV>Plel0;3;uC3H~H*C&g3Xb}~FU{=deP;mJMEOp2$VpJXP% z?UeWvxSa}r9JimsAH(gZ@x-|O44w$LQ{#`~_OtjSxcwZS5VxPlAI9x8_(Qmz7Jm@8 z)8P-`_6zv^xcwr2A8x;d-;3KX?FRS< zxZMzcAGaIf@8Nc1{9W8`g1>{?P4TyJyBU5Gx0~Z9aJvQm7H+r1-^A@!_#3$08h;(P z+u+A>yDfeUx7*>b;dXocC~kMakKlGk{4j2J!VlqgXZ#>;cfk+fc2|5qZg<1?;dXa? zFK+k1_uzIy5ZjZy4 z;r4iZDQ-`|m*Dn9d@*iM!WZH8WPBlRPr(=9_Eda6ZcoGK;r4WVE^g1jU&Za2_#E7x zh0n(S*Z3@aw&$5M@j3LX%o(^n7oU#X^YCf7Js+Qn+Y9h1xV;dcjN6OwNw~cjpNQK_ z@CmrR6d#Y<%kXiyy&NBl+bi%fxV;h|joYj6QMkPtABo#*@DaGZ79Wn=>+oT?y&fNm z+Z*s9xV;e{jN6;=LAbpcABfvq@Bz5J74MJR+wgw4y&dn1+dJ?+xV;najoZ8MUbwv* z?}^)c@E*9m7w?YS`|xhKy&vz2+XwJ2xP1`sjN6CsPPly-?}*z+@D8|r6mO5)ui@=* z`xxF9w~ym(aQk(Nxcw7e2)BR63*z=K zcmdr070-{`zv20C`*%DqZvTPj!Rj1h-S-PvCYc{BhiV3V#f@ zpT-m8_A_`Q+)j-@irdfPkKp!mctYHM9)B3O)8G%`c3S*F+)jr-fZH$N_v7}9_M{5#w(j(>~WCGc->yCnWKZkNKp!tK)dm$+R9{{pwm z;#YCI9R4|Om&ZTD?F#s(xLpyyg4>nw%eY+`zl7UW@Qb)z75@actKlExc6Iy$Zr8xi z<91E_9B$Xb&*FA%{0wf_!B69MUHl{5u7`h!+x78NxZME%0Jj_B@8fnO{5{-mjK7Q9 zP4IVcyD9!QZa2eE;&yZV1a7y$-@@&d_?x)h3V#E)TjQ_eb{qUSZnwpc;dVRxHQa8G zAI0qs_z~Rhh#$u7PWU0*?u;MA?JoEM-0q6+$L((TKHTn(@5SvN_#WKuiSNekUidED z?v3xn?LPPp-0q8S$L)UjHr(!yZ^i8a_!itAh;PR2LHH)z9*l3q?IHLE+#ZUr$L(SG zI@}(Puf^>V_!`_EiLb`(QTQs{9*wWW?J@WY+#ZWB$L(?WGTa`IFU9Q%_!8Wnh%d(N zN%$h%o{TTV?J4*I+@6Zh$L(qOJlvj+&&BN-_^Y@*6Q6_Iv+&vY{~Di#&-OfXCO(IL zl{o{q=i<|GdmcUwx98(iaeDzi1-BRClW}_yJ_)xM;}dav2|fY0m*V4bdl^0sx0mB% zaeDKkJ_xrr z;{$Pf3qAn1x8nVAdmG*lx3}YcaeD{e2e)_Py>WXN-V3*P<2`YE58eZ}_u}1gdmr8n zxA)^+ar*$?1-B34opJjR-U+u4;~jDP2;Kp=kK*ld`!&2BZXd(j;`VX84Q{`Vx5n)^ z@K(6}Cf*Xa-@;qq_6fW>ZlA=P;r82jQ`~+BZ-U$J;*D|pJ-iWazmGS>?GNwF(mye@8^#_Qnr8N4=bpT%q8_Bp&JZlA|%;PwT)I&OcASHta3@T$0d5wC*V zm+;ECeHpKW+gI?4xcwfN!B_MJG>Zfe~%Z%?H}+Wxcwtu7`K1I3*q+9ctPC$1uuZxzvB6E`!_rvZvT$w z#qB@vJh=TQo*TFS!gJyF-*`^kzJ}+(?dy1U+`fTl!|i|Ythjv>&w|^x@XWY<8_$H> zckqn3{V$#Yx9{TVaXUdtKL5w4L@N~HSAf6VtAHvh% z_QUw|xSbGx4!0k{pT+G*@zl7T2!95*6XQ?g_G9={xcxYu3b&uYQ{r|K{7KwSil@Ns zWO#D?e~l-@lY5?-6i-1v$xMRVDe)(8I~D#oZa;-ThTBi$iE;ZGJP~fE#vjG)XYogH z`#C%zZa9=}_f z&;RKR%ztq^BYp?BGvT*!J2QR@x3l0kaXTyi4{m3}Z{T)z{5o#uz^~zUPW*4&&V~Pl z+qv;SaXSzG2X5!Zf5+{7_;0wKAO97%3*f)tc0v4S+%AOwgxiJjA91?~{sV3o#lOex zV)%EsT^#=ww@cvP;C4y;Yuqk{e}&tn@h@?^4E_afm&LE*b~*fW+%AuQhT9eJPjR~< zeg(HH;g@l{GJXlStKb)LyDI((Zdb!U#_j6(1>CNIpU3T*_&MCJg`dUk+V~mVu7jV( z?Yj6!xLptb5Vz~&r*OLg{sC?`#NWs5M)-TU-57rtx0~Sa;C55|ZQO2#pTzCv_zB!@ zfxm^@E%7&TyA}QhZnwr?$L%)waolc;AH(f-_-nY`9zTlP9q=Q#-4Q>G+nw-3xZN2) zh}&K81GwE4-;dkf@O`-59p8)FJ@7ra-4ox9+r98zxZNAyiQ9ef9k|^W-;Ue;@NKx= zAK!}G1Mn@lJrLiF+k@~;xIGx(h}%Q(4Y)lNUys|v@O8L79AAsuBk(o2JrZAy+oSMR zxIG$QiQ8lF6}UYXUyj@3@MX9?9$$*v6YwRtJrQ4w+mrA`xIGzPh}%=}1-LyGpO4$q z@OijB9iNNaGw@e&dnP^yw`bwA@&7eG3!m+I=1hDJ{VH z_8NQyZm-3MZ{V$P`%SzhZoh@M!0i)wbKE|O zH^c3>@us-_4&DT}-^Cl__Ir3E+iaQjQVG;V)|m%{C@@shax4PFAbzr~B=_IG$O-2NUfirYWn zMR5B^yfAM6gcri?pYejY{R>_Iw|~X+{vvMQkH3K158&x=`$0S{Za;*l!R?3f=W#nB{v2*Uf0oKofJ=j+sW|c`2QMDh9~ztGbx^eev+94 zw^QOz;C3qfaom0ie+;*u#uMZAGk7B0PK`f`+t1>U;P!KPLfn2He;BvZ;1A(;TKqxW zPKQ5$+b`hvSRf5Ws((qA*} zQuJ3$yEOeJ(=J1Q!L-ZLSDAJ>`g5jTp8kw!SD-&-+7;<5OuG_&nQ2$1FEQ;Z^hKs! zmHvcjSED~>+STa`OuGhso@v*l&oS*<^jW4|n?A#|>(Hl}c3t`-rd^NzkZISaPciKV z^ao74A^kqnZbZMwv>Vg!GVLbxJ50MN{WjBXMxSKb&FK?Ny9NCg({4$>$+TP1Z!qoF z^y^H!4Sk$xx22CU?RNBQOuIdOlxcUMk1*|y^kJsmi9W=%JJSc5b{F~p)9y;|XWHH9 zeN4MMy_aeCp!YECp7d^}-HYDEw0qM#nRXv~2h;9LZ)e*5=xt29KfRS{51_X&?Sb@W zrag$>#Iy&~8=3YHdIQrQO0Q?y!{~KPdpNz8X^)`SFzu1_YNkDkUd6OW(<_~Q^+5Ud@_oeOcZ+{=#z90De-uC^&_X*qg8{b!K-=BORvVA}E zearU!&-Xdo_e>W{^-rLchkL?_8z(?)80$> zVA}iW?o4|>-HmA?eTJ^Xw9nGDnf5ul7SldY*JRok=o(D>W4b!i z{)Dc^v@gT zU(uzR_SbYNru_|Fl4*ZSmtfl8(Z!ke_jEC){R3T;Y5zzUVcI{@g_-uxbRnkw3tf=aof*#)8MwB2S1P7et!HMZu@!jv$*Z&)2VUW&$FMwZ9o5h z8n^wt{3+b_^Yv7??dS0+aof-DpTuoH?@xi-ULQz~+g?vdhTC3$NQ&EDuSkO1Uf*~E zx4jqQB1+v`gYQ&}Up!R6GqUU9-j`(8$GwlqZh(8=lid*aJ}J8q?tN8uW8C|&>?XMP zZP`t6@AI;o;ocW!H^;q?%x-~u-#m7al12q2)Dc72XVVAegL<-;rnsBJH8LMd*FLyaeFYn3Acyf8*zIm zz5%y~;p=gGIKB?IN8oF5dnCRFw@2ZtaeFkr3b)7LD{*@)z5=($;mdJ*JiZLKC*VtQ zdm_FBw zVBFq}55ny&_(0s=iVwi;ZFqm&-j4Uf?Hzbu+}?@z!R=jmZ`|IE_rmQxcu(Bki}%3o zeRy}=-j8>~?E`pM+&+kR!Rct_kmig&>6*YNhZeGG4h+sE;?xcxfb z2Djh9TjTbdcq`m~3vY?rC-4@yeG+eu+i&B|aQhv+DQ>@uH^J@q@W#0PKHdnoKfoK} z_9?spZhwf^$L){sdboWWuZ!Df@H)7C7O#!l=kQv%eIBog+ZXT}xcxC+9k)NhtKs%V zyee*A!mHr+WxO(OU%@Nk_NRD7-2M!&fZLzr<#GEeUJkdvz{}$Hmv|Z6{t7RR+h60Q zaQhp)ByN9;m%#1s@Zz}rJzfmAf5404_K$cG-2MqKjN3osg>d^9ydZA>iWk7`-|+mn z{X3oyxBtNN;`X0-9^C#5&yCxE>|^KYKUZJ(F(6mI)` zom9B(^LSF?w$JZ*61RQcPYT@j`9R5W+vf=-!)>2GloYppUQrU<_W4Fn;I_|0dK|ZX ze$r#O?emrrDG2Q!}c7HQoESd7n1j`@MNz zH{JWgc^^34`^kCVINkftd7nAm`_*}0I^Fx*c^^C7`{8-tJKg)|d7nJp`|WvOJ>C2B zc^^LA`}uj_KHdBOd7nSs`vrPmKs`UduDp++UV!d>2lawt)y^o__g6@4E^^$b&6RDS?dtXVtG~N49>SgHOw^A=l_db_; zIlA}7)XUSokEULM?tM4)igfSOsaK+VUr)U<-TQ#*Rp{O~RIf_+KBIayy7wj3tJA%Y zsa}KbeNXk8bnla@*P?r0RlPRd`>^VD=-#(guS@qnuX;VY_l4E#)4h+Z-hl3XXZ413 z?^CNcqI+Lky)oVU;Ob52-ZxioO7}jydNaEB<<*uu>f>3Tc*4!Yi+zMZajpl_q=9qC)?dMEl8y55<-nXY%CZ=&m6=^N>K zH~I#;-krXluJ@p?qw78CYw3C~`Wm|4o4%T^_o1(%>wW1f>3To<3cB8(zMQTPpf98A z1L;fY`XKrex;~h`n63|@FQV&1=?m%lF!}tpFN>H0YO47xs^KAo;lpiiUg6X{dw`Xu@kx;~jcnXXTvPonEn=@aStH2MU( zKAk?EuFs&4qw6#2W9j-V`WU)Cn?9PZ&!LZ^>vQQN>H0kS2)aI>KAf&Epbw+#3+Y4Y z`Xc%ey1tk`n659O52EW!=>zHdGWr0zzMS5luCJi?qw6c_ed+otdLO#Jn%uc#f>H0c)54ygd-kq**pm(F|8|hu?`X+i8y1tp-nXYf4ccSZC=^g3%HhKrTzMbBl zuJ53?qw72AZRz?hdKwD=f>H0o;3%b6a-kh!b?N#kdL6ocnqHf(pP|>H>u2dT z>H0Z(4Z41wUY)LApjV^o7wJ{$`Xzc5x_+5nnXX@6W$F4YdKtQYn_il(-=UYH>v!oT>H0l-3A%otUYxE!pckX-59vke`XhP~y8f76 zn65ve7ozJ==>_TfGkO8K{+ynlu769%Y>!q3gfVv(ok7=~?LdOZwMz{SW$Abp20yX1e~0o{6siMgNkn z|4q+G*Z-kspzHtA)6@0W^mKIn4LvPge@jn8*L}WdYP#<8NK?^upI@4iuKT>x6m;F^ zqb8^8K2J3nUHAE`N$I-JYfVDeeZFgAy6*E}zo6?rKlXFF?(=3pqw7AOHW6L-dA6U@ zb)SFx30?PjxgXPYpRfB7UH5ssAJTQ7-`7)Og_j%nB>AKJNjzHIa9=Ol_)_s1s z&k5Ik-nh>d*L^;@&mq@+p1IF0*M0uE&pFq9Ub@dk*L}Xa&r#QX9=p$7*L{Aw&uQ0v z-n-9r*L^;`&wv`zk)AhXc@926y`nPmFKm9pfFF=1r*9+30()B|0Cv?3q{V`oHLVrZp zi_#y`^*DKPm()CL8D|Edw{W4vzLcc`UtI{vh^=kABbiF$LJYBCrKS$SV($CWMTJ$q? zy*B+cU9UqwMc3=nPtx^z^b>TwKK(ddZ$Ljr*BjE0()C94BXqqn{V-i`LO(>;o6--` z^=9+~biFx!KV5G@-$&P5()ZH!R`fk|y)}I|U2j9*Mc3QXchdEC^c{4)J$*Y}??B&1 z*E`a;()CXCEp)vzeKTF}Lf=H!yV5t(^=|YHbiF%$JzeiXUq{z_($~`UUi39|y*GU| zUGGC*Mc4b%SJL%<^c8fyKYck}A3$G5*9X#<()B^~C3Jl-eKB1hLSIDJhte0)^=LYtr>|^cr;iJiR(yzd)}>*Dunm()CO9Ds=ra zy)s?DLa#*EuhJ{h^=tGBbp1NLJYBy*FGtsJ(#z8ITl6w?{WiTcUB5#wMc41rOVagw z^b&OaKD{_ye?Tur*B{c0()CC5B6R&Ry)a#WLN7$upVAA`^=I?~bp1I!KVAQpo{z47 zN6$;wzo+M+>p#$Q)Ab+ex#;>&^qh44XL=60{tG=jU4KE(M%RC(e?!-Qqi3b-ztgkO z^_TRo>G~h^uju-p^vrbq6+IJO|BL=5UH_Y&k*@zk&p_AzrKhLsuj%RN`Wt#$y8f1) zhOS2_7UBQ?lbWtaq^F|mk?1MudSrSEx*mm|oUTWuC!_1{(38^jX!Im>Jvu!xU5`Qk zg08#^vc()HN%Pw09a`p0xVF8w3A9*_PZU5`&sNY@k4KcMUH z)8D7-AJ7xf^@Q~Jbp1nmJi7i7JuY4Um>!3&e?pH<*FUAlqU(w1G3oke^!Moc=k#~! z`WN&VbUiUWI$cjfk4D#%(%+%$$>>q(dUARcx}Jg_nXad#N22Sg=n?69YI+2^o`(K5 zUxferkDiwPhOVchzozTy>HpI84D^5KdPe%+bp1>EUvxba{S{r$O#hRve?|X;u76E` zN!PQ`f2ZqN>A%tSZ|J|$^=$MPbUi!$7rLH<{xe*Q?Sm()DWe3v|6Y{XAW-K|e>=Ytqls^;+~ZbiFqHG+nPlKSkH;(ofR$ zdh`=?y*~XoU2i}?M%NqCkJ9x<^doe=G5s)IZ$dvr*PGH0()DKa19ZJPeLr1qLElH$ zThjN^^;YyfbiFlwH(hT--$mEk(s$DJcJv)|y*+(9UGG5OM%O#ix6<`a^euF~Gkr5% z??T^1*Spd;()Dii4RpObeLY?8L0?DLd(zj^^;e)JV| zy+3_9T^~SSM%M?@m(uk?^d)qCFnuvyA3|S5*N4&<()D5V1$2EleLh_uL7zw0N7Cog z^-=UWbbT~^HeDY>pGDWl(r423ar7B>7(fS4EjjAK9fFzuFs+mr|Yxn!|3`P z`cS$)mp+89&!Z2f>+|V@==uWsK)Sw=K7g(-qW7oki|PI7`Vx9yy1ta&hpsQ9_onO1 z>AmRs3VKhvzLMU9uCJnZr|YZf-RSxndRMx>mfnS~ucLRS>+9*A==uhFN4ma|-hr-f zqPM5(o9XT7`WAXyy1td(hOTd;x2Egc>8-*`A==uSAL%M#D-hi$jqSvSEhw1g``Vo3vx_*>ihpr!^*QV>o>9y$k z33^Ssev)2;uAib;r|YNb)#&;edR4l9mR^OfpQBf%>*wi}==ueEMY?{GUV*M(qL-)Z zm+9r``W1Rvx_*^jhOS?um!|92>80rU4SGqsev@8;uHT{;r|Y-r#pwDSdQrN5mtKUf z-=i0%>-Xt}==uYCLAw5sUVyGYqUWdUkLmg7`V)Fyy8e`&hps=P=cen=>AC3oxAdHJ z{X2RNy8b==hhQG|?CiPk`5)PHF74UallGt3`x!b9`!~V9=YL_(xwL0xPugFwmxa0h zEB&`%9`>)!Gb1v;k*^~B|?8So4!=5DA_k3*joJ)IR_M|-ydvT%juzwNkdp;g} z&ZYfx_M|;NdkLWPuzwcpd;Wd)oJ)Hm_N4s-_7XzpVgEGP_xy+KIhXcN*pv2;*!vhd z5BtZ#{{POq&-{Pq=pWJLC-hHYqTpQEKMeLg{~3GEr9B~g(*8MnUqI(!{~*}+d}8*T zOM4RL@3XHbr6-{4$>_<0dD!E#=f3Atu;*ObQ!gdnV@Zv9D*Qzf0G@qJJIC!ybb@_dTD5 zJ?GM%m3egb^>66ef_d1ZvFE<$v$N-1+H){}hkZRKJt|$#Mb90~!ybh__dTD7J?GM% zmw9CN^?daF!947d*mK|W1=w>g?FE@fWM3~tFC5In9)UggJzs=9=h9x3`P;Jp{r{9+ zj9xsLhy4wE?t8ujd(Nf3B=gto>!s+WgL&BhWzT)jmtoJjw3lUGE;twVf4IK;o-fay zb7`-@{BQR4iu6jsJnVn5=f3AFv*%pet1zz`oD2IauJ69*tFh-?+N(4FlYPAgy=E{E zd#zyZb?kp|U1_h)ULEK>>@S0T&(~$oxwO|~UOzY&_6EV+>)0DIZxoyhd*fj4b?i-; zHx15(y;(5#I`-zwTLkCA-ZGeb9eXS0t%Gx6ZxhVDj=e4OcEP!@w-4rC$KHW?$KYJp zI|XyEWADtoOK>jiU4yyTv3FzMJvbNk9>Lt}*n2YX6`Tuu?_lnA?0uN`4bFwVUoiJN z_WsNV1n0s&FqnHC`yl3ngL7dY63o4heJJx`!MU&x59VISK7#qk;9S^81#_=sAI*GB za4zg)gSpqSk7GVQI2ZN_!QAWECo<2#>!3b~J~^0&eM&I*I`*l|rv>N2K0TOw9s3OC zGlO$spB2o#j(s-sIl;NG&kg2Y$3Bnw{NP;J7X)*!V_(R8QE)Eoi-Wn>u`gl1G&mRb zWx?F**q1Y35u6MA%3$tw?5mis4$g&rO)&R5_O;B{1?R%PKA3wQ`v&G4gL7fu6wJMj zeKYed!MU(+4d!0QzK!|z;9S^u1aq%r-^qMea4zh-gSpqS?_s_-I2ZPP!QAWE_cK2b zoD2KGVD5G7hnOD@&V~I*F!wt4qs)&5=fa+z*FX0?f1Ew%(td(@I`;LG^i#n+?5Bgd z*RiMNy3&4zy|d7H*wY02o^3A z?78pxtL!^1)?78px2kbeQ_J_<9v#&p*KMv+$|AIaDJ^zF~=hFU^`RDBG&*;yCdDuT= z&wbB-%bs&-|BiVg_Vw@SpVIXo=syPYuz$jy`=0-aJ?GN?GxLwx*MFhE2?MHC!yY-<_x$_pIhXcG>`D6v z>?MTG!yYl%_xy+KIhXbb>`D7a?0pQKhy86CzEPL!c>WXioJ;!~_N4t&_7XwoVSgR$ zd;T-_oJ;$^>`D9Q?0o^9hy9;m-}8ytb1vnXhyAZ$-}A}Xb1v<#*pv3; z?4^Lt!~SQm@A;JMIhXc7*pv2D?7d{Jr>3U~=3)PxJ@-AImObav{u_JJo{qir(0SN@ z4fZ{sfj#Ha{(?Pe&&b{{%=ItnnSy!Pe`e2p&u3=OxwQYpp0t0(-q+B1*nbT6J)ea= z=hFTId(xhjz3-Xp-_WxK^RR!%p8KB9&Yp8=|CT*z&%s_!=sfJtgMH8EV$Zp>KVwhY zbF=r9xt@pqgs$hMKc?&X=#S`ne)>bYUV#39t{0@=r|X62_vm_I`dzwSgnoyv7p32( z>&57|=z4MbO}bu!euJ);q+h4&rRdk_dTIJqx?YBUg|3&SU#9Ej=$GhvdHO}VUV(mr zu2-a=r|XsI=jeK6`dPYOg?@&vSEZk(>(%I|=z4YfNxEKxeuA#oq#vj2wdlv_dTshq zx?YEVgs#`6AExW|=!fWfefmMV-hh69t~aFbr|XUA`{;UO`d+%;guaKaH>K~U>&@u9 z=z4SdPP*QLzJso}q;IF|t?1k6dTaVty55Gqg|4@yZ>H<*=$q(zd-_JY-hsY>u6Lxb zr|X^Q>*#uC`dYf)g}#QaccrhU>)q(9=z4ehO1j>IzJjjzq%WuIz39v6dT;tty55Jr zgs%6cFQ)7L=!@ujfBHhYK7hV}t`DTor|X00^XU3u`dqp`gg%F^52eqh>%-`?==yN_ zOu9aTK7+20q)(^oqv+G<`e^!8x;}+|S?>H2*7AiBPQK9H_2qz|C$i|GC7`eJ%Ny1s+9&9>H2zlC%V3Y-jS|vq<5g} zo9ON7`eu4Ny1s?pmacE5x1sCX=&kAcc6uwizJuP9uJ5F`pzFKn&FT7XdNaDdhu)N~ z@1-}P>-*@9>H2zq&J}Jhv@a``eAxKx_*RSm#!bB*P-jj=(Xwkae6Jf zeu7?;uAijWpzEjT)#>_adNsO!hF+DfpQTr!>*wf|>H2wkCAxlrUXiX}q*tKpm+0l` z`ek}Kx_*UTmabo=Ukm18FT`D7;_TE6}VgD-F_xxM-oJ)IV_M|;RN&fyRbRPCh!G1)}M}p3!{Y&m6XAF$_K z+7mKQ#=ia`Jt^YbAPnjoXUr$8;g06o?|2&w7{d4x*|KEA{ zng8z`Ju&=@xt@fcG?<4y5qs`?J{fz?r9Cx?mpm57~3y^Xb`hF6|kZCuCpGNdGdJhy4Tg-1mGY_MA(5X6Em+uYX1V zI+%w&0ekLyJ_~!!r9CV2`0VT7(6a^eu*YN1ea~lS&$+bcV4gEL7xuVZ-+j;LV$Zp> z=Vl&^YbAlFUm5=fWO?>$~sy((E~x_A<=N2Is;ao$I^r z`Eu+zm-h0^D+K4l9*yg}@A-=CIhXcI%qs`y!u}4|ci;0>*mExJRhd@{&V{{tF!wt4 zsC;~BufbkT=sfJTg1P7HwV6lZ>jiVKW3SIVGS}A|&>IHxur~_kUdP^; zd6VE=*dy`r-S>P`_MA(5Gv>{Mb75~0%)O4iCG%Fnxv)p%$LYT3TeIg}+S@R18=MP! zyI}5h?CqI%2+oDQV=(tR_D;+@2j{}xC7631dspTW_<7O0(Ypupu=fb&UdP^(d9UDH z*n0~Bl+{f+$lc>WFDx&1ZWx&2?dbNfGZ=k~wp&h3BEo!ej0o!kGU zJGcKqcW!@4cW(ck?%e(x-MRf&x^w#rx^w$4bm#V;>CWvx(Vg3Wq&v6&KzDBM$A5q4 z(*8Yr(*7M?+P|es`*XUqKch?gQ@XT2p-cN?y0kx{OZ!8*v_GIr`+d5!-=jw4b0$`*FIoAEQhAQM$Arp-cN=y0jmnOZ!2(v>%{L`+mB# z@1slmUb?jJp-cO2y0q`2OZ!f`wC|ux`*ymtZ=*~5R=Turp-cN_y0mYiOZ!H;v~QqG z`+B;xucJ%*TDr8ap-cN}y0ovNOZ!T?w6CB``*OOpFQZHQQo6J+p-cN>y0rJ_^V=fk z`T+Vux;~J;fUXas&!_8y>GSCN5c*uYK9oL(t`DQnrt8D$v*`K=`b@e$l0Jj3kD^bf z>!az@==vD?RJuNvK83E2qfe&mW2lI&e~O-aY#`_N09> zdt;gFQ|M#p`c(R8x;~9Qimp$mkEH7}=p*R*O!{!TK8rq#uFs|qrR#I(L+JWk`e3>~ zk3NX5&!-Qh>kH@u==wr>f4aVi-jA*?ruU`mOXz**dT-qBp7W*bB@OoM%YwP*?8}+2 z2+oClWiarxbOL$>^YbAUCeg}=fb`xn0p=jUgrCPb7B92AE*1C z-_M?NX+OaHU~n$%hl07+u^(psIX@2l2>oa<5BsrT?se?PnSaLh^%L}y!947zg1OhR zpJtwj>+5IeXM=gz&joX@V?WRQQ?9RHpkEB;VZRj2y^j48t}E@A*}DRrhy7|W_niG> zt}pG^*t-s$hy6w{_niGBt}pF3*}Dauhy8Xi_niGht}pF(*t-jzhdp7i@A-S|IhXeP z%pU~j!u|o*ci;05*>f)KkC?yDzW$j0B$$W&X)yOX_5@s4+Mlua96Aqs{9xbn-?Hai z+P`BSkA3}n`VYZ8>^}x`uVatPb*23$_I`%W!yYHt_xvyHIhXbq%ww~!|4RQYn1?+U zd+vMwclMl1`%C6A+1LM|{~64~{vLbod;S%B&ZYe?=I^qv|4siVn1?+Ed+vMwU-q0! z`)lUW+1KCD-v;xrM`O=@&qpZr-=9}Im-ctqllF-0MS{-59yQqad}Q{VOM4XNQP|g` z`tgE!*dx2=$LD-B=v>;PGmpfc9)li{uD?rvFPMit0(-#`|Dut`FM2a(jK4rzfezr{{!{+@ehJ|*#8dZo=-@3F6|#O{|o9L;jf_nG5$#~ z5Bs0N-1DE(olAQn=6^u_GyEmgKgYia=3)Omn0r1k-MO^?#$4Ky(31x9u>Ts&J)ey3 zT-skSm-giJ6u~^~zXWs7r=&ZV_Me$cdn$VBU>^3Lg1P6@(49;BkIbb#Ej?W@5Bm?n z-1F(_&ZYf(=F*;lo-vq*{kvf9`7i0trTtsx(w>Q)Ihcq2c`*0^2+!QAut=+346E^}$mPcIP6!+s~2d%hsuxwPMAF71Wrx1e4aFA~hd zelwVRz9`+fwBKMZ?ZxQDgL&Am2XoJtpgWiLYs{s+B>gJXOW~!1dDyQ6bI+HdJD2v$ z%%#07y<9L4`=wy+`SNt<(teS-v{#^CfOh1B3Q15_mfO!98lUkmjv_!_8p#aBbU8@>wa-SL%B?}4v?dQW^g)O+E} zpxzr_3iUqt5~%mZ7el=tz6k35@r6(yfG>dhKzu&b2jTOeJ{X@1^&$8is1Lf`Z=P@jOu<=g-CIQV#; z59Hjgdp-AbKfWJF_s8pxOZVT;e-GWC5C6S&fByV=(*61N=T-N=kN+KX|9kr1P4~aQ z|DAPzz4+@w_t%%dj&y%L`s+^j*RQ`$b$`A4>st5shrbVWe?R&AM)&uhzt41kzxw-9 z_xHEIk9A)U{C%(c`r+$@?(2=OE4r^wz7FZWp82|^`}*hWobKzTuZy~`ufC4zz8?F! ztNZ%x>$L9cy|3%~27aITc|hMt?*R2pczdXC#@j)C3*Hv$Tk$qf--fq_`gXh()OX-5 zp}rGu0rg#YbExmen?ZdK-W2M4@g`8;hc|}$e!LOX58w@SysPP(O!PhWdHD64Wo? z6`_6+uK=&YYp^7|1#iPb@IHJ1bHkVL5BOQ&f8vSYEBF`uDDc1W58*%XUzi~9*LZyR z2EK){1NYCrW6}Nda{oL&23_~h@1xWGdVyb0h(h=49)4ZLub=pJ7{AWr*K_>3kY9K5 z>q~x}%CCd@^)A02=hyxG`kr5Z^y{2{J=3pu`*n4{ey;oVe7|n5`+Wp{zku%dFZg{5 zet(DG7vuN8=*jqcgx~)o?a7&^2+oB)Wia>Yx+*RgkG-YGa2_RhiF>)5+6?;4y7d$(Zjb?n`l_Xy5~y=O4@I`&@7 zdk5$2ed+z+V!lsB?@wPu*9Xx3K4^U)eF5k7LG<}_eK36i<*GJN4(DhOD>2!TGeHvXKL!V05$I_?J^>Osc^ojT+IDxKDrjMuVQ|RO9 z`c(Q@x;~9QhOSSikEZK0=%eWRO!`Q=K8rqruFs|qr|Wa*!|3{4`cS$)k3NL1&!-Qj z>kH_E==wtXK)Sw&K7g(-ruV1&_mTbk(_QKQeRuy}eto*`{Qzpyy?=%G$tXnkz8&5d zBsbmrlz1PMtaR_2;(b{%)4h+2_le0s_r5aTwE6FnuR!;HpL#{Q_XpK0(Y>FjUYYLwNA)Un?^mi< zrF(xh^hpRV4R?)`W5CiH#WZ%=PZ-%Hn<(f82x=Jefky#;+2 zU2jR>N!MG^chL3L^zC%L4SgG3Z%f}w*W1yz(DnB8&2+s3eG^^pNZ&};JJC1L_0IJ5 zbiE6G9bNBAUrX1!(bv%R?)24ky$5|2UGGU>N!NSPSJ3s|^yPHD4}BS3?@M1w*Za|z z(DnZG#dLiDeGy$BNMA_T2hkVM^}+P{bbSbY9$gPP&?n#%;RL!qi9VjLPo|Hf>r?1s>H1Xq7`i@< zKANsir;noRGw37f`b_!=x;~3OoUYHN52NdI=tJrHT>22YK94?_uFt0rqU#Ij1L^ug z`T)AVh~A&BFQ)gS>r3c;>H1Q7AG*Gb-kYv3r}v`kE9gDx`bv5ay1t6uovyE@ccbfT z=w0dhT6!0{zK-6RuCJ$eqU#&z9qIZ;dI!3`iQb;BZ>G1S>s#n;>H1cB8@j%Y-kPp& zr?;Z(JLoOx`c8Tay1t9voUZStH>2x&=uPSRUV0O{zK`CRuJ5NeqU#6f4e9zpdIP$C zh+dzrAEwu%>qqEy>H1N69lCyuUYo8Tr`MwEC+Icl`bl~Xx_*jYovxpzSEK7^=vC?Z zS$Y+^evV$5uAiq@qU#sv73um#dIh?EiC&(rU#6F%>sRPy>H1ZA8M=OrUYf37rrd!;>H1T89=iUFo}2zX{sYWP{{?>mGtyt;f5239pAYQwhojSVpI01>?(>a( zesW~G?(>!-(S1I%&wutg&$`cx_PNkLU)twa`3 zIA6rMzQLa7!uev(^$GSo7tWV(u6MBKxp2OebG?E+&xP}4oa-6vc`lqU=Uk6q&vW5? z1?Rd4d!7sDD>>IK*z;UCU&Xnu!Jg;B`D)H}3HCe}&ew3RbFk;RaK4svoq|2jh4Xcs z>lo~LE}XCDT!&!KbK!gg=h_E*o(tz2IoB@O^ISOJ#JRS?p69~(X3n(<_B3I6uU>y1}03oXf+(dH3vfm`nQ+dTpp5#cM(R7+w?V$MG6aKY>?=`boSR z)KB46p?(^#0`)U^WvHLUD?$AnUJ>f&@d{ACfR~5*MZ6r;FX3gOei<(V^(%O3s9(iP zLH!zD66)9S5>UT^7l-;yycpDP;YFc-8!rO&J9uHJ-^B|-{T^Nr>i6*iP=A2uhx$W2 zAJiY=d7=Io&ja-*cy6da#dAUZ8J-jB&+!~k{}#^<_3!X(Q2!qP2I@cHS)u+To(1YZ z;a@}jXZ$Ou|AJ?R`U^Z0)PKdlg!*rIMyUUeXMp-kd?N1`o!kFp{t8y-+~4>=umb%x z{sxw$zr`c)_oa%`BjS-@L3(673d~E7ioXMM()DQc9Q5dT449SvF8&_OOxI)5Gtpz= zv0-|;9*3Te9v6=XQ_=PK^px}j`1>#^UH^cdgq{{p2j3R^?=Pf%iD!bZ=vnZr@C7{w zo)dmY*K^UorR%xr&*^#|`ZKzom;RKl=c7NN>-p)A>3RYBBf4IY{*bO0qCcSPh3WU{ zdJ+0Px?Yrim#!D1-=XWp>9^^63HmL%UXp&3u9u?UpzEdS*Xep0`Zc;*eW}>3RkFCAwabevz(MqF8I&>4f-j%UXy;3 zuGgZUpzF2i$LV?<`Z2m*mwuG4*P|by>-Fh}>3ReDA-dj>evqy=q935^jp_U8dK3CS zy55w&m##OX@1g6>>AUHA3;Hg)-jcqPuD7D^pzE#a+v$26`Zl`WmcEs)x1(>N>+R{A z>3RqHCc55{zLBnXqHmz8t5_5Be&)-jlwPuJ@v^ zpzFQq%jtR_`ZBuSm%fy)_oFYN>;37A>G}ZrBDy}1zL2gDqA#H9gX#0>`Vjg&x;~UX zm#z<^&!OwX>9gtj2>L9#K9W9@u8*S6pzEXQ)9Lyc`ZT&emOhoPkE2ha*Wv%ud>`uj zQtA89TAY)<53Na;z7O?%sq}qlb}`h?fg^2`?M)GF~R&72Nlw()XdhFO}Cg@B31Do$mWm>HARMm&%)*_kF3n zMfZKF^nIxBOQr8aeP1elAL{#3>HARMmrCD<`o2{9KGgT6()XdhFO|Lz^?j-IeW>qC zrSC(1Un+ecnv0(g>HE-}bm{w0-C*S1U(u!SLo?Im3*7gm@>ja=OXY8L-J4 zpx3kaq5JVY=XH8B_v3orK9Kn!I276kKlZ4SWnf z8oIBCbN8Klea|`9y`J6k()k2F{#2+>3Vd?lQ}Bt~xG+8YJkb9O(T?#K00Tz)?B z^NgQY?BVAVKY!T$eBtLGKacqN!q;_Qzr)w<@bx-;9i7b2-xN3%M&v$WbMSb09QYpe zeqkTrv0zM?0LF*0q1TUuCxq|AC@?yF7ej1A+!xG)}!4->%m;Ri4w{1AQwKZc*cPhleX z8T=f60TaU{Feyw1lfx7+B}@fV!!$50Ob64$3@{`75@v##;aBi$m<48q-@t4zJIn!d z!dx&n%meend@w&O01LuGurMqFi^5{CI4l86!cwp_ECb8Ja~Yy;cEcCbC{06W4?urure zyTWd;JL~~_!d|d9>;wD4ey~3r00+WBa4;MKhr(fSI2-{-!clNE90SL~ad14G04Ksp za59_%r^0D)I-CJ#!dY-OoCD{=d2l{l02jhVa4}p0m%?RmIa~o(!c}lJTm#p_b#Oi0 z05`%-a5LNjx5903JKOpTcMGIs6uW2fv3u zz#rjH@Mri7d;x!jzro+(OZW%;6TX6f!N1`@@L%{EzJYIH1pWsqB8&th!zeH+dy<;8R3^O6U+?1f?vZdFf059W`o&b4ww_>g1KQHm>1@Q`C$QA z5Eg=kVG&pq7K6oM30M-Af~8>@SQeIpvR)f`H4OkP_g0*2CSQplV z^){5t5pIH;;TE_RZiCz5 z4!9HUg1g}!xEJn&`{4n25FUbu;SqQg9)ri>33w8of~Vmbcov?6=ivo-5nh6q;T3ol zUW3=+4R{mYg16xvco*J-_u&Kh5I%yB;S=~2K7-HUx9~goJ^TUw2!DbwW59RedoU)91!KcF zFfNP-U%JULz_zd*Y!5rYj<6H#47<a2Om8 zN5GMA6dVo5z_D-~91kbJiEt8}45z@Ua2lKrXTX_o7Mu;|z`1Z9oDUbkg>VsE441&A za2Z?46nee@EW`hZ@`=I7Q7Abz`O7sybmA1 zhwu@644=TK@ELp#zlGny@8J*dNB9%`8U6xaz+d5S@OStU{sI4lui#(sZ}<=V7rusX z;9D4>`hTxq5n&`48AgFo;X5!Ij1FVKcj0?5CX5AR!#FT5j0fYx1n_JULz_zd*Y!5rY zj<6H#47<a2Om8N5GMA6dVo5z_D-~ z91kbJiEt8}45z@Ua2lKrXTX_o7Mu;|z`1Z9oDUbkg>VsE441&Aa2Z?46nee@EW`hZ@`=I7Q7Abz`O7sybmA1hwu@644=TK@ELp# zzlGny@8J*dNB9%`8U6xaz+d5S@OStU{sI4lui#(sZ}<=V7rusX;9D4>2A}_7Bp4Y+ zfl=W*FdB>wW59RedoU)91!KcFFfNP-U%l?upBH8E5M4d608iXz^bqstPX3yny?nE z4eP+VupX=r8^DIJ5o`>bz^1SnYz|w%mar9U4coxBupMjx6YLDTz^<)Xt zp0F3}4g0{pupjIX2f%@F5F8ALz@cy$91cgok#H0o4adN-a2y;DC%}nt5}XXDz^QN= zoDOHenQ#`I4d=kQa2}iw7r=#Z5nK$Hz@=~*Tn<;jm2eeY4cEZ6a2;F^H^7Z>6ZHG6 zCh!eU6X7H{8BT#y;WRiM&VV!FEI1p^fpg(JI3F&63*jQT7%qWJ;WD@!u7E4yD!3Z1 zfotJ9xE^kR8{sCn8E%1F;WoG(?tnYtF1Q=+fqUUTxE~&X2jL-j7#@K~;W2m|o`5Ie zDR>&5foI`4cphGW7vUv%8D4=`;Wc<2-hemZEqEK=fp_6OcppB158)&D7(Rhd;WPLg zeha^Y-@_l^kMJk>GyDa1LMMYFg{EG--jQ-gz!W75&Rf_0zZX`;Ail2_ytT1 zlfa}f8B7jSz?3i*Obye(v@jh^4>Q1w@JpBpW`Db=3+KW4Z~3H^I$t z3)~8~!R>Gd+zEHV-Ea@w3-`hO@Blmr55dFm2s{dp!Q=1*JPA+1)9?&D3(vvx@B+LD zFTu<33cL!h!Rzn_ya{i?+wcy&3-7`E@Bw@XAHm1)3498l!RPQ>_#ONn{s4c3Kf#~j zFYpEY75)Z)hcDqD@K5*({ssSr|G0o-80cM0>!b~tT{0e>zv%swI8<-7dhdE$Qm<#5Hd0<|c59WsjU_n?27KTM& zQCJKXhb3T1SPGVgWnfuY4wi=%U`1F7R)$qzRagyHhc#eLSPRyMbzogs57vhbU_;ml zHik`LQ`ihPhb>@B*b26WZD3p24z`CKU`N;qc7|PGSJ(}9hdp3V*bDZCePCbM5B7%x z;6OMC4u(VEP&f<@ha=!fI0}x2W8hdg4vvQt;6ykHPKHz9R5%Szhcn;6-=|UWQlTRd@|vhd1C& zcnc<~^538Te+EB?U%l?upBH8E5M4d z608iXz^bqstPX3yny?nE4eP+VupX=r8^DIJ5o`>bz^1SnYz|w%mar9U4coxBupMj< zJHU>x6YLDTz^<)Xtp0F3}4g0{pupjIX2f%@F5F8ALz@cy$91cgok#H0o4adN- za2y;DC%}nt5}XXDz^QN=oDOHenQ#`I4d=kQa2}iw7r=#Z5nK$Hz@=~*Tn<;jm2eeY z4cEZ6a2;F^H^7Z>6Wk29z^!l_+zxlZop2Z24fnvka397hDNF{F!xS(jOa)WJG%zhp2h+n0FeCgDW`ddFSMY0?1!jfcz-%x(%mH)4TrfAx z1M|XsFh48+3&KLMFf0O#!eX#EECEZxQm`~E1Ixm4uso~)E5b^!GOPlt!fLQOtO0An zTCg^(1M9+ius&=68^T7gF>C^x!e+2JYyn%sR;ZeiUa&Xp1N*{$us<9C2f{&cFdPDh!eMYY905ndQE)UI1INN~a6Fs!fWt4ya8{*Tktl#1Mk9n@IHJ1AHqlQF?<4_!e{U~{1$!(zlT4-AK_2% zXZQQ;mX<<5;9%g_U;g>KI%nZMRU&AagEBpp#gV|vYm=orLxnUld7v_WcVF6eW7J`Lg z5m*!!gT-M9SQ3_krC}LZ7M6qMVFg$bR)Upb6<8HkgVkXTSQFNQwP77t7uJLIVFTC@ zHiC^|6WA0sgWex16@OnYHB1B3!gMe_%m6dOFJUH_8GZ%7hFM@%_zlbkv%~+>-d%uO zRria&=cT*5ySux)ySux)ySqEY!d5^<1;rp#EI`FVQ7l9O1uWn$HlMMd{jR##2Cu|6BHAsewVo3JUH zu{m3?C0nsI+psO$u{}GmBRjD(yRa*}u{(RPCws9s`>-$ju|EfJAO~?Uhj1u|aX3eC zBu8;H$8apiaXcq*A}4V&r*JB#aXM#kCTDRr=Ws6PaXuGtAs2BmmvAYUaXD9TC0B7Z z*KjS@aXmM1BR6p~w{R=BaXWW#CwFl-_wYXM<^6ns5Aq>C%zb=>kMc1-&L{XJpW@Se zhWmMd2l*_YwJU9c$_DAl5g@YzRgp7hwt(|zRwSM znrC>HAMzu9%yayNpYk()&M$bLU-Bzn;Me?y7x^u}@vw%{z?a2iiXvm+=^%37C+Hn3zeJl*yQ!DVUO}n3`#rmg$(D z8JLlon3-9amD!k`Ihd2Vn45W+m-(2V1z3=USeQjvl*L$_C0LTBSej*6mgQKU6iDZayZ`5xcr2RzL)Jj)OH5kKZRe!@@r89(P2JkKxr z6)*5>e#49Wmf!Jv{=gr3i9hi&f95Z|!mGT-U-=ua^9FD7cmBaY`4|7@E#BrG#_jng@UGdYX1IfrvOkMp^J3%Q7kxr9r( zjLW%#E4hlRxrS@Gj_bLB8@Y*_xrJM~joZ0{JGqOyxrg_0FYo6Ae2@?EVeaE2e3Xyz zaX!H(`4pe#Gu+PuJjiGH9G~YQzQ7mx5)bnTU*;=(!Qan(kuUKukML!_!lQhZukm%h z!DBqm6FkW``4->iDZayZ`5xcr2RzL)Jj)OH5kKZRe!@@r89(P2JkKxr6)*5>e#49W zmf!Jv{=gr3i9hi&f95Z|!mGT-U-=ua^9FD7cmBaY`4|7@E#BrG#_8(MkuWafF+LM8 zArmn%lQ1chF*#E(B~vjq(=aX5F+DRdBQr5GvoI^OF*|cGCv!13^Dr;-F+U5iAPccD zi?Aq*u{cYxBulY0%djlVu{##2Cu|6BHAsewVo3JUH zu{m3?C0nsI+psO$u{}GmBRjD(yRa*}u{(RPCws9s`>-$ju|EfJAO~?Uhj1u|aX3eC zBu8;H$8apiaXcq*A}4V&r*JB#aXM#kCTDRr=Ws6PaXuGtAs2BmmvAYUaXD9TC0B7Z z*KjS@aXmM1BR6p~w{R=BaXWW#CwFl-_wYXM<^6ns5Aq>C%zb=>kMc1-&L{XJpW@Se zhWmMd2l*_YwJU9c$_DAl5g@YzRgp7hwt(|zRwSM znrC>HAMzu9%yayNpYk()&M$bLU-Bzn;Me?y7x^u}@vw%{z?K&Ch?vWjw}b0w!c4CT0>QWilpb3Z`T#re+$ZWjdy3 z24-X?W@Z*e>tpX5_~n$K`Q5AYzL<#T+Vhxh_t8s}i??})ak~5Y z&$x`o_)NfrOvJ=Y!lX>ba4+1Y{k}W!?tY4_Kf~Jo|*2Qu5mIm3$rpCvoi;CG8c0*5A!k~^Roa8 zvJeZi2#c~9i?akvvJ^|R49l_{%d-M2vJxw^3ahdjtFs1cvKDKz4(qZW>$3qHvJo4z z37fJRo3jP|XX@j$vfi3)*p}_sp0WPATlB}?jng@UGdYX1IfrvOkMp^J z3%Q7kxr9r(jLW%#E4hlRxrS@Gj_bLB8@Y*_xrJM~joZ0{JGqOyxrg_0FYo6Ae2@?E zVeaE2e3XyzaX!H(`4pe#Gu+PuJjiGH9G~YQzQ7mx5)bnTU*;=3%2)XsU*{V<#^XG} zlYEnJ@ok>sJA9Y#@qK>4(>%ko{E#29=ryvT3)9lz%f z{E?UV6EE{;{=zG~%4__UzwtV6@FsufAN-Sl@o(PZZQfy=f86`zAB@X*jL!s2$V5!c zBuvU=OwJTc$y7|uG)&8MOwSC=$V|-4EX>Mm%+4Il$z06MJj}~{%+CTW$U-d4A}q>c zEY1=v$xM$W7eLE!@g&+|C``$z9ydJ-m;5c|RZEgM5e&a~~h!qkN2y^9er5r}#9V;eHJ znVE%InT^?*gE^UtxtWJ~nUDEdfCX8Ig;|6}S&YS5f+bmsrCEk$S&rpdffZSam05*V zS&h|MgEd);wONOCS&#MEfDPG*joE}v*^JHEf-TvKt=Wcc*^cemfgRb2o!Nz5*^S-V zgFV@cz1fF-*^m7>fCD**gE@plIgG6?z#n;uKk+hu z<}bX$tGvcv`5UkE25<6r{=q-_7ysrh-sT;~Y3=tD#$`OlX96ZJXAb6MF6L$)=4C$SX8{&uAr@v47G*IOX9<>MDVAm# zmSs7XX9ZSdC01q?R%JC-XARb5E!Jio)@41`X9G55BQ|CeHf1w5XA8DuE4F4Ewq-lE zX9sp%766{GEUBPyWTf zd5gDshjH5Y`OmnF$M{UZgiOT5Ov0p0#^g-FluX6cOvAKH$Mnp=jLgK$%)+e9#_Y_& zoXo}C%)`9Q$NVh7f-JNj_kzF?82_>#_sIFp6tcm?8Cn7 z$Nn6^fgHra9KxX-#^D^nksQU*9K*33$MKxNiJZjAoWiM`#_62FnViMhoWr@C$N5~q zgV%GiI@2^f8iBgiDZayZ`5xcr z2RzL)Jj)OH5kKZRe!@@r89(P2JkKxr6)*5>e#49Wmf!Jv{=gr3i9hi&f95Z|!mGT- zU-=ua^9FD7cmBaY`4|7@E#BrG#!2D&Wn9K%d?sK*CSqbHVNxbza;9KPrebQQVOpkR zdS+loW@2V$VOC~icIIGC=3;KxE|=Xr=P@I}7F!#u*5 z`3jHnRldg8`38^iI8X2--{f0-o2U2=-{pIJpC9lv&+sfi_n#@A(6N%qg78X`Id(oXJ_7%{iRQd7RG$T*yUS%q3jP zWn9h`T**~j%{5%hbzIL4+{jJb%q`r?ZQRZs+{s*_%dJNQNGI8_&VRA77x*>5;YEJS@Ay4`;E%k-pLm%+ z^A}#>RbJz-{EgRngE#p*|KOkei+}SLZ}Sf0r1JBhaT$;CnScqIh>4kmNtukvnSv>q zim91~X_=1cnSmLZiJ6&&S(%O5nS(i*i@BMHd6|#-S%3vuh=o~%MOlo+S%M{5ilteG zWm%5pS%DQh8VP1%gi*@7+Eimlm(ZP||P z*?}F|iJjSnUD=J@*@HdVi@n*0ec6xwIe-H>h=VzVLphAYIf5fOilaG(V>yoFIe`;7 ziIX{nQ#p;(IfFAfi?cb0b2*Rmxqu6~h>N*|OSz28xq>UXimSPXYq^f=xq%zGiJQ5F zTe*$fxq~~oi@VvO`@QGEj_kzF?82_>#_sIFp6tcm?8Cn7$Nn6^fgHra9KxX-#^D^n zksQU*9K*33$MKxNiJZjAoWiM`#_62FnViMhoWr@C$N5~qgV%GiI@2^f8iBgSw6?-d5ACYMZUzt zJi?dx3Xk$tzQ))229NPLPw*t)Tl`3*1fTYksy`2&CCCH}Ntl$$n4Bq?lBt-QX_%Jjn4TG!k(rp8S(ugCn4LM8lew6i zd6<{^n4bk$kcC*7MOc)@SezwTlBHOhWmuNwSe_MFk(F4PRalkPSe-RkleJizby%16 zSf35pkd4@wP1uyp*qklclC9X9ZP=FW*q$BOk)7C?UD%b~*quGtlfBrReb|@%*q;M9 zkb^jwLpYSfIGiImlA}19V>p)MIGz(Yk&`%?Q#h5=IGr;%le0LRb2yjtIG+o+kc+sO zOSqKFxST7vlB>9yYq*x{xSkuhk(;=gTey|mxScz=le@T^dw3uB@_s(R2l)^m<~}~c zNBI~Z=M#LAPw{C!!~HzKgM60H@p&HN3w)6;@i33@Wxm3re3h^9b-ux4JkAq5$v62H z-{vX4!*}@}-{%KB%`-g95BU*4<~e@CPx%=?=NCNBFZmTO@N0gx=+G9KeI0TVJ26Eg{uG8vOI z1yeE=Q!@?IG9A-112ZxcGcyabG8?lq2XitPb2AU~G9UA^01L7Z3$qA|vKWiA1WU3M zOS25ivK-5^0;4|`^t6BX;u-Ge0UqSDe2&la5MSVne2Is7gfH_I9_6cijj!_!9^-MI z;7Pv8xA-Sc!6K@8(!qM{EpxA z2mZ)Q{E3(OGk@U~Ugb6Z%HMdMH+Yl3^AG;XzxX$A@iy-;PCU;SjLUe8&jd`!L`=*i zOv+?T&J;|^R7}k@Ov`jk&kW4SOw7zI%*t%c&K%6iT+Gcp%*%Yt&jKvSLM+T8EXram z&JrxiQY_6fEX#5%&kC%_O03K(tjcPv&Kj)ATCB}Ftjl_=&jxJBMr_O`Y|3VA&K7LR zR&32SY|D0R&kpR!PVCGs?89LixF&Ji5RQ5?-N z9LsSW&k3B!Nu10noXTmO&KaD^S)9!|oXdHf&jnn_MO@4!T*_r!&J|qARb0(AT+4M_ z&kfwjP29{a+{$g-&K=yzUEIw*ypMZ%KOf+Oe25QoA0OePe2kCt2|mfE_%xs4ejeaK zKFjC$JP+{&zQ~t&m`C_BU*S={%GdZh-{3JG=Lw$Vn|zCJ^Az9VyL^xD^8=pd8J^{b z{D>d(96#Zw{EVOT3!dkf{E8R&HNW9Se#`IpJ%8Yjyu_b)nLqOvUg1?<OO4&%i4^Ph1UkMWs+37LqAnS@E1jLDgTDVd6?nTBbZj_H|!8JUTh znT1)IjoF!lIhl*OnTL6qkNH`E1zCuNS%gJdjKx`kC0UB4S%zgjng@UGdYX1 zIfrvOkMp^J3%Q7kxr9r(jLW%#E4hlRxrS@Gj_bLB8@Y*_xrJM~joZ0{JGqOyxrg_0 zFYo6Ae2@?EVeaE2e3XyzaX!H(`4pe#Gu+PuJjiGH9G~YQzQ7mx5)bnTU*;=3%2)Xs zU*{V<#^XG}lYEnJ@ok>sJA9Y#@qK>4(>%ko{E#29=r zyvT3)9lz%f{E?UV6EE{;{=zG~%4__UzwtV6@FsufAN-Sl@o(PZZQfy=1b+TAF5@vi z6EGnYF)@=cDU&fdQ!ph{F*VaLEz>bQGcY4FF*CC;E3+{>b1)}!F*oxtFY_@!3$P#y zu`r9UD2uT;ORywMu{6uDEX%PxE3hIfu`;W$Dyy+NYp^D3u{P_lF6*&A8?Yf8u`!#l zDVwo5Td*Ztu{GPUE!(j@JFp`=u`|1{E4#5fd$1>au{Zm$FZ;1S2XG(Ci2XQcma43gyI7e_KM{zXAa4g4hJST7>Cvh^Ta4M&9 zI%jYuXK^;?a4zR@J{NEy7jZF{a4DB@IahEcS8+Aha4pwyJvVS8H*qt!a4WZQJ9ls= zcX2oO@ILP4{d|BA@*zIVeSCzE@-aTnC-@|v;?sPF`+0x|`7EE~^E|{C_#$88VIJYj ze1%8(DqrL4e1pe$oF{maZ}Kg^%~O1b@A5sq&kuN-XLyz$@*{rCbNqy#@-u$UFL<6` z@+)58*ZhVT`7OWW_xyoB@)CdIW&X@xc!gJajlc3YUgr(o&0D<9JB-uL z@2!l>c#O{kOvpq`%p^?8WK7N!OvzMC%`{BQbWG0-%*ag4%q+~xY|PFa%*kBL%{%qg78X`Id(oXJ_7%{iRQd7RG$T*yUS%q3jP zWn9h`T**~j%{5%hbzIL4+{jJb%q`r?ZQRZs+{s*_%dJNQNGI8_&VRA77x*>5;YEJS@Ay4`;E%k-pLm%+ z^A}#>RbJz-{EgRngE#p*|KOkei+}SLZ}Sf0wD4kmNtukvnSv>q zim91~X_=1cnSmLZiJ6&&S(%O5nS(i*i@BMHd6|#-S%3vuh=o~%MOlo+S%M{5ilteG zWm%5pS%DQh8VP1%gi*@7+Eimlm(ZP||P z*?}F|iJjSnUD=J@*@HdVi@n*0ec6xwIe-H>h=VzVLphAYIf5fOilaG(V>yoFIe`;7 ziIX{nQ#p;(IfFAfi?cb0b2*Rmxqu6~h>N*|OSz28xq>UXimSPXYq^f=xq%zGiJQ5F zTe*$fxq~~oi@Ujp_i-=p=L39@5Ak8{<0E{OkMVIn!6*3?pXM{%&jUQjXZakT=OMnp z7x@wo^9Wz&D?G|q`5Is68$8D2Ji(KElW*~Dp5i-vm+$d?e!$Z_!?XO5AMs~imuXg&Jpr4HC0tw+bp=J>JxGq-UnJAU-XfipUOC4W9WT2F6# zW!t0m=y=b@`nu8Wp0ho=AJNx&KGyw@j(5oR=mg_h)UZd!Hn=9?iGg z?*Cqh6U{f;9^F2gZ?!%8V^K*QZ;kDVtVi?pwkNbbns2i`x_va?V0&~wqV4N!kM4JL zyG^!7_b)pBX4|9tAKjlVwx@D`qHbwot?$TnZ^LZ|Y&6Oa4j6m?ZH4a5qdza!Xp-Ce z!m+>J#%lk(e~V@RynnKLt8t?Hmpaz^)?)T|{~AoQgZmfz_Ob8p=5n!aKkuJ!AKl;R zJY3i4pZ9OE>7VzH{(eSue=`_I>lokoMUANWjSDn%Eqy3}(qT|=FUrk2$Bl-AzCf77me=SOtAHP)lY6Wy;nu|8rSHyS%T<3wLCI&L(Nju*|Ne$hPI z9vMCEXdWFenn(9Dnn%Zr=25R`9vv^5M~@?#N9)l%`hG_9WFBBNkG_A=JUaiQd9;5t zkDkw>d363p^XPhs=F#&*H1~AyuYIGh7tOQAx_{C0VKmPXYaTt{MDyIS=F$C)=J{gH zqw6)A7mPKJuFGg%B-T87ywSXPtam8^!=(C>-PHvh|b$OvE~!9+}jWxuU@QqrCj$mMCWaTSo5mp z(Rtn|*1U#!bRIW}HLqZpdDbe{yoq^q9<_-zZ*Cr)C+%X* zTbW1aL5EoLw&v0Ixl^op2XmR@`1SK&zki+0v$ zdi*{Hc^tP-tmF4LkFKkJvF3x!3)ns&)_kaWA=?MVnvXD#uDc`K<~3}e9&5hOyq4`VV$Gj6kDeE1#+n~8kDeE1#hM>AkDeE1 z$C@8EkFNVU=F#)jDf8&Mo*Qd^+B~{$=f#?zGmoyz`LX8b&7 zp+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C z5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S z0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;J zC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFj zgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfo zKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q z3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6> zp+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C z5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S z0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;J zC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFj zgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfo zKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q z3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6> zp+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C z5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S z0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;J zC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFj zgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfo zKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q z3WNfoKqwFjgaV;JC=d#S0--=C5DJ6>p+G1Q3WNfoKqwFjgaV;JC=d#S0{=%A_(#m6 zjvKQih*=WGEJp!rVwSuy%m35kri;04`j{m{%#tx?$rrQak68-DECpkhLNQC>n59U}QZ!~M7PAzO zSxUq#C1aN8>&A=uJbFxtVm|+$d0d%e_RA8pWQ|$=?c@8m$GqF<->z@l6|*7cV>@?n z^pJkT2K2u-`;Y#2M4$0h%a{I-Cik}W9W`NO|2|`%qg78X`Id(oXJ_7%{iRQd7RG$T*yUS%q3jPWn9h`T**~j%{5%hbzIL4+{jJb z%q`r?|LpwkIAHAf0h9mTY5A`k!aVf(|MK}!Z^GD#1OD}F{r8`QdFT_)kAHt%L|gt> zUmxuzj2+mg-+%rc3iHtCf93hnan$e$BmVQ#GtU3p^G0JwO&A?rtp9=k)p-lQAC{<> z{nCYsS!+e>D=r`0ee>8;HUD@0{Wto3I7$|KJ@)U((R#Fh?DgpP>1h5xT91D3j`siG zZT)2>}^g1_sT^sxLZuI&#+8*r}z21%eIyhR7 z=F#in==E;29=#5Z)}z?uS8O@{h=y=ig=y;LQJY3)RE` + + + + + + + + + + + + + + + diff --git a/tests/unit_tests/cad/settings.xml b/tests/unit_tests/cad/settings.xml new file mode 100644 index 000000000..89b797687 --- /dev/null +++ b/tests/unit_tests/cad/settings.xml @@ -0,0 +1,16 @@ + + + + eigenvalue + true + 15 + 5 + 10000 + + + + -4 -4 -4 4 4 4 + + + + diff --git a/tests/unit_tests/cad/tallies.xml b/tests/unit_tests/cad/tallies.xml new file mode 100644 index 000000000..62a870c02 --- /dev/null +++ b/tests/unit_tests/cad/tallies.xml @@ -0,0 +1,31 @@ + + + + + 1 + + + + 0 20.0e6 + + + + 0 20.0e6 + + + + 1 + total scatter nu-scatter absorption fission nu-fission + + + + 1 2 + total scatter nu-scatter absorption fission nu-fission + + + + 1 2 3 + scatter nu-scatter nu-fission + + + diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py new file mode 100644 index 000000000..21a3a246d --- /dev/null +++ b/tests/unit_tests/cad/test_cad.py @@ -0,0 +1,10 @@ + +import pytest + +from subprocess import call + +from tests.unit_tests import assert_false + +def test_cad(): + assert not call(["openmc"]) + From 2b2bc9a4680d5c2937178dc5dee754ff3af92f79 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 8 Sep 2018 02:04:39 -0500 Subject: [PATCH 084/175] Removing bad import. --- tests/unit_tests/cad/test_cad.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index 21a3a246d..b6a8db9bd 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -3,8 +3,6 @@ import pytest from subprocess import call -from tests.unit_tests import assert_false - def test_cad(): assert not call(["openmc"]) From 326eddc46987896d19976890fca36f37d711980f Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 8 Sep 2018 11:37:42 -0500 Subject: [PATCH 085/175] Adding Python init file. --- tests/unit_tests/cad/__init__.py | 9 +++++++++ tests/unit_tests/cad/test_cad.py | 4 +--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 tests/unit_tests/cad/__init__.py diff --git a/tests/unit_tests/cad/__init__.py b/tests/unit_tests/cad/__init__.py new file mode 100644 index 000000000..59a520c12 --- /dev/null +++ b/tests/unit_tests/cad/__init__.py @@ -0,0 +1,9 @@ +import numpy as np +import pytest + + +def assert_unbounded(obj): + """Assert that a region/cell is unbounded.""" + ll, ur = obj.bounding_box + assert ll == pytest.approx((-np.inf, -np.inf, -np.inf)) + assert ur == pytest.approx((np.inf, np.inf, np.inf)) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index b6a8db9bd..5df861aa1 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -1,8 +1,6 @@ -import pytest - from subprocess import call def test_cad(): - assert not call(["openmc"]) + assert not call(['openmc']) From f2cb4da8d9fab3e7a5e72815a0ed90e49e85d640 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 8 Sep 2018 14:32:23 -0500 Subject: [PATCH 086/175] Ensuring only one thread on the CAD run. --- tests/unit_tests/cad/test_cad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index 5df861aa1..ccd874c3c 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -2,5 +2,5 @@ from subprocess import call def test_cad(): - assert not call(['openmc']) + assert not call(['openmc -s 1']) From 1befe1c059c23c0d5a45fa063474f6df21cf68f3 Mon Sep 17 00:00:00 2001 From: shriwise Date: Sat, 8 Sep 2018 14:51:44 -0500 Subject: [PATCH 087/175] More updates to CAD test. Attempt at skip if DAGMC is not enabled. Attempting to add local directory to path. --- tests/unit_tests/cad/test_cad.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index ccd874c3c..544e87380 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -1,6 +1,20 @@ from subprocess import call +import os +import sys + + +import pytest +pytestmark = pytest.mark.skipif( + os.environ.get('CAD') != 'y', + reason="CAD build is not enabled.") + def test_cad(): - assert not call(['openmc -s 1']) + # make sure cwd is in the python system path + d = os.path.abspath(os.path.dirname(__file__)) + print(d) + sys.path.append(d) + + assert not call(['openmc','-s','1']) From 87b1b4d8ecf258df0404188fe2379ad4fbd69fa4 Mon Sep 17 00:00:00 2001 From: shriwise Date: Mon, 10 Sep 2018 22:47:10 -0500 Subject: [PATCH 088/175] Attempting a new way of accessing local files for test. --- tests/unit_tests/cad/test_cad.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index 544e87380..d73069297 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -13,8 +13,8 @@ pytestmark = pytest.mark.skipif( def test_cad(): # make sure cwd is in the python system path d = os.path.abspath(os.path.dirname(__file__)) - print(d) - sys.path.append(d) - + # move here + os.chdir(d) + # run test assert not call(['openmc','-s','1']) From e1dde40f0ad838389706bd62d598a77a3f74b2aa Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 08:19:23 -0500 Subject: [PATCH 089/175] Using test harness to run openmc instead --- tests/unit_tests/cad/test_cad.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index d73069297..4b5ae34cf 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -1,9 +1,4 @@ - -from subprocess import call - -import os -import sys - +from tests.testing_harness import TestHarness import pytest pytestmark = pytest.mark.skipif( @@ -11,10 +6,5 @@ pytestmark = pytest.mark.skipif( reason="CAD build is not enabled.") def test_cad(): - # make sure cwd is in the python system path - d = os.path.abspath(os.path.dirname(__file__)) - # move here - os.chdir(d) - # run test - assert not call(['openmc','-s','1']) - + harness = TestHarness('statepoint.15.h5') + harness.main() From 1da96b2fa6b0290c0b767dd27d393d547310027f Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 08:28:56 -0500 Subject: [PATCH 090/175] Adding a test harness class to make sure threads are set correctly in CI. --- tests/testing_harness.py | 9 +++++++++ tests/unit_tests/cad/test_cad.py | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/testing_harness.py b/tests/testing_harness.py index fb07575ce..912bbb6f4 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -312,3 +312,12 @@ class HashedPyAPITestHarness(PyAPITestHarness): def _get_results(self): """Digest info in the statepoint and return as a string.""" return super()._get_results(True) + + +class CADTestHarness(TestHarness): + + def __init__(self, statepoint_name): + super(TestHarness, self).__init__(statepoint_name) + + def _run_openmc(self): + openmc.run(openmc_exec=config['exe'], threads = 1) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index 4b5ae34cf..4eb44aac2 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -1,4 +1,4 @@ -from tests.testing_harness import TestHarness +from tests.testing_harness import CADTestHarness import pytest pytestmark = pytest.mark.skipif( @@ -6,5 +6,5 @@ pytestmark = pytest.mark.skipif( reason="CAD build is not enabled.") def test_cad(): - harness = TestHarness('statepoint.15.h5') + harness = CADTestHarness('statepoint.15.h5') harness.main() From 44c8b09214342f4a9c637cfd3d8aec0f0181f2da Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 16:53:01 -0500 Subject: [PATCH 091/175] Removing MOAB and DAGMC source dirs to limit CI image size. --- tools/ci/travis-install.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index ded3c6c00..44655bc9d 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -63,7 +63,7 @@ def install(omp=False, mpi=False, phdf5=False, cad=False): def mkcd(directory): os.mkdir(directory) os.chdir(directory) - + def build_dagmc(): current_dir = os.getcwd() @@ -95,6 +95,9 @@ def build_dagmc(): # update LB_LIBRARY_PATH (so DAGMC can find MOAB) os.environ['LD_LIBRARY_PATH'] = moab_install_dir+"/lib" + ":" + ld_lib_path + + # remove moab source dir + os.rmdir(home_dir + "/MOAB/moab") # build dagmc os.chdir(home_dir) @@ -116,7 +119,11 @@ def build_dagmc(): # update LB_LIBRARY_PATH (so DAGMC can find MOAB) os.environ['LD_LIBRARY_PATH'] = dagmc_install_dir+"/lib" + ":" + ld_lib_path - + + # remove dagmc source dir + os.rmdir(home_dir + "/DAGMC/dagmc") + + # return to original directory os.chdir(current_dir) def main(): From 6ca6ddd758cdb8bbc46fc9ad223776b75d2339e6 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 17:01:36 -0500 Subject: [PATCH 092/175] Re-adding os import. --- tests/unit_tests/cad/test_cad.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/cad/test_cad.py b/tests/unit_tests/cad/test_cad.py index 4eb44aac2..4ae75ff76 100644 --- a/tests/unit_tests/cad/test_cad.py +++ b/tests/unit_tests/cad/test_cad.py @@ -1,6 +1,7 @@ from tests.testing_harness import CADTestHarness - +import os import pytest + pytestmark = pytest.mark.skipif( os.environ.get('CAD') != 'y', reason="CAD build is not enabled.") From a39c06c01abea9479225a5135fc693f801df0465 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 20:18:55 -0500 Subject: [PATCH 093/175] Correcting call to remove source dirs. --- tools/ci/travis-install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 44655bc9d..6dbe5faf0 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -97,7 +97,7 @@ def build_dagmc(): os.environ['LD_LIBRARY_PATH'] = moab_install_dir+"/lib" + ":" + ld_lib_path # remove moab source dir - os.rmdir(home_dir + "/MOAB/moab") + shutil.rmtree(home_dir + "/MOAB/moab") # build dagmc os.chdir(home_dir) @@ -121,7 +121,7 @@ def build_dagmc(): os.environ['LD_LIBRARY_PATH'] = dagmc_install_dir+"/lib" + ":" + ld_lib_path # remove dagmc source dir - os.rmdir(home_dir + "/DAGMC/dagmc") + shutil.rmtree(home_dir + "/DAGMC/dagmc") # return to original directory os.chdir(current_dir) From 4a9faf4205bb662b12473c64208010944d07162e Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 22:01:01 -0500 Subject: [PATCH 094/175] Limiting number of jobs for make commands. --- tools/ci/travis-install.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index 6dbe5faf0..ce7aa1572 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -57,7 +57,7 @@ def install(omp=False, mpi=False, phdf5=False, cad=False): cmake_cmd.append('..') print(' '.join(cmake_cmd)) subprocess.check_call(cmake_cmd) - subprocess.check_call(['make', '-j']) + subprocess.check_call(['make', '-j2']) subprocess.check_call(['sudo', 'make', 'install']) def mkcd(directory): @@ -81,7 +81,7 @@ def build_dagmc(): cmake_cmd = ['cmake', '../moab', '-DENABLE_HDF5=ON', '-DENABLE_TOOLS=ON', '-DCMAKE_INSTALL_PREFIX='+moab_install_dir] subprocess.check_call(cmake_cmd) - subprocess.check_call(['make', '-j']) + subprocess.check_call(['make', '-j2']) subprocess.check_call(['make', 'test']) @@ -113,7 +113,7 @@ def build_dagmc(): cmake_cmd = ['cmake', '../dagmc', '-DCMAKE_INSTALL_PREFIX='+dagmc_install_dir, '-DBUILD_TALLY=ON'] subprocess.check_call(cmake_cmd) - subprocess.check_call(['make','-j']) + subprocess.check_call(['make','-j2']) subprocess.check_call(['make','install']) From 4aa3497ae4becf5206f5d4120f8a9c6d46efb0b6 Mon Sep 17 00:00:00 2001 From: shriwise Date: Tue, 11 Sep 2018 23:28:52 -0500 Subject: [PATCH 095/175] Removing init call in CADTestHarness. --- tests/testing_harness.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 912bbb6f4..67c3bef8c 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -316,8 +316,5 @@ class HashedPyAPITestHarness(PyAPITestHarness): class CADTestHarness(TestHarness): - def __init__(self, statepoint_name): - super(TestHarness, self).__init__(statepoint_name) - def _run_openmc(self): openmc.run(openmc_exec=config['exe'], threads = 1) From 0104a0f217bb2b3838ed23f0d2709b08938c0424 Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 12 Sep 2018 01:08:42 -0500 Subject: [PATCH 096/175] Adding a test fixture to set working directory. --- tests/unit_tests/cad/conftest.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/unit_tests/cad/conftest.py diff --git a/tests/unit_tests/cad/conftest.py b/tests/unit_tests/cad/conftest.py new file mode 100644 index 000000000..bb5f1ad68 --- /dev/null +++ b/tests/unit_tests/cad/conftest.py @@ -0,0 +1,13 @@ + + +@pytest.fixture(scope='module', autouse=True) +def setup_cad_test(request): + # Reset autogenerated IDs assigned to OpenMC objects + openmc.reset_auto_ids() + + # Change to test directory + olddir = request.fspath.dirpath().chdir() + try: + yield + finally: + olddir.chdir() From 4ce6e0211e8f9e48801048285e7c447deae47e78 Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 12 Sep 2018 07:38:29 -0500 Subject: [PATCH 097/175] Adding missing imports. --- tests/unit_tests/cad/conftest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit_tests/cad/conftest.py b/tests/unit_tests/cad/conftest.py index bb5f1ad68..4e36edf67 100644 --- a/tests/unit_tests/cad/conftest.py +++ b/tests/unit_tests/cad/conftest.py @@ -1,3 +1,6 @@ +import openmc +import pytest + @pytest.fixture(scope='module', autouse=True) From b7eb82b6be65df8f4b37693414b76c82a3aec5d0 Mon Sep 17 00:00:00 2001 From: shriwise Date: Wed, 12 Sep 2018 09:21:29 -0500 Subject: [PATCH 098/175] Going back to default openmc run from the test_harness. Adjusting post-run tests (for now). --- tests/testing_harness.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 67c3bef8c..60c8e7c16 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -316,5 +316,11 @@ class HashedPyAPITestHarness(PyAPITestHarness): class CADTestHarness(TestHarness): - def _run_openmc(self): - openmc.run(openmc_exec=config['exe'], threads = 1) + def execute_test(self): + """Run OpenMC with the appropriate arguments and check the outputs.""" + try: + self._run_openmc() + self._test_output_created() + finally: + self._cleanup() + From b149adde0f1e6f58f8e05b1a3c65e3563e9539ff Mon Sep 17 00:00:00 2001 From: pshriwise Date: Mon, 17 Sep 2018 15:31:54 -0500 Subject: [PATCH 099/175] Adding error checks to dagmc calls. --- src/cell.cpp | 12 ++++++------ src/surface.cpp | 12 +++++++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index f0ae46898..82ae2cc3d 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -598,12 +598,12 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const CADCell::CADCell() : Cell{} {}; std::pair CADCell::distance(Position p, Direction u, int32_t on_surface) const { - + moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); moab::EntityHandle hit_surf; double dist; - dagmc_ptr->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); - + rval = dagmc_ptr->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); + MB_CHK_ERR_CONT(rval); int surf_idx; if(hit_surf != 0) { surf_idx = dagmc_ptr->index_by_handle(hit_surf); @@ -619,12 +619,12 @@ std::pair CADCell::distance(Position p, Direction u, int32_t on } bool CADCell::contains(Position p, Direction u, int32_t on_surface) const { - + moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); int result = 0; - dagmc_ptr->point_in_volume(vol, p.xyz, result, u.xyz); - + rval = dagmc_ptr->point_in_volume(vol, p.xyz, result, u.xyz); + MB_CHK_ERR_CONT(rval); return bool(result); } diff --git a/src/surface.cpp b/src/surface.cpp index e0dc35227..ad30a37fc 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -256,25 +256,31 @@ double CADSurface::evaluate(Position r) const } double CADSurface::distance(Position p, Direction u, bool coincident) const { + moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); moab::EntityHandle hit_surf; double dist; - dagmc_ptr->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); + rval = dagmc_ptr->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); + MB_CHK_ERR_CONT(rval); if (dist < 0.0) dist = INFTY; return dist; } Direction CADSurface::normal(Position p) const { + moab::ErrorCode rval; Direction u; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); - dagmc_ptr->get_angle(surf, p.xyz, u.xyz); + rval = dagmc_ptr->get_angle(surf, p.xyz, u.xyz); + MB_CHK_ERR_CONT(rval); return u; } BoundingBox CADSurface::bounding_box() const { + moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); double min[3], max[3]; - dagmc_ptr->getobb(surf, min, max); + rval = dagmc_ptr->getobb(surf, min, max); + MB_CHK_ERR_CONT(rval); return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); } From 725a2fa8145cd8411ddf719e2cf98d1fb23dbb9a Mon Sep 17 00:00:00 2001 From: pshriwise Date: Mon, 17 Sep 2018 16:20:23 -0500 Subject: [PATCH 100/175] Updating how volumes without material assignments are handled. --- src/cad.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cad.cpp b/src/cad.cpp index 9ab4e91f9..7680932db 100644 --- a/src/cad.cpp +++ b/src/cad.cpp @@ -81,8 +81,8 @@ void load_cad_geometry_c() } } else { - std::cout << "Warning: volume without material found!" << std::endl; - c->material_.push_back(openmc::MATERIAL_VOID); + std::cout << c->id_ << std::endl; + openmc::fatal_error("A volume without a material was found."); } } From d0a20099745df3adf74a7f7c2b5c572acaf28d0c Mon Sep 17 00:00:00 2001 From: pshriwise Date: Mon, 17 Sep 2018 22:05:53 -0500 Subject: [PATCH 101/175] Updating DAGMC geometry test file. --- tests/unit_tests/cad/dagmc.h5m | Bin 1233192 -> 1233316 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/unit_tests/cad/dagmc.h5m b/tests/unit_tests/cad/dagmc.h5m index 63a29ee62b5134745be52c1b07d6e3199265a11b..5f84286de26d73a7538ff2ff0558c95e19e6d230 100644 GIT binary patch delta 3193 zcmb7FZ%k8H6o2m)^}W{#k2j|UjnvIaNeq@vq%ya)_^%Tt$d>8QxZ((QMiD35P;?Y< zS{-8R*(e1p?LhZXH|^dB(2Rw|51{))`Njtm+_G$hEu%}8jAS3&d+*-Yju|U9Il1@r z{@%I2^E>C>D}Gkk(_QE>(LLd;?eo&68z}YHj|a-#iziVjq#viDmgNz32F|d?6kc6e zZ+m^?=Hk*fDexZ2mHuGc>4YIZM+uh8lM^m4OHH^O(ofOdk*5-Epg^Rtv?xsnq}z+1 zp>-8$L6}al(u^^H(L&lsn`8m1yIcs#ppF_snY_p_W`UcYc2Yh?=DRMG|i0Wq)cZp`Ap=QaEC@ah_~kK`RHx$_(n> z<5oYLV#KHvXt3FIwG<7<%N8lC(ztEDs+crYfG2Q&{f`NVY%83iVPaDyJqPx>vY>Xe zsoqH#3?IT1n)p%T^ELR7TJpb(Of;NG{NbY*;3harJ)USd2k~8`n+Xh38dJd>bV_aZ zV4{j_EBretL1N`4iI)X{YI{@Xy=oZc;|Y^GIKGBUMeiBwj)l%kSMmvsz1( z!Xf8cuJeYVLhUhD(ungm_hy3-taGA+-U@-a{=ti%VvMRiFvu9t}HF4 zqtlr#e+9dCuF<5MaQXp)PeD3$bp}KTegn;l0Npj?6VsCRTFsUW7Yh3v#@#F^$$} zOshXon0hYnLCr&OHEdM(9|_+=(HfOj=a2y3FNxE#)?p%;R)l!7(-Tb`RcXar9~!T< zAj5G&ixy$@NCr4$0ZkujwC>KNCDy65e*ZtMrvK6!Bi<}&1smW@ePw1F4nbK-xwR7* zFTVdt#S9le=TOklii{s=wGx}O zTA5EOqVP?7xRt}Wn;0r~_QsWCc_JN&O^QI=>IV^WR{_&(&T@Q=xy(`>@wBYYZtoxi z{VgT>*ds|%&~)xuFr9Pgx7uFasDvyoD1h#B$C22qFt&QksQ;|Sc-@112xHg+CT_!n z%kpKyx`~Xq+f3&li@4dV5C>0?r2+OGXcb=DTD*a#bQHdLD9Z4Org7A(X>9sbVXPD+ zUP{>Ko#u)NLvg0$W=Ka-uPXUp1W^*ZdgNCn#7>jGs#XuO$3NQ~Li%56xEEkhuni^y zavpXDjkUvMYXDVuXvCdZSOL(F|qr~TX zA>Wm~EJ|R5U(SS05TAk6>lxlb3vR>sx98tIiGo+P(wnbnnqB`w=~?BqaV-&`EYHj( zjpF;kII~&hWsa8*07W5WzM_Y@IXEM)l{B$WD3LNrri)( z!=`Hqk#O@V974G$7QbbKimD>|o|0^Ma4FqXC7r60XxWf#I@ywBn3EAe$mfTk*rKH!P_O8ChY<>mDCL1x+X5VNYzvz@`;blwh6D_ak51 zfMB2leZ2$1JkD1#Bp7{T5#dQ+M?^T=cYR10W70ahaF9+iULa$@cl)NW*B8AhBqhCZ K@SO^8*zhk7^-1>t delta 3143 zcmb7GZA?>F7{2FJ@ZKuy(o9!`NttdIvy=~=pPRO*qlXl7`~KuHrb;nJICnOOk1l-r%x$tH>}Zm^y>d zx6)YJDx~^jPc=-XKhE2fox34BcN1oHplUfTZ{3!>^;>fDRBSwfwd)O=CDqEeL?wQ& zVJr^ulH@7WtIM62mF~5(SXr)ry?aqc-1^Lkt{`VF%|Ek1muTf#hG+d zOnqQHkgpcEiVC^)2x^P9%G9$RJ}@6N#?6Nkmh60;MjE$8Hxn|BbV#Ll$@RHTHQj{!~*v2bZ@nb83kbMPwQKDBLzok(?JEK&jhh={uqz98~O;&d~Eh0}F z?!TWHxngZcwQU7vaG80*>ZTEX7~lUqeDAJlE4PB>gQf5!@HV!U2Lc-qm{qzg{usq+ z=S?7AJ*=;UwZ}`<;m;|YuY||fzCso#tjYk}avo1sx&tf0Ud3Zul{@eY=nm+F$aPmi z;l|DCq1#limW!5t!qk@@1u-5fPUPeR0>S%Qom5nrjsvKqB0#&-|p|i0RCj0a+*;w8o zfp#Kq$E^Kad(8lr0=;{%8>Y7jLiBb+QByk-A?2j9(Z~xa<_u+{btjbyoH~pL?!nS? zIz?>uxe@GblqKPz*r+UJx;Y}{kwLF#uf+nDc$<~e7kf#d^5|C(Y7%kqbYyF+&dAnG zwnT^x$0*3etWJg4Xlzuz{MP22EYU^DEricBLal_(A@?v3e2XQG{F^Jm@0j-Nk~_0c zPgBcBP}ZV@nHC4;+GK*RGdWlUnP5X2uhyQWc{jDfZ=Ghi4+A)O4{FcTVqQEy0)L;= zBL|%Mn!aO%uQ1t8W9-VwcX+5bKl7A}T0$n_TdKeMwv z>q@x6-z5sJZn_$kqW4j6fl{Wsh?GN+vpf+cz?v_!>X{~P`V3tsa>!#vrsICva5|6-X(*}O*%XAMq*a!SKIH&AA42*ST6Otm4KYFVkudjBI`dai zdDv}!IV0B88BHMhKA~V>3>eBpHaisoAQOSRUgKoxwJz4 z3a#)gS`((z?%~9ya;dpoLc}mJ6|qIc5{M-dTTF~6CJ<8-TS9Cpu_R*2gXPk5D{2N^ z22rOTd~#b;hCOG;G<>sht4J(m(7098UGG^muF-l{k85l)qyb<3?5;*V`0A)8#C!JL M)rg)8_cX450gXZ$?f?J) From 3d27fe55eb0df7eb60d6dfde6f3ceb290a6d3561 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 21 Sep 2018 15:48:50 -0400 Subject: [PATCH 102/175] Changing cad references/symbols to dagmc to leave room for other CAD implementations. --- CMakeLists.txt | 14 ++++----- include/openmc/cell.h | 8 ++--- include/openmc/surface.h | 10 +++--- src/api.F90 | 8 ++--- src/cad.h | 18 ----------- src/cad_header.F90 | 30 ------------------ src/cell.cpp | 16 +++++----- src/{cad.cpp => dagmc.cpp} | 64 +++++++++++++++++++------------------- src/dagmc.h | 18 +++++++++++ src/dagmc_header.F90 | 30 ++++++++++++++++++ src/geometry.F90 | 4 +-- src/input_xml.F90 | 24 +++++++------- src/settings.F90 | 2 +- src/settings.cpp | 4 +-- src/summary.cpp | 2 +- src/surface.cpp | 16 +++++----- src/tracking.F90 | 4 +-- 17 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 src/cad.h delete mode 100644 src/cad_header.F90 rename src/{cad.cpp => dagmc.cpp} (64%) create mode 100644 src/dagmc.h create mode 100644 src/dagmc_header.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index cbbe045c9..f81a9a1e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ option(debug "Compile with debug flags" OFF) option(optimize "Turn on all compiler optimization flags" OFF) option(coverage "Compile with coverage analysis flags" OFF) option(mpif08 "Use Fortran 2008 MPI interface" OFF) -option(cad "Enable support for CAD-based geometry" OFF) +option(dagmc "Enable support for DAGMC (CAD) geometry" OFF) # Maximum number of nested coordinates levels set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels") @@ -40,14 +40,14 @@ if(MPI_ENABLED AND mpif08) endif() #=============================================================================== -# CAD Geometry Support - need DAGMC/MOAB +# DAGMC Geometry Support - need DAGMC/MOAB #=============================================================================== -if(cad) +if(dagmc) find_package(DAGMC REQUIRED) if(NOT DAGMC_FOUND) message(FATAL_ERROR "Could not find DAGMC installation") endif() - add_definitions(-DCAD) + add_definitions(-DDAGMC) link_directories(${DAGMC_LIBRARY_DIRS}) include_directories(${DAGMC_INCLUDE_DIRS}) endif() @@ -311,7 +311,7 @@ add_library(libopenmc SHARED src/algorithm.F90 src/bank_header.F90 src/api.F90 - src/cad_header.F90 + src/dagmc_header.F90 src/cmfd_data.F90 src/cmfd_execute.F90 src/cmfd_header.F90 @@ -400,8 +400,8 @@ add_library(libopenmc SHARED src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 - src/cad.cpp - src/cad.h + src/dagmc.cpp + src/dagmc.h src/cell.cpp src/cmfd_execute.cpp src/distribution.cpp diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 1f3bbe7a4..b7353b305 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -13,7 +13,7 @@ #include "openmc/constants.h" #include "openmc/position.h" -#ifdef CAD +#ifdef DAGMC #include "DagMC.hpp" #endif @@ -167,12 +167,12 @@ protected: bool contains_complex(Position r, Direction u, int32_t on_surface) const; }; -#ifdef CAD -class CADCell : public Cell +#ifdef DAGMC +class DAGMCCell : public Cell { public: moab::DagMC *dagmc_ptr; - explicit CADCell(); + explicit DAGMCCell(); std::pair distance(Position p, Direction u, int32_t on_surface) const; bool contains(Position p, Direction u, int32_t on_surface) const; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 7a1181719..0588dabc1 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -12,7 +12,7 @@ #include "openmc/constants.h" #include "openmc/position.h" -#ifdef CAD +#ifdef DAGMC #include "DagMC.hpp" #endif @@ -133,14 +133,14 @@ class CSGSurface : public Surface }; //============================================================================== -//! A `Surface` representing a CAD-based surface in DAGMC. +//! A `Surface` representing a DAGMC-based surface in DAGMC. //============================================================================== -#ifdef CAD -class CADSurface : public Surface +#ifdef DAGMC +class DAGMCSurface : public Surface { public: moab::DagMC* dagmc_ptr; - explicit CADSurface(); + explicit DAGMCSurface(); double evaluate(Position p) const; double distance(Position p, Direction u, bool coincident) const; diff --git a/src/api.F90 b/src/api.F90 index 5058b0ab1..38329ad80 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -29,8 +29,8 @@ module openmc_api use timer_header use volume_calc, only: openmc_calculate_volumes -#ifdef CAD - use cad_header, only: free_memory_cad +#ifdef DAGMC + use dagmc_header, only: free_memory_dagmc #endif implicit none @@ -330,8 +330,8 @@ contains call free_memory_tally_filter() call free_memory_tally_derivative() call free_memory_bank() -#ifdef CAD - call free_memory_cad() +#ifdef DAGMC + call free_memory_dagmc() #endif ! Deallocate CMFD diff --git a/src/cad.h b/src/cad.h deleted file mode 100644 index 1a1663cdb..000000000 --- a/src/cad.h +++ /dev/null @@ -1,18 +0,0 @@ - -#ifdef CAD - -#ifndef CAD_H -#define CAD_H - -#include "DagMC.hpp" -#include "openmc/cell.h" -#include "openmc/surface.h" - -extern moab::DagMC* DAGMC; - -extern "C" void load_cad_geometry_c(); -extern "C" void free_memory_cad_c(); - -#endif // CAD_H - -#endif diff --git a/src/cad_header.F90 b/src/cad_header.F90 deleted file mode 100644 index 898211454..000000000 --- a/src/cad_header.F90 +++ /dev/null @@ -1,30 +0,0 @@ -#ifdef CAD - -module cad_header - - use, intrinsic :: ISO_C_BINDING - - implicit none - - interface - subroutine load_cad_geometry_c() bind(C) - end subroutine load_cad_geometry_c - - subroutine free_memory_cad_c() bind(C) - end subroutine free_memory_cad_c - - end interface - -contains - - subroutine load_cad_geometry() - call load_cad_geometry_c() - end subroutine load_cad_geometry - - subroutine free_memory_cad() - call free_memory_cad_c() - end subroutine free_memory_cad - -end module cad_header - -#endif diff --git a/src/cell.cpp b/src/cell.cpp index 82ae2cc3d..80d144884 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -592,12 +592,12 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const } //============================================================================== -// CAD Cell implementation +// DAGMC Cell implementation //============================================================================== -#ifdef CAD -CADCell::CADCell() : Cell{} {}; +#ifdef DAGMC +DAGMCCell::DAGMCCell() : Cell{} {}; -std::pair CADCell::distance(Position p, Direction u, int32_t on_surface) const { +std::pair DAGMCCell::distance(Position p, Direction u, int32_t on_surface) const { moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); moab::EntityHandle hit_surf; @@ -618,7 +618,7 @@ std::pair CADCell::distance(Position p, Direction u, int32_t on return result; } -bool CADCell::contains(Position p, Direction u, int32_t on_surface) const { +bool DAGMCCell::contains(Position p, Direction u, int32_t on_surface) const { moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); @@ -628,7 +628,7 @@ bool CADCell::contains(Position p, Direction u, int32_t on_surface) const { return bool(result); } -void CADCell::to_hdf5(hid_t group_id) const { return; } +void DAGMCCell::to_hdf5(hid_t group_id) const { return; } #endif //============================================================================== @@ -771,9 +771,9 @@ extern "C" { int cell_type(Cell* c) {return c->type_;} -#ifdef CAD +#ifdef DAGMC - int32_t next_cell(CADCell* cur_cell, CADSurface *surf_xed ) { + int32_t next_cell(DAGMCCell* cur_cell, DAGMCSurface *surf_xed ) { moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id_); moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id_); diff --git a/src/cad.cpp b/src/dagmc.cpp similarity index 64% rename from src/cad.cpp rename to src/dagmc.cpp index 7680932db..b701583ef 100644 --- a/src/cad.cpp +++ b/src/dagmc.cpp @@ -1,28 +1,28 @@ -#ifdef CAD +#ifdef DAGMC -#include "cad.h" +#include "dagmc.h" #include "openmc/error.h" #include #include -moab::DagMC* DAGMC; +moab::DagMC* DAG; #define TOLOWER(S) std::transform(S.begin(), S.end(), S.begin(), ::tolower) -void load_cad_geometry_c() +void load_dagmc_geometry_c() { - if(!DAGMC) { - DAGMC = new moab::DagMC(); + if(!DAG) { + DAG = new moab::DagMC(); } - int32_t cad_univ_id = 0; // universe is always 0 for CAD + int32_t dagmc_univ_id = 0; // universe is always 0 for DAGMC - moab::ErrorCode rval = DAGMC->load_file("dagmc.h5m"); + moab::ErrorCode rval = DAG->load_file("dagmc.h5m"); MB_CHK_ERR_CONT(rval); - rval = DAGMC->init_OBBTree(); + rval = DAG->init_OBBTree(); MB_CHK_ERR_CONT(rval); std::vector< std::string > prop_keywords; @@ -30,46 +30,46 @@ void load_cad_geometry_c() prop_keywords.push_back("boundary"); std::map ph; - DAGMC->parse_properties(prop_keywords, ph, ":"); + DAG->parse_properties(prop_keywords, ph, ":"); MB_CHK_ERR_CONT(rval); // initialize cell objects - openmc::n_cells = DAGMC->num_entities(3); + openmc::n_cells = DAG->num_entities(3); for(int i = 0; i < openmc::n_cells; i++) { - moab::EntityHandle vol_handle = DAGMC->entity_by_index(3, i+1); + moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); // set cell ids using global IDs - openmc::CADCell* c = new openmc::CADCell(); - c->id_ = DAGMC->id_by_index(3, i+1); - c->dagmc_ptr = DAGMC; - c->universe_ = cad_univ_id; // set to zero for now + openmc::DAGMCCell* c = new openmc::DAGMCCell(); + c->id_ = DAG->id_by_index(3, i+1); + c->dagmc_ptr = DAG; + c->universe_ = dagmc_univ_id; // set to zero for now c->fill_ = openmc::C_NONE; // no fill, single universe openmc::cells.push_back(c); openmc::cell_map[c->id_] = c->id_; // Populate the Universe vector and dict - auto it = openmc::universe_map.find(cad_univ_id); + auto it = openmc::universe_map.find(dagmc_univ_id); if (it == openmc::universe_map.end()) { openmc::universes.push_back(new openmc::Universe()); - openmc::universes.back()-> id_ = cad_univ_id; + openmc::universes.back()-> id_ = dagmc_univ_id; openmc::universes.back()->cells_.push_back(i); - openmc::universe_map[cad_univ_id] = openmc::universes.size() - 1; + openmc::universe_map[dagmc_univ_id] = openmc::universes.size() - 1; } else { openmc::universes[it->second]->cells_.push_back(i); } - if(DAGMC->is_implicit_complement(vol_handle)) { + if(DAG->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now c->material_.push_back(openmc::MATERIAL_VOID); continue; } - if(DAGMC->has_prop(vol_handle, "mat")){ + if(DAG->has_prop(vol_handle, "mat")){ std::string mat_value; - rval = DAGMC->prop_value(vol_handle, "mat", mat_value); + rval = DAG->prop_value(vol_handle, "mat", mat_value); MB_CHK_ERR_CONT(rval); TOLOWER(mat_value); @@ -87,21 +87,21 @@ void load_cad_geometry_c() } // initialize surface objects - openmc::n_surfaces = DAGMC->num_entities(2); + openmc::n_surfaces = DAG->num_entities(2); openmc::surfaces.resize(openmc::n_surfaces); for(int i = 0; i < openmc::n_surfaces; i++) { - moab::EntityHandle surf_handle = DAGMC->entity_by_index(2, i+1); + moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); // set cell ids using global IDs - openmc::CADSurface* s = new openmc::CADSurface(); - s->id_ = DAGMC->id_by_index(2, i+1); - s->dagmc_ptr = DAGMC; + openmc::DAGMCSurface* s = new openmc::DAGMCSurface(); + s->id_ = DAG->id_by_index(2, i+1); + s->dagmc_ptr = DAG; - if(DAGMC->has_prop(surf_handle, "boundary")) { + if(DAG->has_prop(surf_handle, "boundary")) { std::string bc_value; - rval = DAGMC->prop_value(surf_handle, "boundary", bc_value); + rval = DAG->prop_value(surf_handle, "boundary", bc_value); MB_CHK_ERR_CONT(rval); TOLOWER(bc_value); @@ -115,7 +115,7 @@ void load_cad_geometry_c() s->bc_ = openmc::BC_REFLECT; } else if(bc_value == "periodic") { - openmc::fatal_error("Periodic boundary condition not supported in CAD."); + openmc::fatal_error("Periodic boundary condition not supported in DAGMC."); } else { std::stringstream err_msg; @@ -137,9 +137,9 @@ void load_cad_geometry_c() return; } -void free_memory_cad_c() +void free_memory_dagmc_c() { - delete DAGMC; + delete DAG; } #endif diff --git a/src/dagmc.h b/src/dagmc.h new file mode 100644 index 000000000..d417b072f --- /dev/null +++ b/src/dagmc.h @@ -0,0 +1,18 @@ + +#ifdef DAGMC + +#ifndef DAGMC_H +#define DAGMC_H + +#include "DagMC.hpp" +#include "openmc/cell.h" +#include "openmc/surface.h" + +extern moab::DagMC* DAG; + +extern "C" void load_dagmc_geometry_c(); +extern "C" void free_memory_dagmc_c(); + +#endif // DAGMC_H + +#endif diff --git a/src/dagmc_header.F90 b/src/dagmc_header.F90 new file mode 100644 index 000000000..cb9b66481 --- /dev/null +++ b/src/dagmc_header.F90 @@ -0,0 +1,30 @@ +#ifdef DAGMC + +module dagmc_header + + use, intrinsic :: ISO_C_BINDING + + implicit none + + interface + subroutine load_dagmc_geometry_c() bind(C) + end subroutine load_dagmc_geometry_c + + subroutine free_memory_dagmc_c() bind(C) + end subroutine free_memory_dagmc_c + + end interface + +contains + + subroutine load_dagmc_geometry() + call load_dagmc_geometry_c() + end subroutine load_dagmc_geometry + + subroutine free_memory_dagmc() + call free_memory_dagmc_c() + end subroutine free_memory_dagmc + +end module dagmc_header + +#endif diff --git a/src/geometry.F90 b/src/geometry.F90 index c06084888..72caab359 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -56,7 +56,7 @@ module geometry subroutine neighbor_lists() bind(C) end subroutine neighbor_lists -#ifdef CAD +#ifdef DAGMC function next_cell_c(current_cell, surface_crossed) & bind(C, name="next_cell") result(new_cell) @@ -72,7 +72,7 @@ module geometry contains -#ifdef CAD +#ifdef DAGMC function next_cell(c, s) result(new_cell) type(Cell), intent(in) :: c diff --git a/src/input_xml.F90 b/src/input_xml.F90 index eef112b3a..00415bfe8 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,8 +11,8 @@ module input_xml use error, only: fatal_error, warning, write_message, openmc_err_msg use geometry, only: neighbor_lists use geometry_header -#ifdef CAD - use cad_header +#ifdef DAGMC + use dagmc_header #endif use hdf5_interface use list_header, only: ListChar, ListInt, ListReal @@ -351,15 +351,15 @@ contains end subroutine read_settings_xml_f -#ifdef CAD +#ifdef DAGMC !=============================================================================== -! READ_GEOMETRY_CAD reads data from a DAGMC .h5m file, checking +! READ_GEOMETRY_DAGMC reads data from a DAGMC .h5m file, checking ! for material properties and surface boundary conditions ! some universe information is spoofed for now !=============================================================================== - subroutine read_geometry_cad() + subroutine read_geometry_dagmc() integer :: i, j integer :: univ_id @@ -375,12 +375,12 @@ contains filename = trim(path_input) // "dagmc.h5m" inquire(FILE=filename, EXIST=file_exists) if (.not. file_exists) then - call fatal_error("Geometry CAD file '" // trim(filename) // "' does not & + call fatal_error("Geometry DAGMC file '" // trim(filename) // "' does not & &exist!") end if - call write_message("Reading CAD geometry...", 5) - call load_cad_geometry() + call write_message("Reading DAGMC geometry...", 5) + call load_dagmc_geometry() call allocate_surfaces() call allocate_cells() @@ -405,7 +405,7 @@ contains return - end subroutine read_geometry_cad + end subroutine read_geometry_dagmc #endif @@ -436,9 +436,9 @@ contains type(VectorInt) :: univ_ids ! List of all universe IDs type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each ! universe contains -#ifdef CAD +#ifdef DAGMC if (dagmc) then - call read_geometry_cad() + call read_geometry_dagmc() return end if #endif @@ -941,7 +941,7 @@ contains end if ! Create list of macroscopic x/s based on those specified, just treat - ! them as nuclides. This is all really a facade so the user thinks they + ! them as nuclides. This is all really a fadagmce so the user thinks they ! are entering in macroscopic data but the code treats them the same ! as nuclides internally. ! Get pointer list of XML diff --git a/src/settings.F90 b/src/settings.F90 index 6625ccef0..5929bdd93 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -80,7 +80,7 @@ module settings ! Mode to run in (fixed source, eigenvalue, plotting, etc) integer(C_INT), bind(C) :: run_mode - ! flag for use of CAD geometry + ! flag for use of DAGMC geometry logical(C_BOOL), bind(C) :: dagmc ! Restart run diff --git a/src/settings.cpp b/src/settings.cpp index 60a805a01..311ba1af3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -213,9 +213,9 @@ void read_settings_xml() dagmc = get_node_value_bool(root, "dagmc"); } -#ifndef CAD +#ifndef DAGMC if (dagmc) { - fatal_error("CAD mode unsupported for this build of OpenMC"); + fatal_error("DAGMC mode unsupported for this build of OpenMC"); } #endif diff --git a/src/summary.cpp b/src/summary.cpp index 1eeb28185..4d54b2c86 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -9,7 +9,7 @@ namespace openmc { extern "C" void write_geometry(hid_t file_id) { -#ifdef CAD +#ifdef DAGMC if (settings::dagmc) { return; } diff --git a/src/surface.cpp b/src/surface.cpp index ad30a37fc..fb43f0f00 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -245,17 +245,17 @@ CSGSurface::to_hdf5(hid_t group_id) const } //============================================================================== -// CADSurface implementation +// DAGMCSurface implementation //============================================================================== -#ifdef CAD -CADSurface::CADSurface() : Surface{} {} // empty constructor +#ifdef DAGMC +DAGMCSurface::DAGMCSurface() : Surface{} {} // empty constructor -double CADSurface::evaluate(Position r) const +double DAGMCSurface::evaluate(Position r) const { return 0.0; } -double CADSurface::distance(Position p, Direction u, bool coincident) const { +double DAGMCSurface::distance(Position p, Direction u, bool coincident) const { moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); moab::EntityHandle hit_surf; @@ -266,7 +266,7 @@ double CADSurface::distance(Position p, Direction u, bool coincident) const { return dist; } -Direction CADSurface::normal(Position p) const { +Direction DAGMCSurface::normal(Position p) const { moab::ErrorCode rval; Direction u; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); @@ -275,7 +275,7 @@ Direction CADSurface::normal(Position p) const { return u; } -BoundingBox CADSurface::bounding_box() const { +BoundingBox DAGMCSurface::bounding_box() const { moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); double min[3], max[3]; @@ -284,7 +284,7 @@ BoundingBox CADSurface::bounding_box() const { return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); } -void CADSurface::to_hdf5(hid_t group_id) const {} +void DAGMCSurface::to_hdf5(hid_t group_id) const {} #endif //============================================================================== // PeriodicSurface implementation diff --git a/src/tracking.F90 b/src/tracking.F90 index 84ab56cf6..352d9bc7b 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -7,7 +7,7 @@ module tracking use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice,& check_cell_overlap -#ifdef CAD +#ifdef DAGMC use geometry, only: next_cell #endif @@ -473,7 +473,7 @@ contains ! ========================================================================== ! SEARCH NEIGHBOR LISTS FOR NEXT CELL -#ifdef CAD +#ifdef DAGMC if (dagmc) then i_cell = next_cell(cells(p % last_cell(1) + 1), surfaces(ABS(p % surface))) ! save material and temp From d8e12ffb92ba441b26f6804f6d93f755e462b4af Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 21 Sep 2018 16:07:14 -0400 Subject: [PATCH 103/175] More friendly class names for DAGMC surfaces/cells. --- include/openmc/cell.h | 4 ++-- include/openmc/surface.h | 4 ++-- src/cell.cpp | 10 +++++----- src/dagmc.cpp | 4 ++-- src/surface.cpp | 14 +++++++------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index b7353b305..7cad800cb 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -168,11 +168,11 @@ protected: }; #ifdef DAGMC -class DAGMCCell : public Cell +class DAGCell : public Cell { public: moab::DagMC *dagmc_ptr; - explicit DAGMCCell(); + explicit DAGCell(); std::pair distance(Position p, Direction u, int32_t on_surface) const; bool contains(Position p, Direction u, int32_t on_surface) const; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 0588dabc1..cd0a8a3c7 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -136,11 +136,11 @@ class CSGSurface : public Surface //! A `Surface` representing a DAGMC-based surface in DAGMC. //============================================================================== #ifdef DAGMC -class DAGMCSurface : public Surface +class DAGSurface : public Surface { public: moab::DagMC* dagmc_ptr; - explicit DAGMCSurface(); + explicit DAGSurface(); double evaluate(Position p) const; double distance(Position p, Direction u, bool coincident) const; diff --git a/src/cell.cpp b/src/cell.cpp index 80d144884..6c01a8ba6 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -595,9 +595,9 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const // DAGMC Cell implementation //============================================================================== #ifdef DAGMC -DAGMCCell::DAGMCCell() : Cell{} {}; +DAGCell::DAGCell() : Cell{} {}; -std::pair DAGMCCell::distance(Position p, Direction u, int32_t on_surface) const { +std::pair DAGCell::distance(Position p, Direction u, int32_t on_surface) const { moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); moab::EntityHandle hit_surf; @@ -618,7 +618,7 @@ std::pair DAGMCCell::distance(Position p, Direction u, int32_t return result; } -bool DAGMCCell::contains(Position p, Direction u, int32_t on_surface) const { +bool DAGCell::contains(Position p, Direction u, int32_t on_surface) const { moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); @@ -628,7 +628,7 @@ bool DAGMCCell::contains(Position p, Direction u, int32_t on_surface) const { return bool(result); } -void DAGMCCell::to_hdf5(hid_t group_id) const { return; } +void DAGCell::to_hdf5(hid_t group_id) const { return; } #endif //============================================================================== @@ -773,7 +773,7 @@ extern "C" { #ifdef DAGMC - int32_t next_cell(DAGMCCell* cur_cell, DAGMCSurface *surf_xed ) { + int32_t next_cell(DAGCell* cur_cell, DAGSurface *surf_xed ) { moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id_); moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id_); diff --git a/src/dagmc.cpp b/src/dagmc.cpp index b701583ef..5885e688b 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -40,7 +40,7 @@ void load_dagmc_geometry_c() moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); // set cell ids using global IDs - openmc::DAGMCCell* c = new openmc::DAGMCCell(); + openmc::DAGCell* c = new openmc::DAGCell(); c->id_ = DAG->id_by_index(3, i+1); c->dagmc_ptr = DAG; c->universe_ = dagmc_univ_id; // set to zero for now @@ -95,7 +95,7 @@ void load_dagmc_geometry_c() moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); // set cell ids using global IDs - openmc::DAGMCSurface* s = new openmc::DAGMCSurface(); + openmc::DAGSurface* s = new openmc::DAGSurface(); s->id_ = DAG->id_by_index(2, i+1); s->dagmc_ptr = DAG; diff --git a/src/surface.cpp b/src/surface.cpp index fb43f0f00..f51af6d16 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -245,17 +245,17 @@ CSGSurface::to_hdf5(hid_t group_id) const } //============================================================================== -// DAGMCSurface implementation +// DAGSurface implementation //============================================================================== #ifdef DAGMC -DAGMCSurface::DAGMCSurface() : Surface{} {} // empty constructor +DAGSurface::DAGSurface() : Surface{} {} // empty constructor -double DAGMCSurface::evaluate(Position r) const +double DAGSurface::evaluate(Position r) const { return 0.0; } -double DAGMCSurface::distance(Position p, Direction u, bool coincident) const { +double DAGSurface::distance(Position p, Direction u, bool coincident) const { moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); moab::EntityHandle hit_surf; @@ -266,7 +266,7 @@ double DAGMCSurface::distance(Position p, Direction u, bool coincident) const { return dist; } -Direction DAGMCSurface::normal(Position p) const { +Direction DAGSurface::normal(Position p) const { moab::ErrorCode rval; Direction u; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); @@ -275,7 +275,7 @@ Direction DAGMCSurface::normal(Position p) const { return u; } -BoundingBox DAGMCSurface::bounding_box() const { +BoundingBox DAGSurface::bounding_box() const { moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); double min[3], max[3]; @@ -284,7 +284,7 @@ BoundingBox DAGMCSurface::bounding_box() const { return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); } -void DAGMCSurface::to_hdf5(hid_t group_id) const {} +void DAGSurface::to_hdf5(hid_t group_id) const {} #endif //============================================================================== // PeriodicSurface implementation From a9b91745c6fae00ab41c72fc32b5b0fd96a7d198 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 21 Sep 2018 16:09:14 -0400 Subject: [PATCH 104/175] Removing whitespace. --- src/dagmc.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 5885e688b..050d437c6 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -18,7 +18,7 @@ void load_dagmc_geometry_c() } int32_t dagmc_univ_id = 0; // universe is always 0 for DAGMC - + moab::ErrorCode rval = DAG->load_file("dagmc.h5m"); MB_CHK_ERR_CONT(rval); @@ -28,22 +28,22 @@ void load_dagmc_geometry_c() std::vector< std::string > prop_keywords; prop_keywords.push_back("mat"); prop_keywords.push_back("boundary"); - + std::map ph; DAG->parse_properties(prop_keywords, ph, ":"); MB_CHK_ERR_CONT(rval); - + // initialize cell objects openmc::n_cells = DAG->num_entities(3); for(int i = 0; i < openmc::n_cells; i++) { moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); - + // set cell ids using global IDs openmc::DAGCell* c = new openmc::DAGCell(); c->id_ = DAG->id_by_index(3, i+1); c->dagmc_ptr = DAG; - c->universe_ = dagmc_univ_id; // set to zero for now + c->universe_ = dagmc_univ_id; // set to zero for now c->fill_ = openmc::C_NONE; // no fill, single universe openmc::cells.push_back(c); @@ -63,16 +63,16 @@ void load_dagmc_geometry_c() if(DAG->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now - c->material_.push_back(openmc::MATERIAL_VOID); + c->material_.push_back(openmc::MATERIAL_VOID); continue; } - + if(DAG->has_prop(vol_handle, "mat")){ std::string mat_value; rval = DAG->prop_value(vol_handle, "mat", mat_value); MB_CHK_ERR_CONT(rval); TOLOWER(mat_value); - + if(mat_value == "void" || mat_value == "vacuum") { c->material_.push_back(openmc::MATERIAL_VOID); } @@ -83,17 +83,17 @@ void load_dagmc_geometry_c() else { std::cout << c->id_ << std::endl; openmc::fatal_error("A volume without a material was found."); - } + } } // initialize surface objects openmc::n_surfaces = DAG->num_entities(2); openmc::surfaces.resize(openmc::n_surfaces); - + for(int i = 0; i < openmc::n_surfaces; i++) { moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); - + // set cell ids using global IDs openmc::DAGSurface* s = new openmc::DAGSurface(); s->id_ = DAG->id_by_index(2, i+1); From 45154ef21fcb3a48c3c3078d4364a91d538944ea Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 21 Sep 2018 16:16:41 -0400 Subject: [PATCH 105/175] Indentation and formatting updates. --- src/dagmc.cpp | 174 +++++++++++++++++++++++++------------------------- 1 file changed, 86 insertions(+), 88 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 050d437c6..8b5d5dc77 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -35,105 +35,103 @@ void load_dagmc_geometry_c() // initialize cell objects openmc::n_cells = DAG->num_entities(3); - for(int i = 0; i < openmc::n_cells; i++) - { - moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); - - // set cell ids using global IDs - openmc::DAGCell* c = new openmc::DAGCell(); - c->id_ = DAG->id_by_index(3, i+1); - c->dagmc_ptr = DAG; - c->universe_ = dagmc_univ_id; // set to zero for now - c->fill_ = openmc::C_NONE; // no fill, single universe - - openmc::cells.push_back(c); - openmc::cell_map[c->id_] = c->id_; - - // Populate the Universe vector and dict - auto it = openmc::universe_map.find(dagmc_univ_id); - if (it == openmc::universe_map.end()) { - openmc::universes.push_back(new openmc::Universe()); - openmc::universes.back()-> id_ = dagmc_univ_id; - openmc::universes.back()->cells_.push_back(i); - openmc::universe_map[dagmc_univ_id] = openmc::universes.size() - 1; + for(int i = 0; i < openmc::n_cells; i++) { + moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); + + // set cell ids using global IDs + openmc::DAGCell* c = new openmc::DAGCell(); + c->id_ = DAG->id_by_index(3, i+1); + c->dagmc_ptr = DAG; + c->universe_ = dagmc_univ_id; // set to zero for now + c->fill_ = openmc::C_NONE; // no fill, single universe + + openmc::cells.push_back(c); + openmc::cell_map[c->id_] = c->id_; + + // Populate the Universe vector and dict + auto it = openmc::universe_map.find(dagmc_univ_id); + if (it == openmc::universe_map.end()) { + openmc::universes.push_back(new openmc::Universe()); + openmc::universes.back()-> id_ = dagmc_univ_id; + openmc::universes.back()->cells_.push_back(i); + openmc::universe_map[dagmc_univ_id] = openmc::universes.size() - 1; + } + else { + openmc::universes[it->second]->cells_.push_back(i); + } + + if(DAG->is_implicit_complement(vol_handle)) { + // assuming implicit complement is void for now + c->material_.push_back(openmc::MATERIAL_VOID); + continue; + } + + if(DAG->has_prop(vol_handle, "mat")){ + std::string mat_value; + rval = DAG->prop_value(vol_handle, "mat", mat_value); + MB_CHK_ERR_CONT(rval); + TOLOWER(mat_value); + + if(mat_value == "void" || mat_value == "vacuum") { + c->material_.push_back(openmc::MATERIAL_VOID); } else { - openmc::universes[it->second]->cells_.push_back(i); - } - - if(DAG->is_implicit_complement(vol_handle)) { - // assuming implicit complement is void for now - c->material_.push_back(openmc::MATERIAL_VOID); - continue; - } - - if(DAG->has_prop(vol_handle, "mat")){ - std::string mat_value; - rval = DAG->prop_value(vol_handle, "mat", mat_value); - MB_CHK_ERR_CONT(rval); - TOLOWER(mat_value); - - if(mat_value == "void" || mat_value == "vacuum") { - c->material_.push_back(openmc::MATERIAL_VOID); - } - else { - c->material_.push_back(std::stoi(mat_value)); - } - } - else { - std::cout << c->id_ << std::endl; - openmc::fatal_error("A volume without a material was found."); + c->material_.push_back(std::stoi(mat_value)); } } - + else { + std::cout << c->id_ << std::endl; + openmc::fatal_error("A volume without a material was found."); + } + } + // initialize surface objects openmc::n_surfaces = DAG->num_entities(2); openmc::surfaces.resize(openmc::n_surfaces); - for(int i = 0; i < openmc::n_surfaces; i++) - { - moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); - - // set cell ids using global IDs - openmc::DAGSurface* s = new openmc::DAGSurface(); - s->id_ = DAG->id_by_index(2, i+1); - s->dagmc_ptr = DAG; - - if(DAG->has_prop(surf_handle, "boundary")) { - std::string bc_value; - rval = DAG->prop_value(surf_handle, "boundary", bc_value); - MB_CHK_ERR_CONT(rval); - TOLOWER(bc_value); - - if(bc_value == "transmit" || bc_value == "transmission") { - s->bc_ = openmc::BC_TRANSMIT; - } - else if(bc_value == "vacuum") { - s->bc_ = openmc::BC_VACUUM; - } - else if(bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { - s->bc_ = openmc::BC_REFLECT; - } - else if(bc_value == "periodic") { - openmc::fatal_error("Periodic boundary condition not supported in DAGMC."); - } - else { - std::stringstream err_msg; - err_msg << "Unknown boundary condition \"" << s->bc_ - << "\" specified on surface " << s->id_; - openmc::fatal_error(err_msg); - } - } - // if no BC property is found, set to transmit - else { + for(int i = 0; i < openmc::n_surfaces; i++) { + moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); + + // set cell ids using global IDs + openmc::DAGSurface* s = new openmc::DAGSurface(); + s->id_ = DAG->id_by_index(2, i+1); + s->dagmc_ptr = DAG; + + if(DAG->has_prop(surf_handle, "boundary")) { + std::string bc_value; + rval = DAG->prop_value(surf_handle, "boundary", bc_value); + MB_CHK_ERR_CONT(rval); + TOLOWER(bc_value); + + if(bc_value == "transmit" || bc_value == "transmission") { s->bc_ = openmc::BC_TRANSMIT; } - - // add to global array and map - openmc::surfaces[i] = s; - openmc::surface_map[s->id_] = s->id_; + else if(bc_value == "vacuum") { + s->bc_ = openmc::BC_VACUUM; + } + else if(bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { + s->bc_ = openmc::BC_REFLECT; + } + else if(bc_value == "periodic") { + openmc::fatal_error("Periodic boundary condition not supported in DAGMC."); + } + else { + std::stringstream err_msg; + err_msg << "Unknown boundary condition \"" << s->bc_ + << "\" specified on surface " << s->id_; + openmc::fatal_error(err_msg); + } } - + // if no BC property is found, set to transmit + else { + s->bc_ = openmc::BC_TRANSMIT; + } + + // add to global array and map + openmc::surfaces[i] = s; + openmc::surface_map[s->id_] = s->id_; + } + return; } From 7b18e7c79106a3249a79f8fdfd198591b1aaebff Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 21 Sep 2018 16:22:54 -0400 Subject: [PATCH 106/175] Updating travis variables. --- .travis.yml | 2 +- tools/ci/travis-install.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80e9c588a..d2bb6e853 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ env: - OMP=y MPI=n PHDF5=n - OMP=n MPI=y PHDF5=n - OMP=n MPI=y PHDF5=y - - OMP=n MPI=y PHDF5=y CAD=y + - OMP=n MPI=y PHDF5=y DAGMC=y notifications: webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN before_install: diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index ce7aa1572..d6720cccf 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -21,7 +21,7 @@ def which(program): return None -def install(omp=False, mpi=False, phdf5=False, cad=False): +def install(omp=False, mpi=False, phdf5=False, dagmc=False): # Create build directory and change to it shutil.rmtree('build', ignore_errors=True) os.mkdir('build') @@ -49,9 +49,9 @@ def install(omp=False, mpi=False, phdf5=False, cad=False): else: cmake_cmd.append('-DHDF5_PREFER_PARALLEL=OFF') - if cad: + if dagmc: build_dagmc() - cmake_cmd.append('-Dcad=ON') + cmake_cmd.append('-Ddagmc=ON') # Build and install cmake_cmd.append('..') @@ -132,10 +132,10 @@ def main(): mpi = (os.environ.get('MPI') == 'y') phdf5 = (os.environ.get('PHDF5') == 'y') - cad = (os.environ.get('CAD') == 'y') + dagmc = (os.environ.get('DAGMC') == 'y') # Build and install - install(omp, mpi, phdf5, cad) + install(omp, mpi, phdf5, dagmc) if __name__ == '__main__': From f9d287eb891dadc65602e696c259d22ad932ab99 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 21 Sep 2018 20:38:21 -0400 Subject: [PATCH 107/175] updating member variable name. --- include/openmc/cell.h | 2 +- include/openmc/surface.h | 2 +- src/cell.cpp | 18 +++++++++--------- src/dagmc.cpp | 4 ++-- src/surface.cpp | 12 ++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 7cad800cb..0b13eef57 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -171,7 +171,7 @@ protected: class DAGCell : public Cell { public: - moab::DagMC *dagmc_ptr; + moab::DagMC *dagmc_ptr_; explicit DAGCell(); std::pair distance(Position p, Direction u, int32_t on_surface) const; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index cd0a8a3c7..9c3df8980 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -139,7 +139,7 @@ class CSGSurface : public Surface class DAGSurface : public Surface { public: - moab::DagMC* dagmc_ptr; + moab::DagMC* dagmc_ptr_; explicit DAGSurface(); double evaluate(Position p) const; double distance(Position p, Direction u, diff --git a/src/cell.cpp b/src/cell.cpp index 6c01a8ba6..ac7bc4568 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -599,14 +599,14 @@ DAGCell::DAGCell() : Cell{} {}; std::pair DAGCell::distance(Position p, Direction u, int32_t on_surface) const { moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); + moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); moab::EntityHandle hit_surf; double dist; - rval = dagmc_ptr->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); + rval = dagmc_ptr_->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); MB_CHK_ERR_CONT(rval); int surf_idx; if(hit_surf != 0) { - surf_idx = dagmc_ptr->index_by_handle(hit_surf); + surf_idx = dagmc_ptr_->index_by_handle(hit_surf); } // indicate that particle is lost else { @@ -620,10 +620,10 @@ std::pair DAGCell::distance(Position p, Direction u, int32_t on bool DAGCell::contains(Position p, Direction u, int32_t on_surface) const { moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr->entity_by_id(3, id_); + moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); int result = 0; - rval = dagmc_ptr->point_in_volume(vol, p.xyz, result, u.xyz); + rval = dagmc_ptr_->point_in_volume(vol, p.xyz, result, u.xyz); MB_CHK_ERR_CONT(rval); return bool(result); } @@ -774,13 +774,13 @@ extern "C" { #ifdef DAGMC int32_t next_cell(DAGCell* cur_cell, DAGSurface *surf_xed ) { - moab::EntityHandle surf = surf_xed->dagmc_ptr->entity_by_id(2,surf_xed->id_); - moab::EntityHandle vol = cur_cell->dagmc_ptr->entity_by_id(3,cur_cell->id_); + moab::EntityHandle surf = surf_xed->dagmc_ptr_->entity_by_id(2,surf_xed->id_); + moab::EntityHandle vol = cur_cell->dagmc_ptr_->entity_by_id(3,cur_cell->id_); moab::EntityHandle new_vol; - cur_cell->dagmc_ptr->next_vol(surf, vol, new_vol); + cur_cell->dagmc_ptr_->next_vol(surf, vol, new_vol); - return cur_cell->dagmc_ptr->index_by_handle(new_vol); + return cur_cell->dagmc_ptr_->index_by_handle(new_vol); } #endif diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 8b5d5dc77..afb319986 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -41,7 +41,7 @@ void load_dagmc_geometry_c() // set cell ids using global IDs openmc::DAGCell* c = new openmc::DAGCell(); c->id_ = DAG->id_by_index(3, i+1); - c->dagmc_ptr = DAG; + c->dagmc_ptr_ = DAG; c->universe_ = dagmc_univ_id; // set to zero for now c->fill_ = openmc::C_NONE; // no fill, single universe @@ -95,7 +95,7 @@ void load_dagmc_geometry_c() // set cell ids using global IDs openmc::DAGSurface* s = new openmc::DAGSurface(); s->id_ = DAG->id_by_index(2, i+1); - s->dagmc_ptr = DAG; + s->dagmc_ptr_ = DAG; if(DAG->has_prop(surf_handle, "boundary")) { std::string bc_value; diff --git a/src/surface.cpp b/src/surface.cpp index f51af6d16..832668e06 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -257,10 +257,10 @@ double DAGSurface::evaluate(Position r) const double DAGSurface::distance(Position p, Direction u, bool coincident) const { moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); + moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); moab::EntityHandle hit_surf; double dist; - rval = dagmc_ptr->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); + rval = dagmc_ptr_->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); MB_CHK_ERR_CONT(rval); if (dist < 0.0) dist = INFTY; return dist; @@ -269,17 +269,17 @@ double DAGSurface::distance(Position p, Direction u, bool coincident) const { Direction DAGSurface::normal(Position p) const { moab::ErrorCode rval; Direction u; - moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); - rval = dagmc_ptr->get_angle(surf, p.xyz, u.xyz); + moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); + rval = dagmc_ptr_->get_angle(surf, p.xyz, u.xyz); MB_CHK_ERR_CONT(rval); return u; } BoundingBox DAGSurface::bounding_box() const { moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr->entity_by_id(2, id_); + moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); double min[3], max[3]; - rval = dagmc_ptr->getobb(surf, min, max); + rval = dagmc_ptr_->getobb(surf, min, max); MB_CHK_ERR_CONT(rval); return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); } From 05aa0cfea93fd69dce3db6a340e6b26f8a31fe2f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 23 Sep 2018 12:58:27 -0400 Subject: [PATCH 108/175] fixed example problem crash --- src/summary.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/summary.F90 b/src/summary.F90 index 0fafd7e5d..820bde31d 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -82,8 +82,8 @@ contains integer(HID_T) :: nuclide_group integer(HID_T) :: macro_group integer :: i - character(12), allocatable :: nuc_names(:) - character(12), allocatable :: macro_names(:) + character(kind=C_CHAR, len=20), allocatable :: nuc_names(:) + character(kind=C_CHAR, len=20), allocatable :: macro_names(:) real(8), allocatable :: awrs(:) integer :: num_nuclides integer :: num_macros @@ -172,8 +172,8 @@ contains integer :: k integer :: n integer :: err - character(20), allocatable :: nuc_names(:) - character(20), allocatable :: macro_names(:) + character(kind=C_CHAR, len=20), allocatable :: nuc_names(:) + character(kind=C_CHAR, len=20), allocatable :: macro_names(:) real(8) :: volume real(8), allocatable :: nuc_densities(:) integer :: num_nuclides From 2e4684ef48432ca0f58aa90299ccbdcab5e1fba4 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 23 Sep 2018 13:05:05 -0400 Subject: [PATCH 109/175] Added initial Dockerfile to new docker directory --- docker/Dockerfile | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 docker/Dockerfile diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..4eacc8b02 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,48 @@ +FROM ubuntu:latest +MAINTAINER Will Boyd + +# Setup environment variables for Docker image +ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ + PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ + LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ + OPENMC_CROSS_SECTIONS=/opt/openmc/data/nndc_hdf5/cross_sections.xml \ + OPENMC_MULTIPOLE_LIBRARY=/opt/openmc/data/WMP_Library \ + OPENMC_ENDF_DATA=/opt/openmc/data/endf-b-vii.1 + +# Install dependencies from Debian package manager +RUN apt-get update -y && \ + apt-get upgrade -y && \ + apt-get install -y wget git emacs && \ + apt-get install -y gfortran g++ cmake && \ + apt-get install -y mpich libmpich-dev && \ + apt-get install -y libhdf5-serial-dev libhdf5-mpich-dev && \ + apt-get autoremove + +# Download Miniconda3 and install Python dependencies +RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ + /bin/bash ~/miniconda.sh -b -p /opt/conda && \ + rm -rf ~/miniconda.sh +RUN pip install --upgrade pip && \ + pip install six numpy scipy pandas h5py matplotlib uncertainties lxml cython jupyter pytest && \ + pip install --no-binary=mpi4py mpi4py + +# Clone and install NJOY2016 +RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ + cd /opt/NJOY2016 && \ + mkdir build && cd build && \ + cmake -Dstatic=on .. && make 2>/dev/null && make install + +# Clone and install OpenMC +RUN git clone https://github.com/wbinventor/openmc.git /opt/openmc && \ + cd /opt/openmc && mkdir -p build && cd build && \ + cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ + make && make install && \ + cd .. && python setup.py install + +# Download cross sections (NNDC and WMP) and ENDF data needed by test suite +RUN mkdir /opt/openmc/data +RUN wget https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz -O - | tar -C /opt/openmc/data -xvJ +RUN wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C /opt/openmc/data -xvJ +RUN wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz && \ + tar -C /opt/openmc/data -xzvf WMP_Library_v1.0.tar.gz && \ + rm WMP_Library_v1.0.tar.gz \ No newline at end of file From 0e0c1ef5583c3d4259e22eb7727cb93ba037a3a3 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 23 Sep 2018 13:08:24 -0400 Subject: [PATCH 110/175] similar change for using C_DOUBLE vice real(8) --- src/summary.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/summary.F90 b/src/summary.F90 index 820bde31d..b16730052 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -84,7 +84,7 @@ contains integer :: i character(kind=C_CHAR, len=20), allocatable :: nuc_names(:) character(kind=C_CHAR, len=20), allocatable :: macro_names(:) - real(8), allocatable :: awrs(:) + real(C_DOUBLE), allocatable :: awrs(:) integer :: num_nuclides integer :: num_macros integer :: j From b395060793b9aaad6ea0afe44fc2f0306096d287 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 23 Sep 2018 13:43:02 -0400 Subject: [PATCH 111/175] Now install Python API in editable mode to allow openmc.data.reconstruct to be usable by test suite --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4eacc8b02..e3923f4b5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -37,7 +37,7 @@ RUN git clone https://github.com/wbinventor/openmc.git /opt/openmc && \ cd /opt/openmc && mkdir -p build && cd build && \ cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ make && make install && \ - cd .. && python setup.py install + cd .. && pip install -e . # Download cross sections (NNDC and WMP) and ENDF data needed by test suite RUN mkdir /opt/openmc/data From 84bfa09c82ec45d607ff8fd1d8fd070b5c45a7e5 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 23 Sep 2018 13:51:16 -0400 Subject: [PATCH 112/175] updated Dockerfile to clone from main openmc-dev GitHub repo --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e3923f4b5..5f29f8c2f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -33,7 +33,7 @@ RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ cmake -Dstatic=on .. && make 2>/dev/null && make install # Clone and install OpenMC -RUN git clone https://github.com/wbinventor/openmc.git /opt/openmc && \ +RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ cd /opt/openmc && mkdir -p build && cd build && \ cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ make && make install && \ From b69077174d311637fda59cd1de52e336311dd2ff Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 23 Sep 2018 14:00:16 -0400 Subject: [PATCH 113/175] Moved Dockerfile to root context --- Dockerfile | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..5f29f8c2f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +FROM ubuntu:latest +MAINTAINER Will Boyd + +# Setup environment variables for Docker image +ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ + PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ + LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ + OPENMC_CROSS_SECTIONS=/opt/openmc/data/nndc_hdf5/cross_sections.xml \ + OPENMC_MULTIPOLE_LIBRARY=/opt/openmc/data/WMP_Library \ + OPENMC_ENDF_DATA=/opt/openmc/data/endf-b-vii.1 + +# Install dependencies from Debian package manager +RUN apt-get update -y && \ + apt-get upgrade -y && \ + apt-get install -y wget git emacs && \ + apt-get install -y gfortran g++ cmake && \ + apt-get install -y mpich libmpich-dev && \ + apt-get install -y libhdf5-serial-dev libhdf5-mpich-dev && \ + apt-get autoremove + +# Download Miniconda3 and install Python dependencies +RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ + /bin/bash ~/miniconda.sh -b -p /opt/conda && \ + rm -rf ~/miniconda.sh +RUN pip install --upgrade pip && \ + pip install six numpy scipy pandas h5py matplotlib uncertainties lxml cython jupyter pytest && \ + pip install --no-binary=mpi4py mpi4py + +# Clone and install NJOY2016 +RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ + cd /opt/NJOY2016 && \ + mkdir build && cd build && \ + cmake -Dstatic=on .. && make 2>/dev/null && make install + +# Clone and install OpenMC +RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ + cd /opt/openmc && mkdir -p build && cd build && \ + cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ + make && make install && \ + cd .. && pip install -e . + +# Download cross sections (NNDC and WMP) and ENDF data needed by test suite +RUN mkdir /opt/openmc/data +RUN wget https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz -O - | tar -C /opt/openmc/data -xvJ +RUN wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C /opt/openmc/data -xvJ +RUN wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz && \ + tar -C /opt/openmc/data -xzvf WMP_Library_v1.0.tar.gz && \ + rm WMP_Library_v1.0.tar.gz \ No newline at end of file From e851a568618e265829b36d0f166978f113ec9394 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 23 Sep 2018 16:21:18 -0400 Subject: [PATCH 114/175] Updated documentation with Docker installation instructions --- docs/source/quickinstall.rst | 43 ++++++++++++++++++++++ docs/source/usersguide/install.rst | 57 ++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 731bffde7..f172accb3 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -58,6 +58,49 @@ are no longer supported. .. _Personal Package Archive: https://launchpad.net/~paulromano/+archive/staging .. _APT package manager: https://help.ubuntu.com/community/AptGet/Howto +------------------------------------------- +Installing with Docker on Linux/Mac/Windows +------------------------------------------- + +OpenMC can be easily deployed using `Docker `_ on any +Windows, Mac or Linux system. With Docker running, execute the following +command in the shell to build a `Docker image`_ called ``debian/openmc:latest``: + +.. code-block:: sh + + docker build -t debian/openmc:latest https://github.com/openmc-dev/openmc.git#develop + +.. note:: This may take 5 -- 10 minutes to run to completion. + +This command will execute the instructions in OpenMC's ``Dockerfile`` to +build a Docker image with OpenMC installed to ``/opt/openmc``. After building +the Docker image, you can run the following to see the names of all images +on your machine, including ``debian/openmc:latest``: + +.. code-block:: sh + + docker image ls + +Now you can run the following to create a `Docker container`_ called +``my_openmc`` based on the ``debian/openmc:latest`` image: + +.. code-block:: sh + + docker run -it --name=my_openmc debian/openmc:latest + +This command will open an interactive shell running from within the +Docker container where you have access to use OpenMC. + +.. note:: The ``docker run`` command supports many + `options `_ + for spawning containers -- including `mounting volumes`_ from the + host filesystem -- which many users will find useful. + +.. _Docker image: https://docs.docker.com/engine/reference/commandline/images/ +.. _Docker container: https://www.docker.com/resources/what-container +.. _options: https://docs.docker.com/engine/reference/commandline/run/ +.. _mounting volumes: https://docs.docker.com/storage/volumes/ + --------------------------------------- Installing from Source on Ubuntu 15.04+ --------------------------------------- diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 48dcd8c78..17810d23c 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -71,6 +71,63 @@ are no longer supported. .. _Personal Package Archive: https://launchpad.net/~paulromano/+archive/staging .. _APT package manager: https://help.ubuntu.com/community/AptGet/Howto +.. _install_docker: + +------------------------------------------- +Installing with Docker on Linux/Mac/Windows +------------------------------------------- + +OpenMC can be easily deployed using `Docker `_ on any +Windows, Mac or Linux system. With Docker running, execute the following +command in the shell to build a `Docker image`_ called ``debian/openmc:latest``: + +.. code-block:: sh + + docker build -t debian/openmc:latest https://github.com/openmc-dev/openmc.git#develop + +.. note:: This may take 5 -- 10 minutes to run to completion. + +This command will execute the instructions in OpenMC's ``Dockerfile`` to +build a Docker image with OpenMC installed. The image includes OpenMC with +MPICH and parallel HDF5 in the ``/opt/openmc`` directory, and +`Miniconda3 `_ with all of the Python +pre-requisites (NumPy, SciPy, Pandas, etc.) installed. The +`NJOY2016 `_ codebase is installed in +``/opt/NJOY2016`` to support full functionality and testing of the +``openmc.data`` Python module. The publicly available nuclear data libraries +necessary to run OpenMC's test suite -- including NNDC and WMP cross sections +and ENDF data -- are in the ``/opt/openmc/data directory``, and the +corresponding :envvar:`OPENMC_CROSS_SECTIONS`, +:envvar:`OPENMC_MULTIPOLE_LIBRARY`, and :envvar:`OPENMC_ENDF_DATA` +environment variables are initialized. + +After building the Docker image, you can run the following to see the names of +all images on your machine, including ``debian/openmc:latest``: + +.. code-block:: sh + + docker image ls + +Now you can run the following to create a `Docker container`_ called +``my_openmc`` based on the ``debian/openmc:latest`` image: + +.. code-block:: sh + + docker run -it --name=my_openmc debian/openmc:latest + +This command will open an interactive shell running from within the +Docker container where you have access to use OpenMC. + +.. note:: The ``docker run`` command supports many + `options `_ + for spawning containers -- including `mounting volumes`_ from the + host filesystem -- which many users will find useful. + +.. _Docker image: https://docs.docker.com/engine/reference/commandline/images/ +.. _Docker container: https://www.docker.com/resources/what-container +.. _options: https://docs.docker.com/engine/reference/commandline/run/ +.. _mounting volumes: https://docs.docker.com/storage/volumes/ + .. _install_source: ---------------------- From dfcdddeb691775006cfdf54cbc59dfb3ee8f2503 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 23 Sep 2018 16:24:13 -0400 Subject: [PATCH 115/175] Removed docker folder and removed maintainer status from Dockerfile --- Dockerfile | 1 - docker/Dockerfile | 48 ----------------------------------------------- 2 files changed, 49 deletions(-) delete mode 100644 docker/Dockerfile diff --git a/Dockerfile b/Dockerfile index 5f29f8c2f..d452f70b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ FROM ubuntu:latest -MAINTAINER Will Boyd # Setup environment variables for Docker image ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 5f29f8c2f..000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM ubuntu:latest -MAINTAINER Will Boyd - -# Setup environment variables for Docker image -ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ - PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ - LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ - OPENMC_CROSS_SECTIONS=/opt/openmc/data/nndc_hdf5/cross_sections.xml \ - OPENMC_MULTIPOLE_LIBRARY=/opt/openmc/data/WMP_Library \ - OPENMC_ENDF_DATA=/opt/openmc/data/endf-b-vii.1 - -# Install dependencies from Debian package manager -RUN apt-get update -y && \ - apt-get upgrade -y && \ - apt-get install -y wget git emacs && \ - apt-get install -y gfortran g++ cmake && \ - apt-get install -y mpich libmpich-dev && \ - apt-get install -y libhdf5-serial-dev libhdf5-mpich-dev && \ - apt-get autoremove - -# Download Miniconda3 and install Python dependencies -RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ - /bin/bash ~/miniconda.sh -b -p /opt/conda && \ - rm -rf ~/miniconda.sh -RUN pip install --upgrade pip && \ - pip install six numpy scipy pandas h5py matplotlib uncertainties lxml cython jupyter pytest && \ - pip install --no-binary=mpi4py mpi4py - -# Clone and install NJOY2016 -RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ - cd /opt/NJOY2016 && \ - mkdir build && cd build && \ - cmake -Dstatic=on .. && make 2>/dev/null && make install - -# Clone and install OpenMC -RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ - cd /opt/openmc && mkdir -p build && cd build && \ - cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ - make && make install && \ - cd .. && pip install -e . - -# Download cross sections (NNDC and WMP) and ENDF data needed by test suite -RUN mkdir /opt/openmc/data -RUN wget https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz -O - | tar -C /opt/openmc/data -xvJ -RUN wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C /opt/openmc/data -xvJ -RUN wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz && \ - tar -C /opt/openmc/data -xzvf WMP_Library_v1.0.tar.gz && \ - rm WMP_Library_v1.0.tar.gz \ No newline at end of file From c22cc14219692f09b80acf8d3627c7268c6d8f72 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 24 Sep 2018 15:15:38 -0500 Subject: [PATCH 116/175] Don't use VERSION_GREATER_EQUAL in order to support CMake 3.3+ --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 73863bc3b..a9ac17534 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ endif() #=============================================================================== # Allow user to specify HDF5_ROOT -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) +if (NOT (CMAKE_VERSION VERSION_LESS 3.12)) cmake_policy(SET CMP0074 NEW) endif() From afb9f02dbf92c06e58d59021a92706179df46eed Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 20:25:17 -0500 Subject: [PATCH 117/175] Updates to style. Moving dagmc header with other headers. --- {src => include/openmc}/dagmc.h | 4 +-- src/cell.cpp | 8 ++---- src/dagmc.cpp | 50 +++++++++++++-------------------- src/input_xml.F90 | 4 +-- src/surface.cpp | 4 +-- 5 files changed, 27 insertions(+), 43 deletions(-) rename {src => include/openmc}/dagmc.h (84%) diff --git a/src/dagmc.h b/include/openmc/dagmc.h similarity index 84% rename from src/dagmc.h rename to include/openmc/dagmc.h index d417b072f..309cf1706 100644 --- a/src/dagmc.h +++ b/include/openmc/dagmc.h @@ -1,8 +1,8 @@ #ifdef DAGMC -#ifndef DAGMC_H -#define DAGMC_H +#ifndef OPEN_DAGMC_H +#define OPEN_DAGMC_H #include "DagMC.hpp" #include "openmc/cell.h" diff --git a/src/cell.cpp b/src/cell.cpp index ac7bc4568..6fad3adb9 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -18,8 +18,6 @@ //TODO: remove this include #include -//extern "C" {int32_t n_cells {0};} - namespace openmc { //============================================================================== @@ -605,11 +603,9 @@ std::pair DAGCell::distance(Position p, Direction u, int32_t on rval = dagmc_ptr_->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); MB_CHK_ERR_CONT(rval); int surf_idx; - if(hit_surf != 0) { + if (hit_surf != 0) { surf_idx = dagmc_ptr_->index_by_handle(hit_surf); - } - // indicate that particle is lost - else { + } else { // indicate that particle is lost surf_idx = -1; } diff --git a/src/dagmc.cpp b/src/dagmc.cpp index afb319986..4e38263d7 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -1,19 +1,18 @@ #ifdef DAGMC -#include "dagmc.h" +#include "openmc/dagmc.h" #include "openmc/error.h" +#include "openmc/string_functions.h" #include #include moab::DagMC* DAG; -#define TOLOWER(S) std::transform(S.begin(), S.end(), S.begin(), ::tolower) - void load_dagmc_geometry_c() { - if(!DAG) { + if (!DAG) { DAG = new moab::DagMC(); } @@ -35,7 +34,7 @@ void load_dagmc_geometry_c() // initialize cell objects openmc::n_cells = DAG->num_entities(3); - for(int i = 0; i < openmc::n_cells; i++) { + for (int i = 0; i < openmc::n_cells; i++) { moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); // set cell ids using global IDs @@ -55,31 +54,28 @@ void load_dagmc_geometry_c() openmc::universes.back()-> id_ = dagmc_univ_id; openmc::universes.back()->cells_.push_back(i); openmc::universe_map[dagmc_univ_id] = openmc::universes.size() - 1; - } - else { + } else { openmc::universes[it->second]->cells_.push_back(i); } - if(DAG->is_implicit_complement(vol_handle)) { + if (DAG->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now c->material_.push_back(openmc::MATERIAL_VOID); continue; } - if(DAG->has_prop(vol_handle, "mat")){ + if (DAG->has_prop(vol_handle, "mat")){ std::string mat_value; rval = DAG->prop_value(vol_handle, "mat", mat_value); MB_CHK_ERR_CONT(rval); - TOLOWER(mat_value); + openmc::to_lower(mat_value); - if(mat_value == "void" || mat_value == "vacuum") { + if (mat_value == "void" || mat_value == "vacuum") { c->material_.push_back(openmc::MATERIAL_VOID); - } - else { + } else { c->material_.push_back(std::stoi(mat_value)); } - } - else { + } else { std::cout << c->id_ << std::endl; openmc::fatal_error("A volume without a material was found."); } @@ -89,7 +85,7 @@ void load_dagmc_geometry_c() openmc::n_surfaces = DAG->num_entities(2); openmc::surfaces.resize(openmc::n_surfaces); - for(int i = 0; i < openmc::n_surfaces; i++) { + for (int i = 0; i < openmc::n_surfaces; i++) { moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); // set cell ids using global IDs @@ -97,33 +93,27 @@ void load_dagmc_geometry_c() s->id_ = DAG->id_by_index(2, i+1); s->dagmc_ptr_ = DAG; - if(DAG->has_prop(surf_handle, "boundary")) { + if (DAG->has_prop(surf_handle, "boundary")) { std::string bc_value; rval = DAG->prop_value(surf_handle, "boundary", bc_value); MB_CHK_ERR_CONT(rval); - TOLOWER(bc_value); + openmc::to_lower(bc_value); - if(bc_value == "transmit" || bc_value == "transmission") { + if (bc_value == "transmit" || bc_value == "transmission") { s->bc_ = openmc::BC_TRANSMIT; - } - else if(bc_value == "vacuum") { + } else if (bc_value == "vacuum") { s->bc_ = openmc::BC_VACUUM; - } - else if(bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { + } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { s->bc_ = openmc::BC_REFLECT; - } - else if(bc_value == "periodic") { + } else if (bc_value == "periodic") { openmc::fatal_error("Periodic boundary condition not supported in DAGMC."); - } - else { + } else { std::stringstream err_msg; err_msg << "Unknown boundary condition \"" << s->bc_ << "\" specified on surface " << s->id_; openmc::fatal_error(err_msg); } - } - // if no BC property is found, set to transmit - else { + } else { // if no BC property is found, set to transmit s->bc_ = openmc::BC_TRANSMIT; } diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 00415bfe8..f90d874b4 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -638,7 +638,7 @@ contains call surface_dict % set(surfaces(i) % id(), i) end do - end subroutine allocate_surfaces + end subroutine allocate_surfaces subroutine allocate_cells() integer :: i @@ -941,7 +941,7 @@ contains end if ! Create list of macroscopic x/s based on those specified, just treat - ! them as nuclides. This is all really a fadagmce so the user thinks they + ! them as nuclides. This is all really a facade so the user thinks they ! are entering in macroscopic data but the code treats them the same ! as nuclides internally. ! Get pointer list of XML diff --git a/src/surface.cpp b/src/surface.cpp index 832668e06..0ec049bab 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -178,7 +178,7 @@ Surface::Surface(pugi::xml_node surf_node) } } - + bool Surface::sense(Position r, Direction u) const { @@ -1286,8 +1286,6 @@ extern "C" { uvw[2] = u.z; } - void surface_to_hdf5(CSGSurface* surf, hid_t group) {surf->to_hdf5(group);} - bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], double uvw[3]) From 3c12328bc369f1c511860208e8bbe9b9ac704fa4 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 21:02:33 -0500 Subject: [PATCH 118/175] Removing union in Position struct. --- include/openmc/position.h | 4 +++- src/cell.cpp | 8 ++++++-- src/surface.cpp | 8 ++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/openmc/position.h b/include/openmc/position.h index a0106b5f2..62c7f804f 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -58,7 +58,9 @@ struct Position { } // Data members - union{ double xyz[3]; struct{ double x,y,z = 0.0; }; }; + double x = 0.; + double y = 0.; + double z = 0.; }; // Binary operators diff --git a/src/cell.cpp b/src/cell.cpp index 6fad3adb9..d1c865112 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -600,7 +600,9 @@ std::pair DAGCell::distance(Position p, Direction u, int32_t on moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); moab::EntityHandle hit_surf; double dist; - rval = dagmc_ptr_->ray_fire(vol, p.xyz, u.xyz, hit_surf, dist); + double pnt[3] = {p.x, p.y, p.z}; + double dir[3] = {u.x, u.y, u.z}; + rval = dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist); MB_CHK_ERR_CONT(rval); int surf_idx; if (hit_surf != 0) { @@ -619,7 +621,9 @@ bool DAGCell::contains(Position p, Direction u, int32_t on_surface) const { moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); int result = 0; - rval = dagmc_ptr_->point_in_volume(vol, p.xyz, result, u.xyz); + double pnt[3] = {p.x, p.y, p.z}; + double dir[3] = {u.x, u.y, u.z}; + rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir); MB_CHK_ERR_CONT(rval); return bool(result); } diff --git a/src/surface.cpp b/src/surface.cpp index 0ec049bab..00acf0df1 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -260,7 +260,9 @@ double DAGSurface::distance(Position p, Direction u, bool coincident) const { moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); moab::EntityHandle hit_surf; double dist; - rval = dagmc_ptr_->ray_fire(surf, p.xyz, u.xyz, hit_surf, dist, NULL, 0, 0); + double pnt[3] = {p.x, p.y, p.z}; + double dir[3] = {u.x, u.y, u.z}; + rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0); MB_CHK_ERR_CONT(rval); if (dist < 0.0) dist = INFTY; return dist; @@ -270,7 +272,9 @@ Direction DAGSurface::normal(Position p) const { moab::ErrorCode rval; Direction u; moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); - rval = dagmc_ptr_->get_angle(surf, p.xyz, u.xyz); + double pnt[3] = {p.x, p.y, p.z}; + double dir[3] = {u.x, u.y, u.z}; + rval = dagmc_ptr_->get_angle(surf, pnt, dir); MB_CHK_ERR_CONT(rval); return u; } From dc4f56ed0c64a3458f256ef26d3c97c5f25ac2c3 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 21:24:34 -0500 Subject: [PATCH 119/175] Removing explicit keyword from empty constructors. --- include/openmc/cell.h | 6 ++++-- include/openmc/surface.h | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 0b13eef57..b941acd7f 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -113,7 +113,6 @@ public: explicit Cell(pugi::xml_node cell_node); Cell() {}; - //! \brief Determine if a cell contains the particle at a given location. //! //! The bounds of the cell are detemined by a logical expression involving @@ -144,6 +143,7 @@ public: //! @param group_id An HDF5 group id. virtual void to_hdf5(hid_t group_id) const = 0; + virtual ~Cell() {} }; class CSGCell : public Cell @@ -162,6 +162,8 @@ public: void to_hdf5(hid_t group_id) const; + + protected: bool contains_simple(Position r, Direction u, int32_t on_surface) const; bool contains_complex(Position r, Direction u, int32_t on_surface) const; @@ -172,7 +174,7 @@ class DAGCell : public Cell { public: moab::DagMC *dagmc_ptr_; - explicit DAGCell(); + DAGCell(); std::pair distance(Position p, Direction u, int32_t on_surface) const; bool contains(Position p, Direction u, int32_t on_surface) const; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 9c3df8980..3f2b4d14b 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -76,7 +76,7 @@ public: std::vector neighbor_neg_; //!< List of cells on negative side explicit Surface(pugi::xml_node surf_node); - explicit Surface(); + Surface(); virtual ~Surface() {} @@ -124,7 +124,7 @@ class CSGSurface : public Surface { public: explicit CSGSurface(pugi::xml_node surf_node); - explicit CSGSurface(); + CSGSurface(); void to_hdf5(hid_t group_id) const; @@ -140,7 +140,7 @@ class DAGSurface : public Surface { public: moab::DagMC* dagmc_ptr_; - explicit DAGSurface(); + DAGSurface(); double evaluate(Position p) const; double distance(Position p, Direction u, bool coincident) const; From 4fb03807c93607e458dadc1791ac52b7c283e5da Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 21:56:47 -0500 Subject: [PATCH 120/175] Putting blas lapack packages with other apts in Travis yaml. Removing redundant packages. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2bb6e853..edb9cb402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ addons: - libmpich-dev - libhdf5-serial-dev - libhdf5-mpich-dev + - libblas-dev + - liblapack-dev cache: directories: - $HOME/nndc_hdf5 @@ -38,8 +40,6 @@ env: - OMP=n MPI=y PHDF5=y DAGMC=y notifications: webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -before_install: - - sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev libblas-dev liblapack-dev -y install: - ./tools/ci/travis-install.sh before_script: From 879328759105e83615f6f67d84095b0950cc6cea Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 21:57:12 -0500 Subject: [PATCH 121/175] Improvements to dagmc linking into openmc library. --- CMakeLists.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f81a9a1e0..a34542e6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,9 +47,7 @@ if(dagmc) if(NOT DAGMC_FOUND) message(FATAL_ERROR "Could not find DAGMC installation") endif() - add_definitions(-DDAGMC) link_directories(${DAGMC_LIBRARY_DIRS}) - include_directories(${DAGMC_INCLUDE_DIRS}) endif() #=============================================================================== @@ -401,7 +399,6 @@ add_library(libopenmc SHARED src/tallies/trigger.F90 src/tallies/trigger_header.F90 src/dagmc.cpp - src/dagmc.h src/cell.cpp src/cmfd_execute.cpp src/distribution.cpp @@ -491,14 +488,20 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml - faddeeva xtensor ${DAGMC_LIBRARIES}) + faddeeva xtensor ${DAGMC_LIBRARIES}) + +if(dagmc) + target_compile_definitions(libopenmc PRIVATE DAGMC) + target_link_libraries(libopenmc ${DAGMC_LIBRARIES}) + target_include_directories(libopenmc PRIVATE ${DAGMC_INCLUDE_DIRS}) +endif() #=============================================================================== # openmc executable #=============================================================================== add_executable(openmc src/main.cpp) target_compile_options(openmc PRIVATE ${cxxflags}) -target_link_libraries(openmc libopenmc ${DAGMC_LIBRARIES}) +target_link_libraries(openmc libopenmc) #=============================================================================== # Python package From 2ad76be9ebe3c90c1f835e3a22c917c14e1a74c5 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 22:28:31 -0500 Subject: [PATCH 122/175] Code updates/changes as requested by @paulromano --- include/openmc/cell.h | 8 ++--- include/openmc/dagmc.h | 7 ++-- include/openmc/surface.h | 16 +++------- src/cell.cpp | 16 ++++------ src/dagmc.cpp | 69 +++++++++++++++++++++------------------- src/dagmc_header.F90 | 18 +++-------- src/input_xml.F90 | 2 -- src/summary.cpp | 4 +-- src/surface.cpp | 10 +++--- src/tracking.F90 | 3 +- 10 files changed, 67 insertions(+), 86 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index b941acd7f..88996226c 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -172,12 +172,12 @@ protected: #ifdef DAGMC class DAGCell : public Cell { - public: - moab::DagMC *dagmc_ptr_; +public: + moab::DagMC* dagmc_ptr_; DAGCell(); - std::pair distance(Position p, Direction u, int32_t on_surface) const; - bool contains(Position p, Direction u, int32_t on_surface) const; + std::pair distance(Position r, Direction u, int32_t on_surface) const; + bool contains(Position r, Direction u, int32_t on_surface) const; void to_hdf5(hid_t group_id) const; diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 309cf1706..8dd60516f 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -8,11 +8,14 @@ #include "openmc/cell.h" #include "openmc/surface.h" +namespace openmc { + extern moab::DagMC* DAG; -extern "C" void load_dagmc_geometry_c(); -extern "C" void free_memory_dagmc_c(); +extern "C" void load_dagmc_geometry(); +extern "C" void free_memory_dagmc(); +} #endif // DAGMC_H #endif diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 3f2b4d14b..ba97734a2 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -44,15 +44,7 @@ extern std::map surface_map; //============================================================================== struct BoundingBox -{ - - BoundingBox(double x_min, double x_max, - double y_min, double y_max, - double z_min, double z_max) : - xmin(x_min), xmax(x_max), - ymin(y_min), ymax(y_max), - zmin(z_min), zmax(z_max) {} - +{ double xmin; double xmax; double ymin; @@ -141,10 +133,10 @@ class DAGSurface : public Surface public: moab::DagMC* dagmc_ptr_; DAGSurface(); - double evaluate(Position p) const; - double distance(Position p, Direction u, + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position p) const; + Direction normal(Position r) const; //! Get the bounding box of this surface. BoundingBox bounding_box() const; diff --git a/src/cell.cpp b/src/cell.cpp index d1c865112..865dcd5f7 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -595,12 +595,12 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const #ifdef DAGMC DAGCell::DAGCell() : Cell{} {}; -std::pair DAGCell::distance(Position p, Direction u, int32_t on_surface) const { +std::pair DAGCell::distance(Position r, Direction u, int32_t on_surface) const { moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); moab::EntityHandle hit_surf; double dist; - double pnt[3] = {p.x, p.y, p.z}; + double pnt[3] = {r.x, r.y, r.z}; double dir[3] = {u.x, u.y, u.z}; rval = dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist); MB_CHK_ERR_CONT(rval); @@ -611,21 +611,19 @@ std::pair DAGCell::distance(Position p, Direction u, int32_t on surf_idx = -1; } - std::pair result(dist, surf_idx); - - return result; + return {dist, surf_idx}; } -bool DAGCell::contains(Position p, Direction u, int32_t on_surface) const { +bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const { moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); int result = 0; - double pnt[3] = {p.x, p.y, p.z}; + double pnt[3] = {r.x, r.y, r.z}; double dir[3] = {u.x, u.y, u.z}; rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir); MB_CHK_ERR_CONT(rval); - return bool(result); + return result; } void DAGCell::to_hdf5(hid_t group_id) const { return; } @@ -773,7 +771,7 @@ extern "C" { #ifdef DAGMC - int32_t next_cell(DAGCell* cur_cell, DAGSurface *surf_xed ) { + int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed ) { moab::EntityHandle surf = surf_xed->dagmc_ptr_->entity_by_id(2,surf_xed->id_); moab::EntityHandle vol = cur_cell->dagmc_ptr_->entity_by_id(3,cur_cell->id_); diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 4e38263d7..61f6fe789 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -8,9 +8,11 @@ #include #include +namespace openmc { + moab::DagMC* DAG; -void load_dagmc_geometry_c() +void load_dagmc_geometry() { if (!DAG) { DAG = new moab::DagMC(); @@ -24,7 +26,7 @@ void load_dagmc_geometry_c() rval = DAG->init_OBBTree(); MB_CHK_ERR_CONT(rval); - std::vector< std::string > prop_keywords; + std::vector prop_keywords; prop_keywords.push_back("mat"); prop_keywords.push_back("boundary"); @@ -33,34 +35,34 @@ void load_dagmc_geometry_c() MB_CHK_ERR_CONT(rval); // initialize cell objects - openmc::n_cells = DAG->num_entities(3); - for (int i = 0; i < openmc::n_cells; i++) { + n_cells = DAG->num_entities(3); + for (int i = 0; i < n_cells; i++) { moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); // set cell ids using global IDs - openmc::DAGCell* c = new openmc::DAGCell(); + DAGCell* c = new DAGCell(); c->id_ = DAG->id_by_index(3, i+1); c->dagmc_ptr_ = DAG; c->universe_ = dagmc_univ_id; // set to zero for now - c->fill_ = openmc::C_NONE; // no fill, single universe + c->fill_ = C_NONE; // no fill, single universe - openmc::cells.push_back(c); - openmc::cell_map[c->id_] = c->id_; + cells.push_back(c); + cell_map[c->id_] = c->id_; // Populate the Universe vector and dict - auto it = openmc::universe_map.find(dagmc_univ_id); - if (it == openmc::universe_map.end()) { - openmc::universes.push_back(new openmc::Universe()); - openmc::universes.back()-> id_ = dagmc_univ_id; - openmc::universes.back()->cells_.push_back(i); - openmc::universe_map[dagmc_univ_id] = openmc::universes.size() - 1; + auto it = universe_map.find(dagmc_univ_id); + if (it == universe_map.end()) { + universes.push_back(new Universe()); + universes.back()-> id_ = dagmc_univ_id; + universes.back()->cells_.push_back(i); + universe_map[dagmc_univ_id] = universes.size() - 1; } else { - openmc::universes[it->second]->cells_.push_back(i); + universes[it->second]->cells_.push_back(i); } if (DAG->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now - c->material_.push_back(openmc::MATERIAL_VOID); + c->material_.push_back(MATERIAL_VOID); continue; } @@ -68,28 +70,28 @@ void load_dagmc_geometry_c() std::string mat_value; rval = DAG->prop_value(vol_handle, "mat", mat_value); MB_CHK_ERR_CONT(rval); - openmc::to_lower(mat_value); + to_lower(mat_value); if (mat_value == "void" || mat_value == "vacuum") { - c->material_.push_back(openmc::MATERIAL_VOID); + c->material_.push_back(MATERIAL_VOID); } else { c->material_.push_back(std::stoi(mat_value)); } } else { std::cout << c->id_ << std::endl; - openmc::fatal_error("A volume without a material was found."); + fatal_error("A volume without a material was found."); } } // initialize surface objects - openmc::n_surfaces = DAG->num_entities(2); - openmc::surfaces.resize(openmc::n_surfaces); + n_surfaces = DAG->num_entities(2); + surfaces.resize(n_surfaces); - for (int i = 0; i < openmc::n_surfaces; i++) { + for (int i = 0; i < n_surfaces; i++) { moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); // set cell ids using global IDs - openmc::DAGSurface* s = new openmc::DAGSurface(); + DAGSurface* s = new DAGSurface(); s->id_ = DAG->id_by_index(2, i+1); s->dagmc_ptr_ = DAG; @@ -97,37 +99,38 @@ void load_dagmc_geometry_c() std::string bc_value; rval = DAG->prop_value(surf_handle, "boundary", bc_value); MB_CHK_ERR_CONT(rval); - openmc::to_lower(bc_value); + to_lower(bc_value); if (bc_value == "transmit" || bc_value == "transmission") { - s->bc_ = openmc::BC_TRANSMIT; + s->bc_ = BC_TRANSMIT; } else if (bc_value == "vacuum") { - s->bc_ = openmc::BC_VACUUM; + s->bc_ = BC_VACUUM; } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { - s->bc_ = openmc::BC_REFLECT; + s->bc_ = BC_REFLECT; } else if (bc_value == "periodic") { - openmc::fatal_error("Periodic boundary condition not supported in DAGMC."); + fatal_error("Periodic boundary condition not supported in DAGMC."); } else { std::stringstream err_msg; err_msg << "Unknown boundary condition \"" << s->bc_ << "\" specified on surface " << s->id_; - openmc::fatal_error(err_msg); + fatal_error(err_msg); } } else { // if no BC property is found, set to transmit - s->bc_ = openmc::BC_TRANSMIT; + s->bc_ = BC_TRANSMIT; } // add to global array and map - openmc::surfaces[i] = s; - openmc::surface_map[s->id_] = s->id_; + surfaces[i] = s; + surface_map[s->id_] = s->id_; } return; } -void free_memory_dagmc_c() +void free_memory_dagmc() { delete DAG; } +} #endif diff --git a/src/dagmc_header.F90 b/src/dagmc_header.F90 index cb9b66481..9895791ac 100644 --- a/src/dagmc_header.F90 +++ b/src/dagmc_header.F90 @@ -7,24 +7,14 @@ module dagmc_header implicit none interface - subroutine load_dagmc_geometry_c() bind(C) - end subroutine load_dagmc_geometry_c + subroutine load_dagmc_geometry() bind(C) + end subroutine load_dagmc_geometry - subroutine free_memory_dagmc_c() bind(C) - end subroutine free_memory_dagmc_c + subroutine free_memory_dagmc() bind(C) + end subroutine free_memory_dagmc end interface -contains - - subroutine load_dagmc_geometry() - call load_dagmc_geometry_c() - end subroutine load_dagmc_geometry - - subroutine free_memory_dagmc() - call free_memory_dagmc_c() - end subroutine free_memory_dagmc - end module dagmc_header #endif diff --git a/src/input_xml.F90 b/src/input_xml.F90 index f90d874b4..9fefbbfcd 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -403,8 +403,6 @@ contains root_universe = find_root_universe() - return - end subroutine read_geometry_dagmc #endif diff --git a/src/summary.cpp b/src/summary.cpp index 4d54b2c86..7a0c4324a 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -10,9 +10,7 @@ extern "C" void write_geometry(hid_t file_id) { #ifdef DAGMC - if (settings::dagmc) { - return; - } + if (settings::dagmc) return; #endif auto geom_group = create_group(file_id, "geometry"); diff --git a/src/surface.cpp b/src/surface.cpp index 00acf0df1..85543fe26 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -255,12 +255,12 @@ double DAGSurface::evaluate(Position r) const return 0.0; } -double DAGSurface::distance(Position p, Direction u, bool coincident) const { +double DAGSurface::distance(Position r, Direction u, bool coincident) const { moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); moab::EntityHandle hit_surf; double dist; - double pnt[3] = {p.x, p.y, p.z}; + double pnt[3] = {r.x, r.y, r.z}; double dir[3] = {u.x, u.y, u.z}; rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0); MB_CHK_ERR_CONT(rval); @@ -268,11 +268,11 @@ double DAGSurface::distance(Position p, Direction u, bool coincident) const { return dist; } -Direction DAGSurface::normal(Position p) const { +Direction DAGSurface::normal(Position r) const { moab::ErrorCode rval; Direction u; moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); - double pnt[3] = {p.x, p.y, p.z}; + double pnt[3] = {r.x, r.y, r.z}; double dir[3] = {u.x, u.y, u.z}; rval = dagmc_ptr_->get_angle(surf, pnt, dir); MB_CHK_ERR_CONT(rval); @@ -285,7 +285,7 @@ BoundingBox DAGSurface::bounding_box() const { double min[3], max[3]; rval = dagmc_ptr_->getobb(surf, min, max); MB_CHK_ERR_CONT(rval); - return BoundingBox(min[0], max[0], min[1], max[1], min[2], max[2]); + return {min[0], max[0], min[1], max[1], min[2], max[2]}; } void DAGSurface::to_hdf5(hid_t group_id) const {} diff --git a/src/tracking.F90 b/src/tracking.F90 index 352d9bc7b..8cf2fc05c 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -319,7 +319,6 @@ contains class(Surface), pointer :: surf class(Surface), pointer :: surf2 ! periodic partner surface - i_surface = abs(p % surface) surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then @@ -475,7 +474,7 @@ contains #ifdef DAGMC if (dagmc) then - i_cell = next_cell(cells(p % last_cell(1) + 1), surfaces(ABS(p % surface))) + i_cell = next_cell(cells(p % last_cell(1) + 1), surfaces(abs(p % surface))) ! save material and temp p % last_material = p % material p % last_sqrtkT = p % sqrtKT From d32a8cf80e0400e5042acf1c30d2fb7fd53860b0 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 22:53:47 -0500 Subject: [PATCH 123/175] Adding dagmc to python settings module and XML/RELAX NG. --- openmc/settings.py | 21 ++++++++++++++++++++- src/relaxng/settings.rnc | 2 ++ src/relaxng/settings.rng | 5 +++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/openmc/settings.py b/openmc/settings.py index efe41b2a1..8d5c9db0d 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -37,6 +37,8 @@ class Settings(object): weight assigned to particles that are not killed after Russian roulette. Value of energy should be a float indicating energy in eV below which particle type will be killed. + dagmc : bool + Indicate that a CAD-based DAGMC geometry will be used. electron_treatment : {'led', 'ttb'} Whether to deposit all energy from electrons locally ('led') or create secondary bremsstrahlung photons ('ttb'). @@ -224,6 +226,9 @@ class Settings(object): self._create_fission_neutrons = None self._log_grid_bins = None + # dagmc + self._dagmc = None + @property def run_mode(self): return self._run_mode @@ -368,6 +373,10 @@ class Settings(object): def log_grid_bins(self): return self._log_grid_bins + @property + def dagmc(self): + return self._dagmc + @run_mode.setter def run_mode(self, run_mode): cv.check_value('run mode', run_mode, _RUN_MODES) @@ -511,6 +520,11 @@ class Settings(object): cv.check_type('photon transport', photon_transport, bool) self._photon_transport = photon_transport + @dagmc.setter + def dagmc(self, dagmc): + cv.check_type('dagmc geometry', dagmc, bool) + self._dagmc = dagmc + @ptables.setter def ptables(self, ptables): cv.check_type('probability tables', ptables, bool) @@ -945,6 +959,11 @@ class Settings(object): elem = ET.SubElement(root, "log_grid_bins") elem.text = str(self._log_grid_bins) + def _create_dagmc_subelement(self, root): + if self._dagmc is not None: + elem = ET.SubElement(root, "dagmc") + element.text = str(self._dagmc).lower() + def export_to_xml(self, path='settings.xml'): """Export simulation settings to an XML file. @@ -992,7 +1011,7 @@ class Settings(object): self._create_volume_calcs_subelement(root_element) self._create_create_fission_neutrons_subelement(root_element) self._create_log_grid_bins_subelement(root_element) - + self._create_dagmc_subelement(root_element) # Clean the indentation in the file to be user-readable clean_indentation(root_element) diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc index 37bc3f66e..83d9bed0c 100644 --- a/src/relaxng/settings.rnc +++ b/src/relaxng/settings.rnc @@ -57,6 +57,8 @@ element settings { element ptables { xsd:boolean }? & + element dagmc { xsd:boolean }? & + element run_cmfd { xsd:boolean }? & element run_mode { xsd:string }? & diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng index 549ea83df..92a1d748a 100644 --- a/src/relaxng/settings.rng +++ b/src/relaxng/settings.rng @@ -254,6 +254,11 @@ + + + + + From 22448ee005a4bcb09db91452b610aca34907e4c5 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 23:00:50 -0500 Subject: [PATCH 124/175] Moving CAD test to regression tests. --- tests/regression_tests/cad/__init__.py | 1 + .../cad/conftest.py | 0 .../{unit_tests => regression_tests}/cad/dagmc.h5m | Bin .../cad/materials.xml | 0 .../cad/settings.xml | 0 .../cad/tallies.xml | 0 .../test_cad.py => regression_tests/cad/test.py} | 0 tests/unit_tests/cad/__init__.py | 9 --------- 8 files changed, 1 insertion(+), 9 deletions(-) create mode 100644 tests/regression_tests/cad/__init__.py rename tests/{unit_tests => regression_tests}/cad/conftest.py (100%) rename tests/{unit_tests => regression_tests}/cad/dagmc.h5m (100%) rename tests/{unit_tests => regression_tests}/cad/materials.xml (100%) rename tests/{unit_tests => regression_tests}/cad/settings.xml (100%) rename tests/{unit_tests => regression_tests}/cad/tallies.xml (100%) rename tests/{unit_tests/cad/test_cad.py => regression_tests/cad/test.py} (100%) delete mode 100644 tests/unit_tests/cad/__init__.py diff --git a/tests/regression_tests/cad/__init__.py b/tests/regression_tests/cad/__init__.py new file mode 100644 index 000000000..5871ed8ee --- /dev/null +++ b/tests/regression_tests/cad/__init__.py @@ -0,0 +1 @@ +import pytest diff --git a/tests/unit_tests/cad/conftest.py b/tests/regression_tests/cad/conftest.py similarity index 100% rename from tests/unit_tests/cad/conftest.py rename to tests/regression_tests/cad/conftest.py diff --git a/tests/unit_tests/cad/dagmc.h5m b/tests/regression_tests/cad/dagmc.h5m similarity index 100% rename from tests/unit_tests/cad/dagmc.h5m rename to tests/regression_tests/cad/dagmc.h5m diff --git a/tests/unit_tests/cad/materials.xml b/tests/regression_tests/cad/materials.xml similarity index 100% rename from tests/unit_tests/cad/materials.xml rename to tests/regression_tests/cad/materials.xml diff --git a/tests/unit_tests/cad/settings.xml b/tests/regression_tests/cad/settings.xml similarity index 100% rename from tests/unit_tests/cad/settings.xml rename to tests/regression_tests/cad/settings.xml diff --git a/tests/unit_tests/cad/tallies.xml b/tests/regression_tests/cad/tallies.xml similarity index 100% rename from tests/unit_tests/cad/tallies.xml rename to tests/regression_tests/cad/tallies.xml diff --git a/tests/unit_tests/cad/test_cad.py b/tests/regression_tests/cad/test.py similarity index 100% rename from tests/unit_tests/cad/test_cad.py rename to tests/regression_tests/cad/test.py diff --git a/tests/unit_tests/cad/__init__.py b/tests/unit_tests/cad/__init__.py deleted file mode 100644 index 59a520c12..000000000 --- a/tests/unit_tests/cad/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -import numpy as np -import pytest - - -def assert_unbounded(obj): - """Assert that a region/cell is unbounded.""" - ll, ur = obj.bounding_box - assert ll == pytest.approx((-np.inf, -np.inf, -np.inf)) - assert ur == pytest.approx((np.inf, np.inf, np.inf)) From 90185f5397d13f0f42ccf6564a0ddd0c4533fbc8 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Tue, 25 Sep 2018 23:01:27 -0500 Subject: [PATCH 125/175] Removing conftest, relying on file in directory above. --- tests/regression_tests/cad/conftest.py | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 tests/regression_tests/cad/conftest.py diff --git a/tests/regression_tests/cad/conftest.py b/tests/regression_tests/cad/conftest.py deleted file mode 100644 index 4e36edf67..000000000 --- a/tests/regression_tests/cad/conftest.py +++ /dev/null @@ -1,16 +0,0 @@ -import openmc -import pytest - - - -@pytest.fixture(scope='module', autouse=True) -def setup_cad_test(request): - # Reset autogenerated IDs assigned to OpenMC objects - openmc.reset_auto_ids() - - # Change to test directory - olddir = request.fspath.dirpath().chdir() - try: - yield - finally: - olddir.chdir() From 93b3e63eeb8acdb877348d909cd6055991a86407 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 10:19:15 -0500 Subject: [PATCH 126/175] Updating skip condition for dagmc test. --- tests/regression_tests/cad/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression_tests/cad/test.py b/tests/regression_tests/cad/test.py index 4ae75ff76..8c54bec18 100644 --- a/tests/regression_tests/cad/test.py +++ b/tests/regression_tests/cad/test.py @@ -3,8 +3,8 @@ import os import pytest pytestmark = pytest.mark.skipif( - os.environ.get('CAD') != 'y', - reason="CAD build is not enabled.") + os.environ.get('DAGMC') != 'y', + reason="DAGMC CAD geometry is not enabled.") def test_cad(): harness = CADTestHarness('statepoint.15.h5') From b8daf739ab0db23460f99c46c5ed46c54b0593c2 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 10:19:33 -0500 Subject: [PATCH 127/175] Renaming cad test to dagmc. --- tests/regression_tests/{cad => dagmc}/__init__.py | 0 tests/regression_tests/{cad => dagmc}/dagmc.h5m | Bin tests/regression_tests/{cad => dagmc}/materials.xml | 0 tests/regression_tests/{cad => dagmc}/settings.xml | 0 tests/regression_tests/{cad => dagmc}/tallies.xml | 0 tests/regression_tests/{cad => dagmc}/test.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression_tests/{cad => dagmc}/__init__.py (100%) rename tests/regression_tests/{cad => dagmc}/dagmc.h5m (100%) rename tests/regression_tests/{cad => dagmc}/materials.xml (100%) rename tests/regression_tests/{cad => dagmc}/settings.xml (100%) rename tests/regression_tests/{cad => dagmc}/tallies.xml (100%) rename tests/regression_tests/{cad => dagmc}/test.py (100%) diff --git a/tests/regression_tests/cad/__init__.py b/tests/regression_tests/dagmc/__init__.py similarity index 100% rename from tests/regression_tests/cad/__init__.py rename to tests/regression_tests/dagmc/__init__.py diff --git a/tests/regression_tests/cad/dagmc.h5m b/tests/regression_tests/dagmc/dagmc.h5m similarity index 100% rename from tests/regression_tests/cad/dagmc.h5m rename to tests/regression_tests/dagmc/dagmc.h5m diff --git a/tests/regression_tests/cad/materials.xml b/tests/regression_tests/dagmc/materials.xml similarity index 100% rename from tests/regression_tests/cad/materials.xml rename to tests/regression_tests/dagmc/materials.xml diff --git a/tests/regression_tests/cad/settings.xml b/tests/regression_tests/dagmc/settings.xml similarity index 100% rename from tests/regression_tests/cad/settings.xml rename to tests/regression_tests/dagmc/settings.xml diff --git a/tests/regression_tests/cad/tallies.xml b/tests/regression_tests/dagmc/tallies.xml similarity index 100% rename from tests/regression_tests/cad/tallies.xml rename to tests/regression_tests/dagmc/tallies.xml diff --git a/tests/regression_tests/cad/test.py b/tests/regression_tests/dagmc/test.py similarity index 100% rename from tests/regression_tests/cad/test.py rename to tests/regression_tests/dagmc/test.py From 6847340f3bf537aa3b6bcdc37414ac71120d07b8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 26 Sep 2018 10:22:57 -0500 Subject: [PATCH 128/175] Remove references to compact fission energy release library (removed in #1032) --- docs/source/io_formats/fission_energy.rst | 53 ----------------------- docs/source/io_formats/index.rst | 1 - docs/source/pythonapi/data.rst | 1 - openmc/data/fission_energy.py | 4 -- 4 files changed, 59 deletions(-) delete mode 100644 docs/source/io_formats/fission_energy.rst diff --git a/docs/source/io_formats/fission_energy.rst b/docs/source/io_formats/fission_energy.rst deleted file mode 100644 index f80db4569..000000000 --- a/docs/source/io_formats/fission_energy.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. _usersguide_fission_energy: - -================================== -Fission Energy Release File Format -================================== - -This file is a compact HDF5 representation of the ENDF MT=1, MF=458 data (see -ENDF-102_ for details). It gives the information needed to compute the energy -carried away from fission reactions by each reaction product (e.g. fragment -nuclei, neutrons) which depends on the incident neutron energy. OpenMC is -distributed with one of these files under -data/fission_Q_data_endfb71.h5. More files of this format can be created from -ENDF files with the -``openmc.data.write_compact_458_library`` function. They can be read with the -``openmc.data.FissionEnergyRelease.from_compact_hdf5`` class method. - -:Attributes: - **comment** (*char[]*) -- An optional text comment - - **component order** (*char[][]*) -- An array of strings - specifying the order each reaction product occurs in the data - arrays. The components use the 2-3 letter abbreviations - specified in ENDF-102 e.g. EFR for fission fragments and ENP for - prompt neutrons. - -**//** - Nuclides are named by concatenating their atomic symbol and mass number. For - example, 'U235' or 'Pu239'. Metastable nuclides are appended with an - '_m' and their metastable number. For example, 'Am242_m1' - -:Datasets: - - **data** (*double[][][]*) -- The energy release coefficients. The - first axis indexes the component type. The second axis specifies - values or uncertainties. The third axis indexes the polynomial - order. If the data uses the Sher-Beck format, then the last axis - will have a length of one and ENDF-102 should be consulted for - energy dependence. Otherwise, the data uses the Madland format - which is a polynomial of incident energy. - - For example, if 'EFR' is given first in the **component order** - attribute and the data uses the Madland format, then the energy - released in the form of fission fragments at an incident energy - :math:`E` is given by - - .. math:: - \text{data}[0, 0, 0] + \text{data}[0, 0, 1] \cdot E - + \text{data}[0, 0, 2] \cdot E^2 + \ldots - - And its uncertainty is - - .. math:: - \text{data}[0, 1, 0] + \text{data}[0, 1, 1] \cdot E - + \text{data}[0, 1, 2] \cdot E^2 + \ldots - -.. _ENDF-102: http://www.nndc.bnl.gov/endfdocs/ENDF-102-2012.pdf diff --git a/docs/source/io_formats/index.rst b/docs/source/io_formats/index.rst index c1bb76a29..ef83bd23d 100644 --- a/docs/source/io_formats/index.rst +++ b/docs/source/io_formats/index.rst @@ -34,7 +34,6 @@ Data Files nuclear_data mgxs_library data_wmp - fission_energy ------------ Output Files diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 9c42f75fa..5cf74bce0 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -39,7 +39,6 @@ Core Functions openmc.data.linearize openmc.data.thin openmc.data.water_density - openmc.data.write_compact_458_library openmc.data.zam Angle-Energy Distributions diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index fed4b21a3..ee2d95078 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -43,10 +43,6 @@ class FissionEnergyRelease(EqualityMixin): dataset. The :meth:`FissionEnergyRelease.from_hdf5` method builds this class from the usual OpenMC HDF5 data files. :meth:`FissionEnergyRelease.from_endf` uses ENDF-formatted data. - :meth:`FissionEnergyRelease.from_compact_hdf5` uses a different HDF5 format - that is meant to be compact and store the exact same data as the ENDF - format. Files with this format can be generated with the - :func:`openmc.data.write_compact_458_library` function. References ---------- From c664a2274d2554e0b52738c5be428571bd2c1c8d Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:23:41 -0500 Subject: [PATCH 129/175] Removing trailing white space. --- include/openmc/surface.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index ba97734a2..3be73bbd9 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -44,7 +44,7 @@ extern std::map surface_map; //============================================================================== struct BoundingBox -{ +{ double xmin; double xmax; double ymin; @@ -69,7 +69,7 @@ public: explicit Surface(pugi::xml_node surf_node); Surface(); - + virtual ~Surface() {} //! Determine which side of a surface a point lies on. @@ -109,7 +109,7 @@ public: //! \param group_id An HDF5 group id. //TODO: this probably needs to include i_periodic for PeriodicSurface virtual void to_hdf5(hid_t group_id) const = 0; - + }; class CSGSurface : public Surface @@ -119,11 +119,11 @@ class CSGSurface : public Surface CSGSurface(); void to_hdf5(hid_t group_id) const; - + protected: - virtual void to_hdf5_inner(hid_t group_id) const = 0; + virtual void to_hdf5_inner(hid_t group_id) const = 0; }; - + //============================================================================== //! A `Surface` representing a DAGMC-based surface in DAGMC. //============================================================================== @@ -142,7 +142,7 @@ class DAGSurface : public Surface void to_hdf5(hid_t group_id) const; }; -#endif +#endif //============================================================================== //! A `Surface` that supports periodic boundary conditions. //! From aabdb9aabc0e0f32b616bca38eb0735c4ce02507 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Wed, 26 Sep 2018 23:24:45 -0400 Subject: [PATCH 130/175] Added docker download script --- docker/docker-download-xs.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 docker/docker-download-xs.sh diff --git a/docker/docker-download-xs.sh b/docker/docker-download-xs.sh new file mode 100755 index 000000000..5ac270090 --- /dev/null +++ b/docker/docker-download-xs.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -ex + +# Download NNDC HDF5 data +if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then + wget https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz -O - | tar -C $HOME -xvJ +fi + +# Download ENDF/B-VII.1 distribution +ENDF=$HOME/endf-b-vii.1/ +if [[ ! -d $ENDF/neutrons || ! -d $ENDF/photoat || ! -d $ENDF/atomic_relax ]]; then + wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C $HOME -xvJ +fi + +# Download multipole library +if [[ ! -e $HOME/WMP_Library/092235.h5 ]]; then + wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz + tar -C $HOME -xzvf WMP_Library_v1.0.tar.gz +fi From 2aa3cb61f492545bc8a486d04b018ab709d4e19a Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:28:35 -0500 Subject: [PATCH 131/175] Fixing indentation in surface header. --- include/openmc/surface.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 3be73bbd9..1eb505e45 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -114,13 +114,13 @@ public: class CSGSurface : public Surface { - public: +public: explicit CSGSurface(pugi::xml_node surf_node); CSGSurface(); void to_hdf5(hid_t group_id) const; - protected: +protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; }; @@ -130,7 +130,7 @@ class CSGSurface : public Surface #ifdef DAGMC class DAGSurface : public Surface { - public: +public: moab::DagMC* dagmc_ptr_; DAGSurface(); double evaluate(Position r) const; From fd23ea2a8a33d8739a6b991a368e5e37ceebc19f Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:30:10 -0500 Subject: [PATCH 132/175] Corrections to openmc settings module. --- openmc/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/settings.py b/openmc/settings.py index 8d5c9db0d..af64af01b 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -226,7 +226,6 @@ class Settings(object): self._create_fission_neutrons = None self._log_grid_bins = None - # dagmc self._dagmc = None @property @@ -1012,6 +1011,7 @@ class Settings(object): self._create_create_fission_neutrons_subelement(root_element) self._create_log_grid_bins_subelement(root_element) self._create_dagmc_subelement(root_element) + # Clean the indentation in the file to be user-readable clean_indentation(root_element) From 6996b9006969707672436249528ff4672c84b5cd Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:34:46 -0500 Subject: [PATCH 133/175] Removing un-needed include. --- src/cell.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 865dcd5f7..ac105c37e 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -15,9 +15,6 @@ #include "openmc/surface.h" #include "openmc/xml_interface.h" -//TODO: remove this include -#include - namespace openmc { //============================================================================== From cc3e85db99ecf9de47a3427ae6a2a873013d6ca3 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Wed, 26 Sep 2018 23:40:11 -0400 Subject: [PATCH 134/175] Updated Dockerfile to call new docker-download-xs.sh script --- Dockerfile | 20 +++++++------------- docker/Dockerfile | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 docker/Dockerfile diff --git a/Dockerfile b/Dockerfile index d452f70b9..b40548420 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,9 +4,9 @@ FROM ubuntu:latest ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ - OPENMC_CROSS_SECTIONS=/opt/openmc/data/nndc_hdf5/cross_sections.xml \ - OPENMC_MULTIPOLE_LIBRARY=/opt/openmc/data/WMP_Library \ - OPENMC_ENDF_DATA=/opt/openmc/data/endf-b-vii.1 + OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml \ + OPENMC_MULTIPOLE_LIBRARY=/root/WMP_Library \ + OPENMC_ENDF_DATA=/root/endf-b-vii.1 # Install dependencies from Debian package manager RUN apt-get update -y && \ @@ -15,15 +15,14 @@ RUN apt-get update -y && \ apt-get install -y gfortran g++ cmake && \ apt-get install -y mpich libmpich-dev && \ apt-get install -y libhdf5-serial-dev libhdf5-mpich-dev && \ + apt-get install -y imagemagick && \ apt-get autoremove # Download Miniconda3 and install Python dependencies RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ /bin/bash ~/miniconda.sh -b -p /opt/conda && \ rm -rf ~/miniconda.sh -RUN pip install --upgrade pip && \ - pip install six numpy scipy pandas h5py matplotlib uncertainties lxml cython jupyter pytest && \ - pip install --no-binary=mpi4py mpi4py +RUN pip install --upgrade pip # Clone and install NJOY2016 RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ @@ -36,12 +35,7 @@ RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ cd /opt/openmc && mkdir -p build && cd build && \ cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ make && make install && \ - cd .. && pip install -e . + cd .. && pip install -e .[test] # Download cross sections (NNDC and WMP) and ENDF data needed by test suite -RUN mkdir /opt/openmc/data -RUN wget https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz -O - | tar -C /opt/openmc/data -xvJ -RUN wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C /opt/openmc/data -xvJ -RUN wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz && \ - tar -C /opt/openmc/data -xzvf WMP_Library_v1.0.tar.gz && \ - rm WMP_Library_v1.0.tar.gz \ No newline at end of file +RUN ./opt/openmc/docker/docker-download-xs.sh \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..b40548420 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,41 @@ +FROM ubuntu:latest + +# Setup environment variables for Docker image +ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ + PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ + LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ + OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml \ + OPENMC_MULTIPOLE_LIBRARY=/root/WMP_Library \ + OPENMC_ENDF_DATA=/root/endf-b-vii.1 + +# Install dependencies from Debian package manager +RUN apt-get update -y && \ + apt-get upgrade -y && \ + apt-get install -y wget git emacs && \ + apt-get install -y gfortran g++ cmake && \ + apt-get install -y mpich libmpich-dev && \ + apt-get install -y libhdf5-serial-dev libhdf5-mpich-dev && \ + apt-get install -y imagemagick && \ + apt-get autoremove + +# Download Miniconda3 and install Python dependencies +RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ + /bin/bash ~/miniconda.sh -b -p /opt/conda && \ + rm -rf ~/miniconda.sh +RUN pip install --upgrade pip + +# Clone and install NJOY2016 +RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ + cd /opt/NJOY2016 && \ + mkdir build && cd build && \ + cmake -Dstatic=on .. && make 2>/dev/null && make install + +# Clone and install OpenMC +RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ + cd /opt/openmc && mkdir -p build && cd build && \ + cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ + make && make install && \ + cd .. && pip install -e .[test] + +# Download cross sections (NNDC and WMP) and ENDF data needed by test suite +RUN ./opt/openmc/docker/docker-download-xs.sh \ No newline at end of file From 5f078b684c22321c16564b025c6b055d04394ebe Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:46:33 -0500 Subject: [PATCH 135/175] Updating function styles. --- src/cell.cpp | 8 ++++++-- src/surface.cpp | 12 ++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index ac105c37e..7364fd1e1 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -592,7 +592,9 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const #ifdef DAGMC DAGCell::DAGCell() : Cell{} {}; -std::pair DAGCell::distance(Position r, Direction u, int32_t on_surface) const { +std::pair +DAGCell::distance(Position r, Direction u, int32_t on_surface) const +{ moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); moab::EntityHandle hit_surf; @@ -611,7 +613,8 @@ std::pair DAGCell::distance(Position r, Direction u, int32_t on return {dist, surf_idx}; } -bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const { +bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const +{ moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); @@ -624,6 +627,7 @@ bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const { } void DAGCell::to_hdf5(hid_t group_id) const { return; } + #endif //============================================================================== diff --git a/src/surface.cpp b/src/surface.cpp index 85543fe26..b2dbcf874 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -139,7 +139,7 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, //============================================================================== Surface::Surface() {} // empty constructor - + Surface::Surface(pugi::xml_node surf_node) { if (check_for_node(surf_node, "id")) { @@ -255,7 +255,9 @@ double DAGSurface::evaluate(Position r) const return 0.0; } -double DAGSurface::distance(Position r, Direction u, bool coincident) const { +double +DAGSurface::distance(Position r, Direction u, bool coincident) const +{ moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); moab::EntityHandle hit_surf; @@ -268,7 +270,8 @@ double DAGSurface::distance(Position r, Direction u, bool coincident) const { return dist; } -Direction DAGSurface::normal(Position r) const { +Direction DAGSurface::normal(Position r) const +{ moab::ErrorCode rval; Direction u; moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); @@ -279,7 +282,8 @@ Direction DAGSurface::normal(Position r) const { return u; } -BoundingBox DAGSurface::bounding_box() const { +BoundingBox DAGSurface::bounding_box() const +{ moab::ErrorCode rval; moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); double min[3], max[3]; From 60e57d3ed7929993ba773853dce4bc36f559f639 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:49:37 -0500 Subject: [PATCH 136/175] Fixing tabs. --- src/dagmc.cpp | 20 ++++++++++---------- src/settings.cpp | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 61f6fe789..fa9ca3095 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -73,9 +73,9 @@ void load_dagmc_geometry() to_lower(mat_value); if (mat_value == "void" || mat_value == "vacuum") { - c->material_.push_back(MATERIAL_VOID); + c->material_.push_back(MATERIAL_VOID); } else { - c->material_.push_back(std::stoi(mat_value)); + c->material_.push_back(std::stoi(mat_value)); } } else { std::cout << c->id_ << std::endl; @@ -102,18 +102,18 @@ void load_dagmc_geometry() to_lower(bc_value); if (bc_value == "transmit" || bc_value == "transmission") { - s->bc_ = BC_TRANSMIT; + s->bc_ = BC_TRANSMIT; } else if (bc_value == "vacuum") { - s->bc_ = BC_VACUUM; + s->bc_ = BC_VACUUM; } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { - s->bc_ = BC_REFLECT; + s->bc_ = BC_REFLECT; } else if (bc_value == "periodic") { - fatal_error("Periodic boundary condition not supported in DAGMC."); + fatal_error("Periodic boundary condition not supported in DAGMC."); } else { - std::stringstream err_msg; - err_msg << "Unknown boundary condition \"" << s->bc_ - << "\" specified on surface " << s->id_; - fatal_error(err_msg); + std::stringstream err_msg; + err_msg << "Unknown boundary condition \"" << s->bc_ + << "\" specified on surface " << s->id_; + fatal_error(err_msg); } } else { // if no BC property is found, set to transmit s->bc_ = BC_TRANSMIT; diff --git a/src/settings.cpp b/src/settings.cpp index 311ba1af3..04facb2f4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -210,7 +210,7 @@ void read_settings_xml() // DAGMC geometry check if (check_for_node(root, "dagmc")) { - dagmc = get_node_value_bool(root, "dagmc"); + dagmc = get_node_value_bool(root, "dagmc"); } #ifndef DAGMC From 33da7d0b161d4ed5e129ca188072952cd8d43739 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:53:00 -0500 Subject: [PATCH 137/175] Reducing number of particles run in dagmc test. --- tests/regression_tests/dagmc/settings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regression_tests/dagmc/settings.xml b/tests/regression_tests/dagmc/settings.xml index 89b797687..508362378 100644 --- a/tests/regression_tests/dagmc/settings.xml +++ b/tests/regression_tests/dagmc/settings.xml @@ -3,9 +3,9 @@ eigenvalue true - 15 - 5 - 10000 + 5 + 0 + 100 From b93777f4232d8a4abc5644249ff8859790145a86 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 22:54:19 -0500 Subject: [PATCH 138/175] Simplifying tallies in dagmc test. --- tests/regression_tests/dagmc/tallies.xml | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/tests/regression_tests/dagmc/tallies.xml b/tests/regression_tests/dagmc/tallies.xml index 62a870c02..9b8b00cd6 100644 --- a/tests/regression_tests/dagmc/tallies.xml +++ b/tests/regression_tests/dagmc/tallies.xml @@ -5,27 +5,9 @@ 1 - - 0 20.0e6 - - - - 0 20.0e6 - - 1 - total scatter nu-scatter absorption fission nu-fission - - - - 1 2 - total scatter nu-scatter absorption fission nu-fission - - - - 1 2 3 - scatter nu-scatter nu-fission + total From 937acbc44da2da6ad2dc0802ffff9c25cd02513f Mon Sep 17 00:00:00 2001 From: pshriwise Date: Thu, 27 Sep 2018 06:51:11 -0500 Subject: [PATCH 139/175] Updating statepoint filename. --- tests/regression_tests/dagmc/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/dagmc/test.py b/tests/regression_tests/dagmc/test.py index 8c54bec18..f230e9ed2 100644 --- a/tests/regression_tests/dagmc/test.py +++ b/tests/regression_tests/dagmc/test.py @@ -7,5 +7,5 @@ pytestmark = pytest.mark.skipif( reason="DAGMC CAD geometry is not enabled.") def test_cad(): - harness = CADTestHarness('statepoint.15.h5') + harness = CADTestHarness('statepoint.5.h5') harness.main() From 216027eb543e108ae76bc5a2da338499d8a3fa1c Mon Sep 17 00:00:00 2001 From: pshriwise Date: Wed, 26 Sep 2018 23:11:37 -0500 Subject: [PATCH 140/175] Moving DAGMC installation to a shell script. --- tools/ci/travis-install-dagmc.sh | 36 +++++++++++++++++ tools/ci/travis-install.py | 68 -------------------------------- tools/ci/travis-install.sh | 5 +++ 3 files changed, 41 insertions(+), 68 deletions(-) create mode 100755 tools/ci/travis-install-dagmc.sh diff --git a/tools/ci/travis-install-dagmc.sh b/tools/ci/travis-install-dagmc.sh new file mode 100755 index 000000000..fa3bf0f3f --- /dev/null +++ b/tools/ci/travis-install-dagmc.sh @@ -0,0 +1,36 @@ + +#!/bin/bash +set -ex + +# MOAB Variables +MOAB_BRANCH='Version5.0' +MOAB_REPO='https://bitbucket.org/fathomteam/moab/' +MOAB_INSTALL_DIR=$HOME/MOAB/ + +# DAGMC Variables +DAGMC_BRANCH='develop' +DAGMC_REPO='https://github.com/svalinn/dagmc' +DAGMC_INSTALL_DIR=$HOME/DAGMC/ + +CURRENT_DIR=$(pwd) + +# MOAB Install +cd $HOME +mkdir MOAB && cd MOAB +git clone -b $MOAB_BRANCH $MOAB_REPO +mkdir build && cd build +cmake ../moab -DENABLE_HDF5=ON -DCMAKE_INSTALL_PREFIX=$MOAB_INSTALL_DIR +make -j test install +rm -r $HOME/MOAB/moab +export LD_LIBRARY_PATH=$MOAB_INSTALL_DIR/lib:$LD_LIBRARY_PATH + +# DAGMC Install +mkdir DAGMC && cd DAGMC +git clone -b $DAGMC_BRANCH $DAGMC_REPO +mkdir build && cd build +cmake ../dagmc -DBUILD_TALLY=ON -DCMAKE_INSTALL_PREFIX=$DAGMC_INSTALL_D +make -j install +rm -r $HOME/DAGMC/dagmc +export LD_LIBRARY_PATH=$DAGMC_INSTALL_DIR/lib:$LD_LIBRARY_PATH + +cd $CURRENT_DIR diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index d6720cccf..a3503bd86 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -50,7 +50,6 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False): cmake_cmd.append('-DHDF5_PREFER_PARALLEL=OFF') if dagmc: - build_dagmc() cmake_cmd.append('-Ddagmc=ON') # Build and install @@ -60,72 +59,6 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False): subprocess.check_call(['make', '-j2']) subprocess.check_call(['sudo', 'make', 'install']) -def mkcd(directory): - os.mkdir(directory) - os.chdir(directory) - -def build_dagmc(): - - current_dir = os.getcwd() - home_dir = os.environ['HOME'] - - os.chdir(home_dir) - mkcd('MOAB') - - clone_cmd = ['git', 'clone', '-b', 'Version'+MOAB_VERSION, 'https://bitbucket.org/fathomteam/moab'] - subprocess.check_call(clone_cmd) - - mkcd('build') - - moab_install_dir = home_dir + "/" + "MOAB" - cmake_cmd = ['cmake', '../moab', '-DENABLE_HDF5=ON', '-DENABLE_TOOLS=ON', '-DCMAKE_INSTALL_PREFIX='+moab_install_dir] - subprocess.check_call(cmake_cmd) - - subprocess.check_call(['make', '-j2']) - - subprocess.check_call(['make', 'test']) - - subprocess.check_call(['make','install']) - - # check for existing LD_LIBRARY_PATH - try: - ld_lib_path = os.environ['LD_LIBRARY_PATH'] - except: - ld_lib_path = '' - - # update LB_LIBRARY_PATH (so DAGMC can find MOAB) - os.environ['LD_LIBRARY_PATH'] = moab_install_dir+"/lib" + ":" + ld_lib_path - - # remove moab source dir - shutil.rmtree(home_dir + "/MOAB/moab") - - # build dagmc - os.chdir(home_dir) - - mkcd('DAGMC') - - clone_cmd = ['git', 'clone', 'https://github.com/svalinn/dagmc'] - subprocess.check_call(clone_cmd) - - mkcd('build') - - dagmc_install_dir = home_dir + "/" + 'DAGMC' - cmake_cmd = ['cmake', '../dagmc', '-DCMAKE_INSTALL_PREFIX='+dagmc_install_dir, '-DBUILD_TALLY=ON'] - subprocess.check_call(cmake_cmd) - - subprocess.check_call(['make','-j2']) - - subprocess.check_call(['make','install']) - - # update LB_LIBRARY_PATH (so DAGMC can find MOAB) - os.environ['LD_LIBRARY_PATH'] = dagmc_install_dir+"/lib" + ":" + ld_lib_path - - # remove dagmc source dir - shutil.rmtree(home_dir + "/DAGMC/dagmc") - - # return to original directory - os.chdir(current_dir) - def main(): # Convert Travis matrix environment variables into arguments for install() omp = (os.environ.get('OMP') == 'y') @@ -137,6 +70,5 @@ def main(): # Build and install install(omp, mpi, phdf5, dagmc) - if __name__ == '__main__': main() diff --git a/tools/ci/travis-install.sh b/tools/ci/travis-install.sh index 88c59d051..c10c22279 100755 --- a/tools/ci/travis-install.sh +++ b/tools/ci/travis-install.sh @@ -4,6 +4,11 @@ set -ex # Install NJOY 2016 ./tools/ci/travis-install-njoy.sh +# Install DAGMC if needed +if [[ $DAGMC = 'y' ]]; then + ./tools/ci/travis-install-dagmc.sh +fi + # Upgrade pip before doing anything else pip install --upgrade pip From abd45373ee57dff2feee1c2aa18a96d301d2dc34 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Thu, 27 Sep 2018 06:49:20 -0500 Subject: [PATCH 141/175] Quick update to build line for MOAB. --- tools/ci/travis-install-dagmc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install-dagmc.sh b/tools/ci/travis-install-dagmc.sh index fa3bf0f3f..310c289e3 100755 --- a/tools/ci/travis-install-dagmc.sh +++ b/tools/ci/travis-install-dagmc.sh @@ -20,7 +20,7 @@ mkdir MOAB && cd MOAB git clone -b $MOAB_BRANCH $MOAB_REPO mkdir build && cd build cmake ../moab -DENABLE_HDF5=ON -DCMAKE_INSTALL_PREFIX=$MOAB_INSTALL_DIR -make -j test install +make -j && make -j test install rm -r $HOME/MOAB/moab export LD_LIBRARY_PATH=$MOAB_INSTALL_DIR/lib:$LD_LIBRARY_PATH From 2cf827c1157d941a201f32f505fc6a3f1708b01c Mon Sep 17 00:00:00 2001 From: pshriwise Date: Thu, 27 Sep 2018 08:56:54 -0500 Subject: [PATCH 142/175] Forcing removal of source directories. --- tools/ci/travis-install-dagmc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci/travis-install-dagmc.sh b/tools/ci/travis-install-dagmc.sh index 310c289e3..05d5d0a64 100755 --- a/tools/ci/travis-install-dagmc.sh +++ b/tools/ci/travis-install-dagmc.sh @@ -21,7 +21,7 @@ git clone -b $MOAB_BRANCH $MOAB_REPO mkdir build && cd build cmake ../moab -DENABLE_HDF5=ON -DCMAKE_INSTALL_PREFIX=$MOAB_INSTALL_DIR make -j && make -j test install -rm -r $HOME/MOAB/moab +rm -rf $HOME/MOAB/moab export LD_LIBRARY_PATH=$MOAB_INSTALL_DIR/lib:$LD_LIBRARY_PATH # DAGMC Install @@ -30,7 +30,7 @@ git clone -b $DAGMC_BRANCH $DAGMC_REPO mkdir build && cd build cmake ../dagmc -DBUILD_TALLY=ON -DCMAKE_INSTALL_PREFIX=$DAGMC_INSTALL_D make -j install -rm -r $HOME/DAGMC/dagmc +rm -rf $HOME/DAGMC/dagmc export LD_LIBRARY_PATH=$DAGMC_INSTALL_DIR/lib:$LD_LIBRARY_PATH cd $CURRENT_DIR From 7a41c3b27f334eb4accb20874ffeb28766073933 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Thu, 27 Sep 2018 11:01:28 -0500 Subject: [PATCH 143/175] Including the remainder of the DAGMC install variable name. ugh. --- tools/ci/travis-install-dagmc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install-dagmc.sh b/tools/ci/travis-install-dagmc.sh index 05d5d0a64..3cd5ee6ff 100755 --- a/tools/ci/travis-install-dagmc.sh +++ b/tools/ci/travis-install-dagmc.sh @@ -28,7 +28,7 @@ export LD_LIBRARY_PATH=$MOAB_INSTALL_DIR/lib:$LD_LIBRARY_PATH mkdir DAGMC && cd DAGMC git clone -b $DAGMC_BRANCH $DAGMC_REPO mkdir build && cd build -cmake ../dagmc -DBUILD_TALLY=ON -DCMAKE_INSTALL_PREFIX=$DAGMC_INSTALL_D +cmake ../dagmc -DBUILD_TALLY=ON -DCMAKE_INSTALL_PREFIX=$DAGMC_INSTALL_DIR make -j install rm -rf $HOME/DAGMC/dagmc export LD_LIBRARY_PATH=$DAGMC_INSTALL_DIR/lib:$LD_LIBRARY_PATH From 87043f9a647e0dd2824375379175e11a27fdb185 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Thu, 27 Sep 2018 19:09:54 -0400 Subject: [PATCH 144/175] Conslidated Travis and Docker XS download scripts --- Dockerfile | 18 ++++---- docker/Dockerfile | 41 ------------------- .../ci/download-xs.sh | 0 tools/ci/travis-before-script.sh | 18 +------- 4 files changed, 12 insertions(+), 65 deletions(-) delete mode 100644 docker/Dockerfile rename docker/docker-download-xs.sh => tools/ci/download-xs.sh (100%) diff --git a/Dockerfile b/Dockerfile index b40548420..e2365e530 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ # Install dependencies from Debian package manager RUN apt-get update -y && \ apt-get upgrade -y && \ + apt-get install -y python3-pip && \ apt-get install -y wget git emacs && \ apt-get install -y gfortran g++ cmake && \ apt-get install -y mpich libmpich-dev && \ @@ -19,10 +20,10 @@ RUN apt-get update -y && \ apt-get autoremove # Download Miniconda3 and install Python dependencies -RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ - /bin/bash ~/miniconda.sh -b -p /opt/conda && \ - rm -rf ~/miniconda.sh -RUN pip install --upgrade pip +#RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ +# /bin/bash ~/miniconda.sh -b -p /opt/conda && \ +# rm -rf ~/miniconda.sh +#RUN pip install --upgrade pip # Clone and install NJOY2016 RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ @@ -31,11 +32,12 @@ RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ cmake -Dstatic=on .. && make 2>/dev/null && make install # Clone and install OpenMC -RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ - cd /opt/openmc && mkdir -p build && cd build && \ +RUN git clone https://github.com/wbinventor/openmc.git /opt/openmc && \ + cd /opt/openmc && git checkout docker && mkdir -p build && cd build && \ cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ make && make install && \ - cd .. && pip install -e .[test] + cd .. && pip3 install -e .[test] # Download cross sections (NNDC and WMP) and ENDF data needed by test suite -RUN ./opt/openmc/docker/docker-download-xs.sh \ No newline at end of file +#RUN ./opt/openmc/docker/docker-download-xs.sh +RUN ./opt/openmc/tools/ci/download-xs.sh \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index b40548420..000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM ubuntu:latest - -# Setup environment variables for Docker image -ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ - PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ - LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ - OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml \ - OPENMC_MULTIPOLE_LIBRARY=/root/WMP_Library \ - OPENMC_ENDF_DATA=/root/endf-b-vii.1 - -# Install dependencies from Debian package manager -RUN apt-get update -y && \ - apt-get upgrade -y && \ - apt-get install -y wget git emacs && \ - apt-get install -y gfortran g++ cmake && \ - apt-get install -y mpich libmpich-dev && \ - apt-get install -y libhdf5-serial-dev libhdf5-mpich-dev && \ - apt-get install -y imagemagick && \ - apt-get autoremove - -# Download Miniconda3 and install Python dependencies -RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ - /bin/bash ~/miniconda.sh -b -p /opt/conda && \ - rm -rf ~/miniconda.sh -RUN pip install --upgrade pip - -# Clone and install NJOY2016 -RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ - cd /opt/NJOY2016 && \ - mkdir build && cd build && \ - cmake -Dstatic=on .. && make 2>/dev/null && make install - -# Clone and install OpenMC -RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ - cd /opt/openmc && mkdir -p build && cd build && \ - cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ - make && make install && \ - cd .. && pip install -e .[test] - -# Download cross sections (NNDC and WMP) and ENDF data needed by test suite -RUN ./opt/openmc/docker/docker-download-xs.sh \ No newline at end of file diff --git a/docker/docker-download-xs.sh b/tools/ci/download-xs.sh similarity index 100% rename from docker/docker-download-xs.sh rename to tools/ci/download-xs.sh diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh index f267cb020..d5ee1331a 100755 --- a/tools/ci/travis-before-script.sh +++ b/tools/ci/travis-before-script.sh @@ -5,19 +5,5 @@ set -ex # https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI sh -e /etc/init.d/xvfb start -# Download NNDC HDF5 data -if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then - wget https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz -O - | tar -C $HOME -xvJ -fi - -# Download ENDF/B-VII.1 distribution -ENDF=$HOME/endf-b-vii.1/ -if [[ ! -d $ENDF/neutrons || ! -d $ENDF/photoat || ! -d $ENDF/atomic_relax ]]; then - wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C $HOME -xvJ -fi - -# Download multipole library -if [[ ! -e $HOME/WMP_Library/092235.h5 ]]; then - wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz - tar -C $HOME -xzvf WMP_Library_v1.0.tar.gz -fi +# Download NNDC HDF5 data, ENDF/B-VII.1 distribution, multipole library +sh /download-xs.sh From 05081709910da582f3bbb1703875698edf81ecfa Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Thu, 27 Sep 2018 19:12:37 -0400 Subject: [PATCH 145/175] Added pip3 installation of NumPy to Dockerfile which is necessary to use system pip3 to install all OpenMC Python prerequisites --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index e2365e530..fb5149efd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,7 @@ RUN apt-get update -y && \ apt-get autoremove # Download Miniconda3 and install Python dependencies +RUN pip3 install numpy #RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ # /bin/bash ~/miniconda.sh -b -p /opt/conda && \ # rm -rf ~/miniconda.sh From b120e05b18141e23bab99dd0971784006f2634a1 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Thu, 27 Sep 2018 20:41:25 -0400 Subject: [PATCH 146/175] Removed commented lines in Dockerfile --- Dockerfile | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index fb5149efd..c29e1321c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:latest # Setup environment variables for Docker image ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ - PATH=/opt/openmc/bin:/opt/conda/bin:/opt/NJOY2016/build:$PATH \ + PATH=/opt/openmc/bin:/opt/NJOY2016/build:$PATH \ LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml \ OPENMC_MULTIPOLE_LIBRARY=/root/WMP_Library \ @@ -19,12 +19,8 @@ RUN apt-get update -y && \ apt-get install -y imagemagick && \ apt-get autoremove -# Download Miniconda3 and install Python dependencies -RUN pip3 install numpy -#RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \ -# /bin/bash ~/miniconda.sh -b -p /opt/conda && \ -# rm -rf ~/miniconda.sh -#RUN pip install --upgrade pip +# Update system-provided pip +RUN pip3 install --upgrade pip # Clone and install NJOY2016 RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ @@ -33,12 +29,11 @@ RUN git clone https://github.com/njoy/NJOY2016 /opt/NJOY2016 && \ cmake -Dstatic=on .. && make 2>/dev/null && make install # Clone and install OpenMC -RUN git clone https://github.com/wbinventor/openmc.git /opt/openmc && \ - cd /opt/openmc && git checkout docker && mkdir -p build && cd build && \ +RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \ + cd /opt/openmc && mkdir -p build && cd build && \ cmake -Doptimize=on -DHDF5_PREFER_PARALLEL=on .. && \ make && make install && \ - cd .. && pip3 install -e .[test] + cd .. && pip install -e .[test] # Download cross sections (NNDC and WMP) and ENDF data needed by test suite -#RUN ./opt/openmc/docker/docker-download-xs.sh RUN ./opt/openmc/tools/ci/download-xs.sh \ No newline at end of file From f2e773780db2ae9fb508471818921b44e81a697d Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Thu, 27 Sep 2018 20:42:51 -0400 Subject: [PATCH 147/175] Updated relative paths in call to download-xs.sh for travis --- tools/ci/travis-before-script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh index d5ee1331a..c810a4a4d 100755 --- a/tools/ci/travis-before-script.sh +++ b/tools/ci/travis-before-script.sh @@ -6,4 +6,4 @@ set -ex sh -e /etc/init.d/xvfb start # Download NNDC HDF5 data, ENDF/B-VII.1 distribution, multipole library -sh /download-xs.sh +sh ./tools/ci/download-xs.sh From 9a8184513fec6be5e55737afc2c035224ef2b2b2 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Fri, 28 Sep 2018 09:24:16 -0500 Subject: [PATCH 148/175] Adding env variable to travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index edb9cb402..a65723ab1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,7 @@ env: - OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml - OPENMC_ENDF_DATA=$HOME/endf-b-vii.1 - OPENMC_MULTIPOLE_LIBRARY=$HOME/WMP_Library + - LD_LIBRARY_PATH=$HOME/MOAB/lib:$HOME/DAGMC/lib - PATH=$PATH:$HOME/NJOY2016/build - DISPLAY=:99.0 - COVERALLS_PARALLEL=true From ea0b6f2948afa16b9cd73bc7bbba70a2464fb34d Mon Sep 17 00:00:00 2001 From: pshriwise Date: Sun, 30 Sep 2018 02:50:56 +0000 Subject: [PATCH 149/175] Skipping geometry write, but indicating a DAGMC geometry was used for now. --- openmc/summary.py | 18 +++++++++++------- src/summary.cpp | 12 ++++++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/openmc/summary.py b/openmc/summary.py index 10898290a..a54e8ebbf 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -97,13 +97,17 @@ class Summary(object): self._macroscopics = name.decode() def _read_geometry(self): - # Read in and initialize the Materials and Geometry - self._read_materials() - self._read_surfaces() - cell_fills = self._read_cells() - self._read_universes() - self._read_lattices() - self._finalize_geometry(cell_fills) + try: + self._f['geometry'].attrs.get("cad") + return + except: + # Read in and initialize the Materials and Geometry + self._read_materials() + self._read_surfaces() + cell_fills = self._read_cells() + self._read_universes() + self._read_lattices() + self._finalize_geometry(cell_fills) def _read_materials(self): for group in self._f['materials'].values(): diff --git a/src/summary.cpp b/src/summary.cpp index 7a0c4324a..eaedd21dd 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -9,11 +9,15 @@ namespace openmc { extern "C" void write_geometry(hid_t file_id) { -#ifdef DAGMC - if (settings::dagmc) return; -#endif - auto geom_group = create_group(file_id, "geometry"); + +#ifdef DAGMC + if (settings::dagmc) { + write_attribute(geom_group, "cad", 1); + return; + } +#endif + write_attribute(geom_group, "n_cells", cells.size()); write_attribute(geom_group, "n_surfaces", surfaces.size()); write_attribute(geom_group, "n_universes", universes.size()); From a4fdbe5048db63e65d1e51a3340e9b3f19045e67 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Sun, 30 Sep 2018 03:05:29 +0000 Subject: [PATCH 150/175] Updating check for cad geometry in summary read. --- openmc/summary.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openmc/summary.py b/openmc/summary.py index a54e8ebbf..fcda49a12 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -97,10 +97,10 @@ class Summary(object): self._macroscopics = name.decode() def _read_geometry(self): - try: - self._f['geometry'].attrs.get("cad") + + if "cad" in self._f['geometry'].attrs.keys(): return - except: + else: # Read in and initialize the Materials and Geometry self._read_materials() self._read_surfaces() From b9eb6455ad0c2bdea7e78e5b79b6b1b7aea64af9 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 30 Sep 2018 16:51:57 -0400 Subject: [PATCH 151/175] Moved detailed Docker deployment discussion to dev guide; quick install now directs users to pull an run from DockerHub --- docs/source/devguide/docker.rst | 57 ++++++++++++++++++++++++++++++ docs/source/devguide/index.rst | 1 + docs/source/quickinstall.rst | 27 +++----------- docs/source/usersguide/install.rst | 57 ------------------------------ 4 files changed, 62 insertions(+), 80 deletions(-) create mode 100644 docs/source/devguide/docker.rst diff --git a/docs/source/devguide/docker.rst b/docs/source/devguide/docker.rst new file mode 100644 index 000000000..12c095c45 --- /dev/null +++ b/docs/source/devguide/docker.rst @@ -0,0 +1,57 @@ +.. _devguide_docker: + +====================== +Deployment with Docker +====================== + +OpenMC can be easily deployed using `Docker `_ on any +Windows, Mac or Linux system. With Docker running, execute the following +command in the shell to build a `Docker image`_ called ``debian/openmc:latest``: + +.. code-block:: sh + + docker build -t debian/openmc:latest https://github.com/openmc-dev/openmc.git#develop + +.. note:: This may take 5 -- 10 minutes to run to completion. + +This command will execute the instructions in OpenMC's ``Dockerfile`` to +build a Docker image with OpenMC installed. The image includes OpenMC with +MPICH and parallel HDF5 in the ``/opt/openmc`` directory, and +`Miniconda3 `_ with all of the Python +pre-requisites (NumPy, SciPy, Pandas, etc.) installed. The +`NJOY2016 `_ codebase is installed in +``/opt/NJOY2016`` to support full functionality and testing of the +``openmc.data`` Python module. The publicly available nuclear data libraries +necessary to run OpenMC's test suite -- including NNDC and WMP cross sections +and ENDF data -- are in the ``/opt/openmc/data directory``, and the +corresponding :envvar:`OPENMC_CROSS_SECTIONS`, +:envvar:`OPENMC_MULTIPOLE_LIBRARY`, and :envvar:`OPENMC_ENDF_DATA` +environment variables are initialized. + +After building the Docker image, you can run the following to see the names of +all images on your machine, including ``debian/openmc:latest``: + +.. code-block:: sh + + docker image ls + +Now you can run the following to create a `Docker container`_ called +``my_openmc`` based on the ``debian/openmc:latest`` image: + +.. code-block:: sh + + docker run -it --name=my_openmc debian/openmc:latest + +This command will open an interactive shell running from within the +Docker container where you have access to use OpenMC. + +.. note:: The ``docker run`` command supports many + `options `_ + for spawning containers -- including `mounting volumes`_ from the + host filesystem -- which many users will find useful. + +.. _Docker image: https://docs.docker.com/engine/reference/commandline/images/ +.. _Docker container: https://www.docker.com/resources/what-container +.. _options: https://docs.docker.com/engine/reference/commandline/run/ +.. _mounting volumes: https://docs.docker.com/storage/volumes/ + diff --git a/docs/source/devguide/index.rst b/docs/source/devguide/index.rst index e2410f080..d100fdcdf 100644 --- a/docs/source/devguide/index.rst +++ b/docs/source/devguide/index.rst @@ -18,3 +18,4 @@ other related topics. tests user-input docbuild + docker diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index f172accb3..33f99e0a9 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -59,37 +59,18 @@ are no longer supported. .. _APT package manager: https://help.ubuntu.com/community/AptGet/Howto ------------------------------------------- -Installing with Docker on Linux/Mac/Windows +Installing on Linux/Mac/Windows with Docker ------------------------------------------- OpenMC can be easily deployed using `Docker `_ on any Windows, Mac or Linux system. With Docker running, execute the following -command in the shell to build a `Docker image`_ called ``debian/openmc:latest``: +command in the shell to download and run a `Docker image`_ with the most recent release of OpenMC from `DockerHub `_ called ``openmc/openmc:latest``: .. code-block:: sh - docker build -t debian/openmc:latest https://github.com/openmc-dev/openmc.git#develop + docker run openmc/openmc:latest -.. note:: This may take 5 -- 10 minutes to run to completion. - -This command will execute the instructions in OpenMC's ``Dockerfile`` to -build a Docker image with OpenMC installed to ``/opt/openmc``. After building -the Docker image, you can run the following to see the names of all images -on your machine, including ``debian/openmc:latest``: - -.. code-block:: sh - - docker image ls - -Now you can run the following to create a `Docker container`_ called -``my_openmc`` based on the ``debian/openmc:latest`` image: - -.. code-block:: sh - - docker run -it --name=my_openmc debian/openmc:latest - -This command will open an interactive shell running from within the -Docker container where you have access to use OpenMC. +This will take 5 -- 10 minutes to run to completion depending on your internet download speed. The command will place you in an interactive shell running in a `Docker container`_ with OpenMC installed. .. note:: The ``docker run`` command supports many `options `_ diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 17810d23c..48dcd8c78 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -71,63 +71,6 @@ are no longer supported. .. _Personal Package Archive: https://launchpad.net/~paulromano/+archive/staging .. _APT package manager: https://help.ubuntu.com/community/AptGet/Howto -.. _install_docker: - -------------------------------------------- -Installing with Docker on Linux/Mac/Windows -------------------------------------------- - -OpenMC can be easily deployed using `Docker `_ on any -Windows, Mac or Linux system. With Docker running, execute the following -command in the shell to build a `Docker image`_ called ``debian/openmc:latest``: - -.. code-block:: sh - - docker build -t debian/openmc:latest https://github.com/openmc-dev/openmc.git#develop - -.. note:: This may take 5 -- 10 minutes to run to completion. - -This command will execute the instructions in OpenMC's ``Dockerfile`` to -build a Docker image with OpenMC installed. The image includes OpenMC with -MPICH and parallel HDF5 in the ``/opt/openmc`` directory, and -`Miniconda3 `_ with all of the Python -pre-requisites (NumPy, SciPy, Pandas, etc.) installed. The -`NJOY2016 `_ codebase is installed in -``/opt/NJOY2016`` to support full functionality and testing of the -``openmc.data`` Python module. The publicly available nuclear data libraries -necessary to run OpenMC's test suite -- including NNDC and WMP cross sections -and ENDF data -- are in the ``/opt/openmc/data directory``, and the -corresponding :envvar:`OPENMC_CROSS_SECTIONS`, -:envvar:`OPENMC_MULTIPOLE_LIBRARY`, and :envvar:`OPENMC_ENDF_DATA` -environment variables are initialized. - -After building the Docker image, you can run the following to see the names of -all images on your machine, including ``debian/openmc:latest``: - -.. code-block:: sh - - docker image ls - -Now you can run the following to create a `Docker container`_ called -``my_openmc`` based on the ``debian/openmc:latest`` image: - -.. code-block:: sh - - docker run -it --name=my_openmc debian/openmc:latest - -This command will open an interactive shell running from within the -Docker container where you have access to use OpenMC. - -.. note:: The ``docker run`` command supports many - `options `_ - for spawning containers -- including `mounting volumes`_ from the - host filesystem -- which many users will find useful. - -.. _Docker image: https://docs.docker.com/engine/reference/commandline/images/ -.. _Docker container: https://www.docker.com/resources/what-container -.. _options: https://docs.docker.com/engine/reference/commandline/run/ -.. _mounting volumes: https://docs.docker.com/storage/volumes/ - .. _install_source: ---------------------- From 3516980b0d09df5851c70de8a86b5ea8d54db908 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 30 Sep 2018 18:11:31 -0400 Subject: [PATCH 152/175] Fixed hyperlink to Docker runtime options in quick install instructions --- docs/source/quickinstall.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 33f99e0a9..11cb5e1b7 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -70,12 +70,11 @@ command in the shell to download and run a `Docker image`_ with the most recent docker run openmc/openmc:latest -This will take 5 -- 10 minutes to run to completion depending on your internet download speed. The command will place you in an interactive shell running in a `Docker container`_ with OpenMC installed. +This will take several minutes to run depending on your internet download speed. The command will place you in an interactive shell running in a `Docker container`_ with OpenMC installed. -.. note:: The ``docker run`` command supports many - `options `_ - for spawning containers -- including `mounting volumes`_ from the - host filesystem -- which many users will find useful. +.. note:: The ``docker run`` command supports many `options`_ for spawning + containers -- including `mounting volumes`_ from the host + filesystem -- which many users will find useful. .. _Docker image: https://docs.docker.com/engine/reference/commandline/images/ .. _Docker container: https://www.docker.com/resources/what-container From 64e2df362a505c933b5eb1b8ce9e30657a6a186a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 10:33:58 -0500 Subject: [PATCH 153/175] Adding changes requested in PR. --- CMakeLists.txt | 2 +- include/openmc/cell.h | 4 ++-- include/openmc/dagmc.h | 7 ++++--- include/openmc/surface.h | 3 +-- openmc/summary.py | 2 +- src/dagmc.cpp | 6 ++++-- src/summary.cpp | 2 +- tests/regression_tests/dagmc/__init__.py | 1 - 8 files changed, 14 insertions(+), 13 deletions(-) delete mode 100644 tests/regression_tests/dagmc/__init__.py diff --git a/CMakeLists.txt b/CMakeLists.txt index a34542e6a..53615696d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -488,7 +488,7 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml - faddeeva xtensor ${DAGMC_LIBRARIES}) + faddeeva xtensor) if(dagmc) target_compile_definitions(libopenmc PRIVATE DAGMC) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 88996226c..5a889023b 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -133,11 +133,11 @@ public: //! known to be on. This index takes precedence over surface sense //! calculations. virtual bool - contains(Position p, Direction u, int32_t on_surface) const = 0; + contains(Position r, Direction u, int32_t on_surface) const = 0; //! Find the oncoming boundary of this cell. virtual std::pair - distance(Position p, Direction u, int32_t on_surface) const = 0; + distance(Position r, Direction u, int32_t on_surface) const = 0; //! Write all information needed to reconstruct the cell to an HDF5 group. //! @param group_id An HDF5 group id. diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 8dd60516f..7b148b7ee 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -1,8 +1,8 @@ #ifdef DAGMC -#ifndef OPEN_DAGMC_H -#define OPEN_DAGMC_H +#ifndef OPENMC_DAGMC_H +#define OPENMC_DAGMC_H #include "DagMC.hpp" #include "openmc/cell.h" @@ -16,6 +16,7 @@ extern "C" void load_dagmc_geometry(); extern "C" void free_memory_dagmc(); } -#endif // DAGMC_H + +#endif // OPENMC_DAGMC_H #endif diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 1eb505e45..23c3b61ec 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -134,8 +134,7 @@ public: moab::DagMC* dagmc_ptr_; DAGSurface(); double evaluate(Position r) const; - double distance(Position r, Direction u, - bool coincident) const; + double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; //! Get the bounding box of this surface. BoundingBox bounding_box() const; diff --git a/openmc/summary.py b/openmc/summary.py index fcda49a12..c5343a553 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -98,7 +98,7 @@ class Summary(object): def _read_geometry(self): - if "cad" in self._f['geometry'].attrs.keys(): + if "dagmc" in self._f['geometry'].attrs.keys(): return else: # Read in and initialize the Materials and Geometry diff --git a/src/dagmc.cpp b/src/dagmc.cpp index fa9ca3095..72ad42549 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -6,6 +6,7 @@ #include "openmc/string_functions.h" #include +#include #include namespace openmc { @@ -78,8 +79,9 @@ void load_dagmc_geometry() c->material_.push_back(std::stoi(mat_value)); } } else { - std::cout << c->id_ << std::endl; - fatal_error("A volume without a material was found."); + std::stringstream err_msg; + err_msg << "Volume " << c->id_ << " has no material assignment."; + fatal_error(err_msg.str()); } } diff --git a/src/summary.cpp b/src/summary.cpp index eaedd21dd..d2f083657 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -13,7 +13,7 @@ write_geometry(hid_t file_id) { #ifdef DAGMC if (settings::dagmc) { - write_attribute(geom_group, "cad", 1); + write_attribute(geom_group, "dagmc", 1); return; } #endif diff --git a/tests/regression_tests/dagmc/__init__.py b/tests/regression_tests/dagmc/__init__.py deleted file mode 100644 index 5871ed8ee..000000000 --- a/tests/regression_tests/dagmc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import pytest From 75b43614f4a58e3415934c4c1d2baeaeeaf4be7a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 10:38:16 -0500 Subject: [PATCH 154/175] Adding check for DAGMC_ROOT in environment as a hint. --- cmake/Modules/FindDAGMC.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/FindDAGMC.cmake b/cmake/Modules/FindDAGMC.cmake index 63a8a3469..c644c8886 100644 --- a/cmake/Modules/FindDAGMC.cmake +++ b/cmake/Modules/FindDAGMC.cmake @@ -8,7 +8,7 @@ # DAGMC_DEFINITIONS - Compiler switches required for using DAGMC find_path(DAGMC_CMAKE_CONFIG NAMES DAGMCConfig.cmake - HINTS ${DAGMC_ROOT} + HINTS ${DAGMC_ROOT} $ENV{DAGMC_ROOT} PATHS ENV LD_LIBRARY_PATH PATH_SUFFIXES lib Lib cmake lib/cmake NO_DEFAULT_PATH) From b16deb5d14d64215083be712ec7e48a46fb29cae Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 10:45:20 -0500 Subject: [PATCH 155/175] Updating name of the dagmc test. --- tests/regression_tests/dagmc/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/dagmc/test.py b/tests/regression_tests/dagmc/test.py index f230e9ed2..01608d7ca 100644 --- a/tests/regression_tests/dagmc/test.py +++ b/tests/regression_tests/dagmc/test.py @@ -6,6 +6,6 @@ pytestmark = pytest.mark.skipif( os.environ.get('DAGMC') != 'y', reason="DAGMC CAD geometry is not enabled.") -def test_cad(): +def test_dagmc(): harness = CADTestHarness('statepoint.5.h5') harness.main() From 62a29c9563ffe2cc813c198bc56be6ab524ebc6e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 10:47:23 -0500 Subject: [PATCH 156/175] Removing old MOAB version variable. --- tools/ci/travis-install.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index a3503bd86..bbf92b2f5 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -2,8 +2,6 @@ import os import shutil import subprocess -MOAB_VERSION= '5.0' - def which(program): def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) From b2751f25f08187072ae7aaa0d5b95af2f856544b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 11:22:14 -0500 Subject: [PATCH 157/175] Adding empty init file in the dagmc test dir. --- tests/regression_tests/dagmc/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/regression_tests/dagmc/__init__.py diff --git a/tests/regression_tests/dagmc/__init__.py b/tests/regression_tests/dagmc/__init__.py new file mode 100644 index 000000000..e69de29bb From 275df356b4e58e411680a19e3147681ca45a05ea Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 13:40:16 -0500 Subject: [PATCH 158/175] Updating DAGMC test, harness, and statepoint read. --- openmc/geometry.py | 5 ++++- tests/regression_tests/dagmc/results_true.dat | 5 +++++ tests/regression_tests/dagmc/test.py | 4 ++-- tests/testing_harness.py | 12 ------------ 4 files changed, 11 insertions(+), 15 deletions(-) create mode 100644 tests/regression_tests/dagmc/results_true.dat diff --git a/openmc/geometry.py b/openmc/geometry.py index 4cbc60c24..e939ecbe3 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -266,7 +266,10 @@ class Geometry(object): Dictionary mapping cell IDs to :class:`openmc.Cell` instances """ - return self.root_universe.get_all_cells() + if self.root_universe is not None: + return self.root_universe.get_all_cells() + else: + return [] def get_all_universes(self): """Return all universes in the geometry. diff --git a/tests/regression_tests/dagmc/results_true.dat b/tests/regression_tests/dagmc/results_true.dat new file mode 100644 index 000000000..fc13a9cda --- /dev/null +++ b/tests/regression_tests/dagmc/results_true.dat @@ -0,0 +1,5 @@ +k-combined: +1.115067E+00 5.423808E-02 +tally 1: +8.543144E+00 +1.530584E+01 diff --git a/tests/regression_tests/dagmc/test.py b/tests/regression_tests/dagmc/test.py index 01608d7ca..8c81b85d5 100644 --- a/tests/regression_tests/dagmc/test.py +++ b/tests/regression_tests/dagmc/test.py @@ -1,4 +1,4 @@ -from tests.testing_harness import CADTestHarness +from tests.testing_harness import TestHarness import os import pytest @@ -7,5 +7,5 @@ pytestmark = pytest.mark.skipif( reason="DAGMC CAD geometry is not enabled.") def test_dagmc(): - harness = CADTestHarness('statepoint.5.h5') + harness = TestHarness('statepoint.5.h5') harness.main() diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 60c8e7c16..fb07575ce 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -312,15 +312,3 @@ class HashedPyAPITestHarness(PyAPITestHarness): def _get_results(self): """Digest info in the statepoint and return as a string.""" return super()._get_results(True) - - -class CADTestHarness(TestHarness): - - def execute_test(self): - """Run OpenMC with the appropriate arguments and check the outputs.""" - try: - self._run_openmc() - self._test_output_created() - finally: - self._cleanup() - From 3b7352dc7d271e87e4254485a712c9279715e410 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 13:41:17 -0500 Subject: [PATCH 159/175] Updating if/else. --- openmc/summary.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/openmc/summary.py b/openmc/summary.py index c5343a553..866dd8288 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -97,17 +97,16 @@ class Summary(object): self._macroscopics = name.decode() def _read_geometry(self): - if "dagmc" in self._f['geometry'].attrs.keys(): return - else: - # Read in and initialize the Materials and Geometry - self._read_materials() - self._read_surfaces() - cell_fills = self._read_cells() - self._read_universes() - self._read_lattices() - self._finalize_geometry(cell_fills) + + # Read in and initialize the Materials and Geometry + self._read_materials() + self._read_surfaces() + cell_fills = self._read_cells() + self._read_universes() + self._read_lattices() + self._finalize_geometry(cell_fills) def _read_materials(self): for group in self._f['materials'].values(): From 7b881c83173280aa00a08b16b7a2f4a45bb3ec97 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 13:43:12 -0500 Subject: [PATCH 160/175] style updates --- src/cell.cpp | 3 ++- src/surface.cpp | 9 --------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 7364fd1e1..f851922e1 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -772,7 +772,8 @@ extern "C" { #ifdef DAGMC - int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed ) { + int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed ) + { moab::EntityHandle surf = surf_xed->dagmc_ptr_->entity_by_id(2,surf_xed->id_); moab::EntityHandle vol = cur_cell->dagmc_ptr_->entity_by_id(3,cur_cell->id_); diff --git a/src/surface.cpp b/src/surface.cpp index b2dbcf874..bf1c2e58c 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1285,15 +1285,6 @@ extern "C" { int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic_;} - void surface_normal(Surface* surf, double xyz[3], double uvw[3]) - { - Position r {xyz}; - Direction u = surf->normal(r); - uvw[0] = u.x; - uvw[1] = u.y; - uvw[2] = u.z; - } - bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], double uvw[3]) From e1361d615cee38854ae9998688320072346db7be Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 14:41:42 -0500 Subject: [PATCH 161/175] Forcing number of threads to one for a dagmc run and letting the user know. --- src/settings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/settings.cpp b/src/settings.cpp index 04facb2f4..ab22e8ee6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -408,6 +408,11 @@ void read_settings_xml() #endif } + if (dagmc) { + warning("Forcing number of threads to 1 for DAGMC simulation."); + omp_set_num_threads(1); + } + // ========================================================================== // EXTERNAL SOURCE From 82f68c441192a5212e4dc18fb75f5a898b154456 Mon Sep 17 00:00:00 2001 From: pshriwise Date: Mon, 1 Oct 2018 20:09:00 +0000 Subject: [PATCH 162/175] Putting dagmc setting in an ifdef. --- src/settings.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/settings.cpp b/src/settings.cpp index ab22e8ee6..19b8a72a5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -408,10 +408,12 @@ void read_settings_xml() #endif } +#ifdef _OPENMP if (dagmc) { warning("Forcing number of threads to 1 for DAGMC simulation."); omp_set_num_threads(1); } +#endif // ========================================================================== // EXTERNAL SOURCE From 5c7a29a0e39c942eea61b90fde0fe2bf617918a5 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Tue, 2 Oct 2018 18:25:31 -0400 Subject: [PATCH 163/175] Updated quick install instructions with v0.10.0 Docker image tag --- docs/source/quickinstall.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 11cb5e1b7..37e431f55 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -64,11 +64,11 @@ Installing on Linux/Mac/Windows with Docker OpenMC can be easily deployed using `Docker `_ on any Windows, Mac or Linux system. With Docker running, execute the following -command in the shell to download and run a `Docker image`_ with the most recent release of OpenMC from `DockerHub `_ called ``openmc/openmc:latest``: +command in the shell to download and run a `Docker image`_ with the most recent release of OpenMC from `DockerHub `_ called ``openmc/openmc:v0.10.0``: .. code-block:: sh - docker run openmc/openmc:latest + docker run openmc/openmc:v0.10.0 This will take several minutes to run depending on your internet download speed. The command will place you in an interactive shell running in a `Docker container`_ with OpenMC installed. From b504ef35278a39301c00ff32eb68f25c4558a1f9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 15:28:29 -0500 Subject: [PATCH 164/175] Skipping neighbor list setup if using CAD. --- src/input_xml.F90 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 9fefbbfcd..6f1080b8a 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -179,8 +179,10 @@ contains ! After reading input and basic geometry setup is complete, build lists of ! neighboring cells for efficient tracking - call neighbor_lists() - + if (.not. dagmc) then + call neighbor_lists() + end if + ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() From 5bb145ebda0c88548ee9ecfba91d2c858d99f3e4 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 15:36:34 -0500 Subject: [PATCH 165/175] Adding openmp build with CAD now that there is a defined behavior for this situation. --- .travis.yml | 3 ++- src/input_xml.F90 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a65723ab1..0f5459734 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,8 @@ env: - OMP=y MPI=n PHDF5=n - OMP=n MPI=y PHDF5=n - OMP=n MPI=y PHDF5=y - - OMP=n MPI=y PHDF5=y DAGMC=y + - OMP=n MPI=y PHDF5=y DAGMC=y + - OMP=y MPI=y PHDF5=y DAGMC=y notifications: webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN install: diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 6f1080b8a..7aa1dec9f 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -181,7 +181,7 @@ contains ! neighboring cells for efficient tracking if (.not. dagmc) then call neighbor_lists() - end if + end if ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() From 3e0a891bb824c968445287dd449d84bdaa4fe267 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 17:37:33 -0500 Subject: [PATCH 166/175] Removing whitespace --- src/input_xml.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 7aa1dec9f..03e38af60 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -182,7 +182,7 @@ contains if (.not. dagmc) then call neighbor_lists() end if - + ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() From f0e3461dfd708bb5f3f3fe5edf6729513861ac1a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 20:10:09 -0500 Subject: [PATCH 167/175] Size overlap check counter vec to fix plotting with DAGMC geoms. --- src/dagmc.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 72ad42549..913e6c88e 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -4,13 +4,15 @@ #include "openmc/dagmc.h" #include "openmc/error.h" #include "openmc/string_functions.h" +#include "openmc/settings.h" +#include "openmc/geometry.h" #include #include #include namespace openmc { - + moab::DagMC* DAG; void load_dagmc_geometry() @@ -37,19 +39,23 @@ void load_dagmc_geometry() // initialize cell objects n_cells = DAG->num_entities(3); + + // Allocate the cell overlap count if necessary. + if (settings::check_overlaps) overlap_check_count.resize(n_cells, 0); + for (int i = 0; i < n_cells; i++) { moab::EntityHandle vol_handle = DAG->entity_by_index(3, i+1); - + // set cell ids using global IDs DAGCell* c = new DAGCell(); c->id_ = DAG->id_by_index(3, i+1); c->dagmc_ptr_ = DAG; c->universe_ = dagmc_univ_id; // set to zero for now c->fill_ = C_NONE; // no fill, single universe - + cells.push_back(c); cell_map[c->id_] = c->id_; - + // Populate the Universe vector and dict auto it = universe_map.find(dagmc_univ_id); if (it == universe_map.end()) { @@ -60,19 +66,19 @@ void load_dagmc_geometry() } else { universes[it->second]->cells_.push_back(i); } - + if (DAG->is_implicit_complement(vol_handle)) { // assuming implicit complement is void for now c->material_.push_back(MATERIAL_VOID); continue; } - + if (DAG->has_prop(vol_handle, "mat")){ std::string mat_value; rval = DAG->prop_value(vol_handle, "mat", mat_value); MB_CHK_ERR_CONT(rval); to_lower(mat_value); - + if (mat_value == "void" || mat_value == "vacuum") { c->material_.push_back(MATERIAL_VOID); } else { @@ -84,25 +90,25 @@ void load_dagmc_geometry() fatal_error(err_msg.str()); } } - + // initialize surface objects n_surfaces = DAG->num_entities(2); surfaces.resize(n_surfaces); for (int i = 0; i < n_surfaces; i++) { moab::EntityHandle surf_handle = DAG->entity_by_index(2, i+1); - + // set cell ids using global IDs DAGSurface* s = new DAGSurface(); s->id_ = DAG->id_by_index(2, i+1); s->dagmc_ptr_ = DAG; - + if (DAG->has_prop(surf_handle, "boundary")) { std::string bc_value; rval = DAG->prop_value(surf_handle, "boundary", bc_value); MB_CHK_ERR_CONT(rval); to_lower(bc_value); - + if (bc_value == "transmit" || bc_value == "transmission") { s->bc_ = BC_TRANSMIT; } else if (bc_value == "vacuum") { @@ -120,12 +126,12 @@ void load_dagmc_geometry() } else { // if no BC property is found, set to transmit s->bc_ = BC_TRANSMIT; } - + // add to global array and map surfaces[i] = s; surface_map[s->id_] = s->id_; } - + return; } From e5ad7f9d77cc4889a86ff5aeadb7373f1e49875b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 17:05:41 -0500 Subject: [PATCH 168/175] Exposing dagmc support through the capi. --- include/openmc/dagmc.h | 6 ++++-- openmc/capi/__init__.py | 2 ++ src/dagmc.cpp | 10 ++++++++++ tests/regression_tests/dagmc/test.py | 3 ++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 7b148b7ee..29e597c67 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -1,9 +1,9 @@ -#ifdef DAGMC - #ifndef OPENMC_DAGMC_H #define OPENMC_DAGMC_H +#ifdef DAGMC + #include "DagMC.hpp" #include "openmc/cell.h" #include "openmc/surface.h" @@ -20,3 +20,5 @@ extern "C" void free_memory_dagmc(); #endif // OPENMC_DAGMC_H #endif + +extern "C" bool dagmc_enabled(); diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 672a6e811..7e569611c 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -38,6 +38,8 @@ else: from unittest.mock import Mock _dll = Mock() +__dagmc_enabled__ = bool(_dll.dagmc_enabled()) + from .error import * from .core import * from .nuclide import * diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 913e6c88e..f93516853 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -142,3 +142,13 @@ void free_memory_dagmc() } #endif + +bool dagmc_enabled() +{ +#ifdef DAGMC + return true; +#else + return false; +#endif +} + diff --git a/tests/regression_tests/dagmc/test.py b/tests/regression_tests/dagmc/test.py index 8c81b85d5..384f075ef 100644 --- a/tests/regression_tests/dagmc/test.py +++ b/tests/regression_tests/dagmc/test.py @@ -1,9 +1,10 @@ from tests.testing_harness import TestHarness import os import pytest +import openmc pytestmark = pytest.mark.skipif( - os.environ.get('DAGMC') != 'y', + not openmc.capi.__dagmc_enabled__, reason="DAGMC CAD geometry is not enabled.") def test_dagmc(): From e573f250f701e6d76483466b7aaa2058fdeb9fc6 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Oct 2018 17:29:28 -0500 Subject: [PATCH 169/175] Always include the dagmc.h file to the extern is seen in the implementation. --- src/dagmc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index f93516853..d1d4963da 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -1,6 +1,4 @@ -#ifdef DAGMC - #include "openmc/dagmc.h" #include "openmc/error.h" #include "openmc/string_functions.h" @@ -11,6 +9,8 @@ #include #include +#ifdef DAGMC + namespace openmc { moab::DagMC* DAG; From 3323ffc5c29ca255038824fabe9e719d978c5534 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 21:26:24 -0500 Subject: [PATCH 170/175] Updating CAPI dagmc_enabled exposure. --- include/openmc/dagmc.h | 6 +++++- openmc/capi/__init__.py | 4 ++-- src/dagmc.cpp | 10 ---------- tests/regression_tests/dagmc/test.py | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 29e597c67..0e5fc4064 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -21,4 +21,8 @@ extern "C" void free_memory_dagmc(); #endif -extern "C" bool dagmc_enabled(); +#ifdef DAGMC +extern "C" constexpr bool dagmc_enabled = true; +#else +extern "C" constexpr bool dagmc_enabled = false; +#endif diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 7e569611c..95ac77a64 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -12,7 +12,7 @@ objects in the :mod:`openmc.capi` subpackage, for example: """ -from ctypes import CDLL +from ctypes import CDLL, c_bool import os import sys @@ -38,7 +38,7 @@ else: from unittest.mock import Mock _dll = Mock() -__dagmc_enabled__ = bool(_dll.dagmc_enabled()) +dagmc_enabled = bool(c_bool.in_dll(_dll, "dagmc_enabled")) from .error import * from .core import * diff --git a/src/dagmc.cpp b/src/dagmc.cpp index d1d4963da..959dabd12 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -142,13 +142,3 @@ void free_memory_dagmc() } #endif - -bool dagmc_enabled() -{ -#ifdef DAGMC - return true; -#else - return false; -#endif -} - diff --git a/tests/regression_tests/dagmc/test.py b/tests/regression_tests/dagmc/test.py index 384f075ef..943245d27 100644 --- a/tests/regression_tests/dagmc/test.py +++ b/tests/regression_tests/dagmc/test.py @@ -4,7 +4,7 @@ import pytest import openmc pytestmark = pytest.mark.skipif( - not openmc.capi.__dagmc_enabled__, + not openmc.capi.dagmc_enabled, reason="DAGMC CAD geometry is not enabled.") def test_dagmc(): From 7d4824a1e7cde8412e45f8c8e94ded143d0bec1d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 21:27:00 -0500 Subject: [PATCH 171/175] Upping the number of jobs in Traivs. --- tools/ci/travis-install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install.py b/tools/ci/travis-install.py index bbf92b2f5..8a70c655c 100644 --- a/tools/ci/travis-install.py +++ b/tools/ci/travis-install.py @@ -54,7 +54,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False): cmake_cmd.append('..') print(' '.join(cmake_cmd)) subprocess.check_call(cmake_cmd) - subprocess.check_call(['make', '-j2']) + subprocess.check_call(['make', '-j4']) subprocess.check_call(['sudo', 'make', 'install']) def main(): From e952b2c6cbfcae0ebc65bd0639fd8f104b6bf161 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Oct 2018 22:22:20 -0500 Subject: [PATCH 172/175] Adding entry to summary file spec in docs. --- docs/source/io_formats/summary.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/io_formats/summary.rst b/docs/source/io_formats/summary.rst index 1f30c69bb..ee0d85fe3 100644 --- a/docs/source/io_formats/summary.rst +++ b/docs/source/io_formats/summary.rst @@ -24,6 +24,8 @@ The current version of the summary file format is 6.0. - **n_universes** (*int*) -- Number of unique universes in the problem. - **n_lattices** (*int*) -- Number of lattices in the problem. + - **dagmc** (*int*) -- Indicates that a DAGMC geometry was used + if present. **/geometry/cells/cell /** From 700533d44d456d57ec509d37a8a5c5a57ea00317 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 4 Oct 2018 13:33:41 -0400 Subject: [PATCH 173/175] Fix indexing error in FilterUniverse --- src/tallies/tally_filter_universe.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tallies/tally_filter_universe.F90 b/src/tallies/tally_filter_universe.F90 index 39c1449b3..9e0e09fcf 100644 --- a/src/tallies/tally_filter_universe.F90 +++ b/src/tallies/tally_filter_universe.F90 @@ -78,7 +78,7 @@ contains allocate(universe_ids(size(this % universes))) do i = 1, size(this % universes) - universe_ids(i) = universe_id(this % universes(i)-1) + universe_ids(i) = universe_id(this % universes(i)) end do call write_dataset(filter_group, "bins", universe_ids) end subroutine to_statepoint_universe From 91a6454f7309126ea8d8bb96c839ceaf00ba0af1 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 4 Oct 2018 14:01:01 -0400 Subject: [PATCH 174/175] Remove reference to compact MT 458 data --- scripts/openmc-convert-mcnp71-data | 9 --------- 1 file changed, 9 deletions(-) diff --git a/scripts/openmc-convert-mcnp71-data b/scripts/openmc-convert-mcnp71-data index ce8c427d6..eaaad078d 100755 --- a/scripts/openmc-convert-mcnp71-data +++ b/scripts/openmc-convert-mcnp71-data @@ -25,8 +25,6 @@ parser = argparse.ArgumentParser( ) parser.add_argument('-d', '--destination', default='mcnp_endfb71', help='Directory to create new library in') -parser.add_argument('-f', '--fission_energy_release', - help='HDF5 file containing fission energy release data') parser.add_argument('--libver', choices=['earliest', 'latest'], default='earliest', help="Output HDF5 versioning. Use " "'earliest' for backwards compatibility or 'latest' for " @@ -64,13 +62,6 @@ for basename, xs_list in sorted(suffixes.items()): else: data = openmc.data.IncidentNeutron.from_ace(filename, 'mcnp') - # Add fission energy release data, if available - if args.fission_energy_release is not None: - fer = openmc.data.FissionEnergyRelease.from_compact_hdf5( - args.fission_energy_release, data) - if fer is not None: - data.fission_energy = fer - # For each higher temperature, add cross sections to the existing table for xs in xs_list[1:]: filename = '.'.join((basename, xs)) From 10fdebdd7a16e5075b449a6c163365453f6c67b9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 4 Oct 2018 14:43:59 -0500 Subject: [PATCH 175/175] Updating warning condition for DAGMC threads and some comment corrections. --- include/openmc/dagmc.h | 4 ++-- src/settings.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 0e5fc4064..afbd9cbc6 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -17,9 +17,9 @@ extern "C" void free_memory_dagmc(); } -#endif // OPENMC_DAGMC_H +#endif // DAGMC -#endif +#endif // OPENMC_DAGMC_H #ifdef DAGMC extern "C" constexpr bool dagmc_enabled = true; diff --git a/src/settings.cpp b/src/settings.cpp index 19b8a72a5..b5f2bf5c6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -409,7 +409,7 @@ void read_settings_xml() } #ifdef _OPENMP - if (dagmc) { + if (dagmc && omp_get_max_threads() > 1) { warning("Forcing number of threads to 1 for DAGMC simulation."); omp_set_num_threads(1); }