mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 13:45:36 -04:00
Merge branch 'develop' into photon-production-fix
This commit is contained in:
commit
d81f1b9c7b
76 changed files with 2589 additions and 3397 deletions
|
|
@ -299,8 +299,6 @@ add_library(libopenmc SHARED
|
|||
src/cmfd_solver.F90
|
||||
src/constants.F90
|
||||
src/dict_header.F90
|
||||
src/distribution_multivariate.F90
|
||||
src/distribution_univariate.F90
|
||||
src/eigenvalue.F90
|
||||
src/endf.F90
|
||||
src/endf_header.F90
|
||||
|
|
@ -341,8 +339,6 @@ add_library(libopenmc SHARED
|
|||
src/settings.F90
|
||||
src/simulation_header.F90
|
||||
src/simulation.F90
|
||||
src/source.F90
|
||||
src/source_header.F90
|
||||
src/state_point.F90
|
||||
src/stl_vector.F90
|
||||
src/string.F90
|
||||
|
|
@ -392,6 +388,7 @@ add_library(libopenmc SHARED
|
|||
src/endf.cpp
|
||||
src/initialize.cpp
|
||||
src/finalize.cpp
|
||||
src/geometry.cpp
|
||||
src/geometry_aux.cpp
|
||||
src/hdf5_interface.cpp
|
||||
src/lattice.cpp
|
||||
|
|
@ -400,6 +397,8 @@ add_library(libopenmc SHARED
|
|||
src/message_passing.cpp
|
||||
src/mgxs.cpp
|
||||
src/mgxs_interface.cpp
|
||||
src/nuclide.cpp
|
||||
src/output.cpp
|
||||
src/particle.cpp
|
||||
src/plot.cpp
|
||||
src/position.cpp
|
||||
|
|
@ -414,8 +413,10 @@ add_library(libopenmc SHARED
|
|||
src/scattdata.cpp
|
||||
src/settings.cpp
|
||||
src/simulation.cpp
|
||||
src/source.cpp
|
||||
src/state_point.cpp
|
||||
src/string_functions.cpp
|
||||
src/summary.cpp
|
||||
src/surface.cpp
|
||||
src/thermal.cpp
|
||||
src/xml_interface.cpp
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ Each ``<cell>`` element can have the following attributes or sub-elements:
|
|||
|
||||
.. math::
|
||||
|
||||
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\theta \sin\psi +
|
||||
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\phi \sin\psi +
|
||||
\sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta
|
||||
\cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta
|
||||
\sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ extern "C" {
|
|||
int openmc_extend_filters(int32_t n, int32_t* index_start, int32_t* index_end);
|
||||
int openmc_extend_materials(int32_t n, int32_t* index_start, int32_t* index_end);
|
||||
int openmc_extend_meshes(int32_t n, int32_t* index_start, int32_t* index_end);
|
||||
int openmc_extend_sources(int32_t n, int32_t* index_start, int32_t* index_end);
|
||||
int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end);
|
||||
int openmc_filter_get_id(int32_t index, int32_t* id);
|
||||
int openmc_filter_get_type(int32_t index, char* type);
|
||||
|
|
@ -57,6 +56,7 @@ extern "C" {
|
|||
int openmc_material_add_nuclide(int32_t index, const char name[], double density);
|
||||
int openmc_material_get_densities(int32_t index, int** nuclides, double** densities, int* n);
|
||||
int openmc_material_get_id(int32_t index, int32_t* id);
|
||||
int openmc_material_get_fissionable(int32_t index, bool* fissionable);
|
||||
int openmc_material_get_volume(int32_t index, double* volume);
|
||||
int openmc_material_set_density(int32_t index, double density);
|
||||
int openmc_material_set_densities(int32_t index, int n, const char** name, const double* density);
|
||||
|
|
@ -84,7 +84,6 @@ extern "C" {
|
|||
int openmc_simulation_finalize();
|
||||
int openmc_simulation_init();
|
||||
int openmc_source_bank(struct Bank** ptr, int64_t* n);
|
||||
int openmc_source_set_strength(int32_t index, double strength);
|
||||
int openmc_spatial_legendre_filter_get_order(int32_t index, int* order);
|
||||
int openmc_spatial_legendre_filter_get_params(int32_t index, int* axis, double* min, double* max);
|
||||
int openmc_spatial_legendre_filter_set_order(int32_t index, int order);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/position.h"
|
||||
|
||||
|
||||
|
|
@ -24,6 +25,13 @@ extern "C" int FILL_MATERIAL;
|
|||
extern "C" int FILL_UNIVERSE;
|
||||
extern "C" int FILL_LATTICE;
|
||||
|
||||
// TODO: Convert to enum
|
||||
constexpr int32_t OP_LEFT_PAREN {std::numeric_limits<int32_t>::max()};
|
||||
constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits<int32_t>::max() - 1};
|
||||
constexpr int32_t OP_COMPLEMENT {std::numeric_limits<int32_t>::max() - 2};
|
||||
constexpr int32_t OP_INTERSECTION {std::numeric_limits<int32_t>::max() - 3};
|
||||
constexpr int32_t OP_UNION {std::numeric_limits<int32_t>::max() - 4};
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
|
@ -31,11 +39,11 @@ extern "C" int FILL_LATTICE;
|
|||
extern "C" int32_t n_cells;
|
||||
|
||||
class Cell;
|
||||
extern std::vector<Cell*> global_cells;
|
||||
extern std::vector<Cell*> cells;
|
||||
extern std::unordered_map<int32_t, int32_t> cell_map;
|
||||
|
||||
class Universe;
|
||||
extern std::vector<Universe*> global_universes;
|
||||
extern std::vector<Universe*> universes;
|
||||
extern std::unordered_map<int32_t, int32_t> universe_map;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -45,9 +53,12 @@ extern std::unordered_map<int32_t, int32_t> universe_map;
|
|||
class Universe
|
||||
{
|
||||
public:
|
||||
int32_t id; //!< Unique ID
|
||||
std::vector<int32_t> cells; //!< Cells within this universe
|
||||
//double x0, y0, z0; //!< Translation coordinates.
|
||||
int32_t id_; //!< Unique ID
|
||||
std::vector<int32_t> cells_; //!< Cells within this universe
|
||||
|
||||
//! \brief Write universe information to an HDF5 group.
|
||||
//! \param group_id An HDF5 group id.
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -57,25 +68,44 @@ public:
|
|||
class Cell
|
||||
{
|
||||
public:
|
||||
int32_t id; //!< Unique ID
|
||||
std::string name; //!< User-defined name
|
||||
int type; //!< Material, universe, or lattice
|
||||
int32_t universe; //!< Universe # this cell is in
|
||||
int32_t fill; //!< Universe # filling this cell
|
||||
int32_t n_instances{0}; //!< Number of instances of this cell
|
||||
int32_t id_; //!< Unique ID
|
||||
std::string name_; //!< User-defined name
|
||||
int type_; //!< Material, universe, or lattice
|
||||
int32_t universe_; //!< Universe # this cell is in
|
||||
int32_t fill_; //!< Universe # filling this cell
|
||||
int32_t n_instances_{0}; //!< Number of instances of this cell
|
||||
|
||||
//! \brief Index corresponding to this cell in distribcell arrays
|
||||
int distribcell_index_{C_NONE};
|
||||
|
||||
//! \brief Material(s) within this cell.
|
||||
//!
|
||||
//! May be multiple materials for distribcell. C_NONE signifies a universe.
|
||||
std::vector<int32_t> material;
|
||||
//! May be multiple materials for distribcell.
|
||||
std::vector<int32_t> material_;
|
||||
|
||||
//! \brief Temperature(s) within this cell.
|
||||
//!
|
||||
//! The stored values are actually sqrt(k_Boltzmann * T) for each temperature
|
||||
//! T. The units are sqrt(eV).
|
||||
std::vector<double> sqrtkT_;
|
||||
|
||||
//! Definition of spatial region as Boolean expression of half-spaces
|
||||
std::vector<std::int32_t> region;
|
||||
std::vector<std::int32_t> region_;
|
||||
//! Reverse Polish notation for region expression
|
||||
std::vector<std::int32_t> rpn;
|
||||
bool simple; //!< Does the region contain only intersections?
|
||||
std::vector<std::int32_t> rpn_;
|
||||
bool simple_; //!< Does the region contain only intersections?
|
||||
|
||||
std::vector<int32_t> offset; //!< Distribcell offset table
|
||||
Position translation_ {0, 0, 0}; //!< Translation vector for filled universe
|
||||
|
||||
//! \brief Rotational tranfsormation of the filled universe.
|
||||
//
|
||||
//! The vector is empty if there is no rotation. Otherwise, the first three
|
||||
//! values are the rotation angles respectively about the x-, y-, and z-, axes
|
||||
//! in degrees. The next 9 values give the rotation matrix in row-major
|
||||
//! order.
|
||||
std::vector<double> rotation_;
|
||||
|
||||
std::vector<int32_t> offset_; //!< Distribcell offset table
|
||||
|
||||
Cell() {};
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ public:
|
|||
//! Sample a value from the distribution
|
||||
//! \return Sampled value
|
||||
double sample() const;
|
||||
|
||||
// Properties
|
||||
const std::vector<double>& x() const { return x_; }
|
||||
const std::vector<double>& p() const { return p_; }
|
||||
private:
|
||||
std::vector<double> x_; //!< Possible outcomes
|
||||
std::vector<double> p_; //!< Probability of each outcome
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "openmc/distribution.h"
|
||||
#include "openmc/position.h"
|
||||
|
||||
|
|
@ -16,14 +18,15 @@ namespace openmc {
|
|||
class UnitSphereDistribution {
|
||||
public:
|
||||
UnitSphereDistribution() { };
|
||||
explicit UnitSphereDistribution(Direction u) : u_ref{u} { };
|
||||
explicit UnitSphereDistribution(Direction u) : u_ref_{u} { };
|
||||
explicit UnitSphereDistribution(pugi::xml_node node);
|
||||
virtual ~UnitSphereDistribution() = default;
|
||||
|
||||
//! Sample a direction from the distribution
|
||||
//! \return Direction sampled
|
||||
virtual Direction sample() const = 0;
|
||||
|
||||
Direction u_ref {0.0, 0.0, 1.0}; //!< reference direction
|
||||
Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -33,6 +36,7 @@ public:
|
|||
class PolarAzimuthal : public UnitSphereDistribution {
|
||||
public:
|
||||
PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi);
|
||||
explicit PolarAzimuthal(pugi::xml_node node);
|
||||
|
||||
//! Sample a direction from the distribution
|
||||
//! \return Direction sampled
|
||||
|
|
@ -62,12 +66,15 @@ public:
|
|||
class Monodirectional : public UnitSphereDistribution {
|
||||
public:
|
||||
Monodirectional(Direction u) : UnitSphereDistribution{u} { };
|
||||
explicit Monodirectional(pugi::xml_node node) : UnitSphereDistribution{node} { };
|
||||
|
||||
//! Sample a direction from the distribution
|
||||
//! \return Sampled direction
|
||||
Direction sample() const;
|
||||
};
|
||||
|
||||
using UPtrAngle = std::unique_ptr<UnitSphereDistribution>;
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // DISTRIBUTION_MULTI_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef OPENMC_DISTRIBTUION_SPATIAL_H
|
||||
#ifndef OPENMC_DISTRIBUTION_SPATIAL_H
|
||||
#define OPENMC_DISTRIBUTION_SPATIAL_H
|
||||
|
||||
#include "pugixml.hpp"
|
||||
|
|
@ -43,15 +43,18 @@ private:
|
|||
|
||||
class SpatialBox : public SpatialDistribution {
|
||||
public:
|
||||
explicit SpatialBox(pugi::xml_node node);
|
||||
explicit SpatialBox(pugi::xml_node node, bool fission=false);
|
||||
|
||||
//! Sample a position from the distribution
|
||||
//! \return Sampled position
|
||||
Position sample() const;
|
||||
|
||||
// Properties
|
||||
bool only_fissionable() const { return only_fissionable_; }
|
||||
private:
|
||||
Position lower_left_; //!< Lower-left coordinates of box
|
||||
Position upper_right_; //!< Upper-right coordinates of box
|
||||
bool only_fissionable {false}; //!< Only accept sites in fissionable region?
|
||||
bool only_fissionable_ {false}; //!< Only accept sites in fissionable region?
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -60,6 +63,8 @@ private:
|
|||
|
||||
class SpatialPoint : public SpatialDistribution {
|
||||
public:
|
||||
SpatialPoint() : r_{} { };
|
||||
SpatialPoint(Position r) : r_{r} { };
|
||||
explicit SpatialPoint(pugi::xml_node node);
|
||||
|
||||
//! Sample a position from the distribution
|
||||
|
|
@ -69,6 +74,8 @@ private:
|
|||
Position r_; //!< Single position at which sites are generated
|
||||
};
|
||||
|
||||
using UPtrSpace = std::unique_ptr<SpatialDistribution>;
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_DISTRIBUTION_SPATIAL_H
|
||||
|
|
|
|||
20
include/openmc/file_utils.h
Normal file
20
include/openmc/file_utils.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef OPENMC_FILE_UTILS_H
|
||||
#define OPENMC_FILE_UTILS_H
|
||||
|
||||
#include <fstream> // for ifstream
|
||||
#include <string>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//! Determine if a file exists
|
||||
//! \param[in] filename Path to file
|
||||
//! \return Whether file exists
|
||||
inline bool file_exists(const std::string& filename)
|
||||
{
|
||||
std::ifstream s {filename};
|
||||
return s.good();
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_FILE_UTILS_H
|
||||
|
|
@ -1,10 +1,60 @@
|
|||
#ifndef OPENMC_GEOMETRY_H
|
||||
#define OPENMC_GEOMETRY_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "openmc/particle.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
extern "C" int openmc_root_universe;
|
||||
|
||||
extern std::vector<int64_t> overlap_check_count;
|
||||
|
||||
//==============================================================================
|
||||
//! Check for overlapping cells at a particle's position.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" bool
|
||||
check_cell_overlap(Particle* p);
|
||||
|
||||
//==============================================================================
|
||||
//! Locate a particle in the geometry tree and set its geometry data fields.
|
||||
//!
|
||||
//! \param p A particle to be located. This function will populate the
|
||||
//! geometry-dependent data fields of the particle.
|
||||
//! \param search_surf A surface that the particle is expected to be on. This
|
||||
//! value should be the signed, 1-based index of a surface. If positive, the
|
||||
//! cells on the positive half-space of the surface will be searched. If
|
||||
//! negative, the negative half-space will be searched.
|
||||
//! \return True if the particle's location could be found and ascribed to a
|
||||
//! valid geometry coordinate stack.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" bool
|
||||
find_cell(Particle* p, int search_surf);
|
||||
|
||||
//==============================================================================
|
||||
//! Move a particle into a new lattice tile.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
cross_lattice(Particle* p, int lattice_translation[3]);
|
||||
|
||||
//==============================================================================
|
||||
//! Find the next boundary a particle will intersect.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
distance_to_boundary(Particle* p, double* dist, int* surface_crossed,
|
||||
int lattice_translation[3], int* next_level);
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_GEOMETRY_H
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ namespace openmc {
|
|||
|
||||
extern "C" void adjust_indices();
|
||||
|
||||
//==============================================================================
|
||||
//! Assign defaults to cells with undefined temperatures.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void assign_temperatures();
|
||||
|
||||
//==============================================================================
|
||||
//! Figure out which Universe is the root universe.
|
||||
//!
|
||||
|
|
@ -25,11 +31,17 @@ extern "C" void adjust_indices();
|
|||
|
||||
extern "C" int32_t find_root_universe();
|
||||
|
||||
//!=============================================================================
|
||||
//! Build a list of neighboring cells to each surface to speed up tracking.
|
||||
//!=============================================================================
|
||||
|
||||
extern "C" void neighbor_lists();
|
||||
|
||||
//==============================================================================
|
||||
//! Allocate storage in Lattice and Cell objects for distribcell offset tables.
|
||||
//! Populate all data structures needed for distribcells.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void allocate_offset_tables(int n_maps);
|
||||
extern "C" void prepare_distribcell(int32_t* filter_cell_list, int n);
|
||||
|
||||
//==============================================================================
|
||||
//! Recursively search through the geometry and count cell instances.
|
||||
|
|
@ -53,15 +65,6 @@ extern "C" void count_cell_instances(int32_t univ_indx);
|
|||
extern "C" int
|
||||
count_universe_instances(int32_t search_univ, int32_t target_univ_id);
|
||||
|
||||
//==============================================================================
|
||||
//! Populate Cell and Lattice distribcell offset tables.
|
||||
//! @param target_univ_id The ID of the universe to be counted.
|
||||
//! @param map The index of the distribcell map that defines the offsets for the
|
||||
//! target universe.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void fill_offset_tables(int32_t target_univ_id, int map);
|
||||
|
||||
//==============================================================================
|
||||
//! Find the length necessary for a string to contain a distribcell path.
|
||||
//! @param target_cell The index of the Cell in the global Cell array.
|
||||
|
|
|
|||
|
|
@ -36,7 +36,13 @@ bool using_mpio_device(hid_t obj_id);
|
|||
//==============================================================================
|
||||
|
||||
hid_t create_group(hid_t parent_id, const std::string& name);
|
||||
|
||||
inline hid_t create_group(hid_t parent_id, const std::stringstream& name)
|
||||
{return create_group(parent_id, name.str());}
|
||||
|
||||
|
||||
hid_t file_open(const std::string& filename, char mode, bool parallel=false);
|
||||
|
||||
void write_string(hid_t group_id, const char* name, const std::string& buffer,
|
||||
bool indep);
|
||||
|
||||
|
|
@ -295,7 +301,7 @@ void read_dataset(hid_t obj_id, const char* name, xt::xarray<T>& arr, bool indep
|
|||
template<typename T> inline void
|
||||
write_attribute(hid_t obj_id, const char* name, T buffer)
|
||||
{
|
||||
write_attr(obj_id, name, 0, nullptr, H5TypeMap<T>::type_id, &buffer);
|
||||
write_attr(obj_id, 0, nullptr, name, H5TypeMap<T>::type_id, &buffer);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
|
@ -334,6 +340,13 @@ write_dataset(hid_t obj_id, const char* name, const std::array<T, N>& buffer)
|
|||
write_dataset(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data(), false);
|
||||
}
|
||||
|
||||
template<typename T> inline void
|
||||
write_dataset(hid_t obj_id, const char* name, const std::vector<T>& buffer)
|
||||
{
|
||||
hsize_t dims[] {buffer.size()};
|
||||
write_dataset(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data(), false);
|
||||
}
|
||||
|
||||
inline void
|
||||
write_dataset(hid_t obj_id, const char* name, Position r)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,12 +22,16 @@ namespace openmc {
|
|||
|
||||
constexpr int32_t NO_OUTER_UNIVERSE{-1};
|
||||
|
||||
enum class LatticeType {
|
||||
rect, hex
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
class Lattice;
|
||||
extern std::vector<Lattice*> lattices_c;
|
||||
extern std::vector<Lattice*> lattices;
|
||||
|
||||
extern std::unordered_map<int32_t, int32_t> lattice_map;
|
||||
|
||||
|
|
@ -42,17 +46,18 @@ class ReverseLatticeIter;
|
|||
class Lattice
|
||||
{
|
||||
public:
|
||||
int32_t id; //!< Universe ID number
|
||||
std::string name; //!< User-defined name
|
||||
std::vector<int32_t> universes; //!< Universes filling each lattice tile
|
||||
int32_t outer {NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice
|
||||
std::vector<int32_t> offsets; //!< Distribcell offset table
|
||||
int32_t id_; //!< Universe ID number
|
||||
std::string name_; //!< User-defined name
|
||||
LatticeType type_;
|
||||
std::vector<int32_t> universes_; //!< Universes filling each lattice tile
|
||||
int32_t outer_ {NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice
|
||||
std::vector<int32_t> offsets_; //!< Distribcell offset table
|
||||
|
||||
explicit Lattice(pugi::xml_node lat_node);
|
||||
|
||||
virtual ~Lattice() {}
|
||||
|
||||
virtual int32_t& operator[](const int i_xyz[3]) = 0;
|
||||
virtual int32_t& operator[](std::array<int, 3> i_xyz) = 0;
|
||||
|
||||
virtual LatticeIter begin();
|
||||
LatticeIter end();
|
||||
|
|
@ -65,7 +70,7 @@ public:
|
|||
|
||||
//! Allocate offset table for distribcell.
|
||||
void allocate_offset_table(int n_maps)
|
||||
{offsets.resize(n_maps * universes.size(), C_NONE);}
|
||||
{offsets_.resize(n_maps * universes_.size(), C_NONE);}
|
||||
|
||||
//! Populate the distribcell offset tables.
|
||||
int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map);
|
||||
|
|
@ -76,14 +81,21 @@ public:
|
|||
//! otherwise.
|
||||
virtual bool are_valid_indices(const int i_xyz[3]) const = 0;
|
||||
|
||||
bool
|
||||
are_valid_indices(std::array<int, 3> i_xyz) const
|
||||
{
|
||||
int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]};
|
||||
return are_valid_indices(i_xyz_);
|
||||
}
|
||||
|
||||
//! \brief Find the next lattice surface crossing
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \param u A 3D Cartesian direction.
|
||||
//! \param i_xyz[3] The indices for a lattice tile.
|
||||
//! \param i_xyz The indices for a lattice tile.
|
||||
//! \return The distance to the next crossing and an array indicating how the
|
||||
//! lattice indices would change after crossing that boundary.
|
||||
virtual std::pair<double, std::array<int, 3>>
|
||||
distance(Position r, Direction u, const int i_xyz[3]) const
|
||||
distance(Position r, Direction u, const std::array<int, 3>& i_xyz) const
|
||||
= 0;
|
||||
|
||||
//! \brief Find the lattice tile indices for a given point.
|
||||
|
|
@ -93,17 +105,17 @@ public:
|
|||
|
||||
//! \brief Get coordinates local to a lattice tile.
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \param i_xyz[3] The indices for a lattice tile.
|
||||
//! \param i_xyz The indices for a lattice tile.
|
||||
//! \return Local 3D Cartesian coordinates.
|
||||
virtual Position
|
||||
get_local_position(Position r, const int i_xyz[3]) const = 0;
|
||||
get_local_position(Position r, const std::array<int, 3> i_xyz) const = 0;
|
||||
|
||||
//! \brief Check flattened lattice index.
|
||||
//! \param indx The index for a lattice tile.
|
||||
//! \return true if the given index fit within the lattice bounds. False
|
||||
//! otherwise.
|
||||
virtual bool is_valid_index(int indx) const
|
||||
{return (indx >= 0) && (indx < universes.size());}
|
||||
{return (indx >= 0) && (indx < universes_.size());}
|
||||
|
||||
//! \brief Get the distribcell offset for a lattice tile.
|
||||
//! \param The map index for the target cell.
|
||||
|
|
@ -122,7 +134,7 @@ public:
|
|||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
protected:
|
||||
bool is_3d; //!< Has divisions along the z-axis?
|
||||
bool is_3d_; //!< Has divisions along the z-axis?
|
||||
|
||||
virtual void to_hdf5_inner(hid_t group_id) const = 0;
|
||||
};
|
||||
|
|
@ -134,31 +146,31 @@ protected:
|
|||
class LatticeIter
|
||||
{
|
||||
public:
|
||||
int indx; //!< An index to a Lattice universes or offsets array.
|
||||
int indx_; //!< An index to a Lattice universes or offsets array.
|
||||
|
||||
LatticeIter(Lattice &lat_, int indx_)
|
||||
: lat(lat_),
|
||||
indx(indx_)
|
||||
LatticeIter(Lattice &lat, int indx)
|
||||
: lat_(lat),
|
||||
indx_(indx)
|
||||
{}
|
||||
|
||||
bool operator==(const LatticeIter &rhs) {return (indx == rhs.indx);}
|
||||
bool operator==(const LatticeIter &rhs) {return (indx_ == rhs.indx_);}
|
||||
|
||||
bool operator!=(const LatticeIter &rhs) {return !(*this == rhs);}
|
||||
|
||||
int32_t& operator*() {return lat.universes[indx];}
|
||||
int32_t& operator*() {return lat_.universes_[indx_];}
|
||||
|
||||
LatticeIter& operator++()
|
||||
{
|
||||
while (indx < lat.universes.size()) {
|
||||
++indx;
|
||||
if (lat.is_valid_index(indx)) return *this;
|
||||
while (indx_ < lat_.universes_.size()) {
|
||||
++indx_;
|
||||
if (lat_.is_valid_index(indx_)) return *this;
|
||||
}
|
||||
indx = lat.universes.size();
|
||||
indx_ = lat_.universes_.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
Lattice ⪫
|
||||
Lattice& lat_;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -168,17 +180,17 @@ protected:
|
|||
class ReverseLatticeIter : public LatticeIter
|
||||
{
|
||||
public:
|
||||
ReverseLatticeIter(Lattice &lat_, int indx_)
|
||||
: LatticeIter {lat_, indx_}
|
||||
ReverseLatticeIter(Lattice &lat, int indx)
|
||||
: LatticeIter {lat, indx}
|
||||
{}
|
||||
|
||||
ReverseLatticeIter& operator++()
|
||||
{
|
||||
while (indx > -1) {
|
||||
--indx;
|
||||
if (lat.is_valid_index(indx)) return *this;
|
||||
while (indx_ > -1) {
|
||||
--indx_;
|
||||
if (lat_.is_valid_index(indx_)) return *this;
|
||||
}
|
||||
indx = -1;
|
||||
indx_ = -1;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
|
@ -190,17 +202,17 @@ class RectLattice : public Lattice
|
|||
public:
|
||||
explicit RectLattice(pugi::xml_node lat_node);
|
||||
|
||||
int32_t& operator[](const int i_xyz[3]);
|
||||
int32_t& operator[](std::array<int, 3> i_xyz);
|
||||
|
||||
bool are_valid_indices(const int i_xyz[3]) const;
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
distance(Position r, Direction u, const int i_xyz[3]) const;
|
||||
distance(Position r, Direction u, const std::array<int, 3>& i_xyz) const;
|
||||
|
||||
std::array<int, 3> get_indices(Position r) const;
|
||||
|
||||
Position
|
||||
get_local_position(Position r, const int i_xyz[3]) const;
|
||||
get_local_position(Position r, const std::array<int, 3> i_xyz) const;
|
||||
|
||||
int32_t& offset(int map, const int i_xyz[3]);
|
||||
|
||||
|
|
@ -209,14 +221,14 @@ public:
|
|||
void to_hdf5_inner(hid_t group_id) const;
|
||||
|
||||
private:
|
||||
std::array<int, 3> n_cells; //!< Number of cells along each axis
|
||||
Position lower_left; //!< Global lower-left corner of the lattice
|
||||
Position pitch; //!< Lattice tile width along each axis
|
||||
std::array<int, 3> n_cells_; //!< Number of cells along each axis
|
||||
Position lower_left_; //!< Global lower-left corner of the lattice
|
||||
Position pitch_; //!< Lattice tile width along each axis
|
||||
|
||||
// Convenience aliases
|
||||
int &nx {n_cells[0]};
|
||||
int &ny {n_cells[1]};
|
||||
int &nz {n_cells[2]};
|
||||
int &nx {n_cells_[0]};
|
||||
int &ny {n_cells_[1]};
|
||||
int &nz {n_cells_[2]};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -226,7 +238,7 @@ class HexLattice : public Lattice
|
|||
public:
|
||||
explicit HexLattice(pugi::xml_node lat_node);
|
||||
|
||||
int32_t& operator[](const int i_xyz[3]);
|
||||
int32_t& operator[](std::array<int, 3> i_xyz);
|
||||
|
||||
LatticeIter begin();
|
||||
|
||||
|
|
@ -235,12 +247,12 @@ public:
|
|||
bool are_valid_indices(const int i_xyz[3]) const;
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
distance(Position r, Direction u, const int i_xyz[3]) const;
|
||||
distance(Position r, Direction u, const std::array<int, 3>& i_xyz) const;
|
||||
|
||||
std::array<int, 3> get_indices(Position r) const;
|
||||
|
||||
Position
|
||||
get_local_position(Position r, const int i_xyz[3]) const;
|
||||
get_local_position(Position r, const std::array<int, 3> i_xyz) const;
|
||||
|
||||
bool is_valid_index(int indx) const;
|
||||
|
||||
|
|
@ -251,10 +263,10 @@ public:
|
|||
void to_hdf5_inner(hid_t group_id) const;
|
||||
|
||||
private:
|
||||
int n_rings; //!< Number of radial tile positions
|
||||
int n_axial; //!< Number of axial tile positions
|
||||
Position center; //!< Global center of lattice
|
||||
std::array<double, 2> pitch; //!< Lattice tile width and height
|
||||
int n_rings_; //!< Number of radial tile positions
|
||||
int n_axial_; //!< Number of axial tile positions
|
||||
Position center_; //!< Global center of lattice
|
||||
std::array<double, 2> pitch_; //!< Lattice tile width and height
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace openmc {
|
|||
//==============================================================================
|
||||
|
||||
class Material;
|
||||
extern std::vector<Material*> global_materials;
|
||||
extern std::vector<Material*> materials;
|
||||
extern std::unordered_map<int32_t, int32_t> material_map;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -27,6 +27,11 @@ public:
|
|||
int32_t id; //!< Unique ID
|
||||
double volume_ {-1.0}; //!< Volume in [cm^3]
|
||||
|
||||
//! \brief Default temperature for cells containing this material.
|
||||
//!
|
||||
//! A negative value indicates no default temperature was specified.
|
||||
double temperature_ {-1};
|
||||
|
||||
Material() {};
|
||||
|
||||
explicit Material(pugi::xml_node material_node);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace openmc {
|
|||
|
||||
extern std::vector<Mgxs> nuclides_MG;
|
||||
extern std::vector<Mgxs> macro_xs;
|
||||
extern "C" int num_energy_groups;
|
||||
|
||||
//==============================================================================
|
||||
// Mgxs data loading interface methods
|
||||
|
|
|
|||
|
|
@ -1,10 +1,24 @@
|
|||
//! \file nuclide.h
|
||||
//! \brief Nuclide type and other associated types/data
|
||||
|
||||
#ifndef OPENMC_NUCLIDE_H
|
||||
#define OPENMC_NUCLIDE_H
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "openmc/constants.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
// Minimum/maximum transport energy for each particle type. Order corresponds to
|
||||
// that of the ParticleType enum
|
||||
extern std::array<double, 2> energy_min;
|
||||
extern std::array<double, 2> energy_max;
|
||||
|
||||
//===============================================================================
|
||||
//! Cached microscopic cross sections for a particular nuclide at the current
|
||||
//! energy
|
||||
|
|
|
|||
26
include/openmc/output.h
Normal file
26
include/openmc/output.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//! \file output.h
|
||||
//! Functions for ASCII output.
|
||||
|
||||
#ifndef OPENMC_OUTPUT_H
|
||||
#define OPENMC_OUTPUT_H
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
//! Display a header block.
|
||||
//!
|
||||
//! \param msg The main text of the header
|
||||
//! \param level The lowest verbosity level at which this header is printed
|
||||
//==============================================================================
|
||||
|
||||
void header(const char* msg, int level);
|
||||
|
||||
//==============================================================================
|
||||
//! Display information regarding cell overlap checking.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void print_overlap_check();
|
||||
|
||||
} // namespace openmc
|
||||
#endif // OPENMC_OUTPUT_H
|
||||
|
|
@ -4,8 +4,10 @@
|
|||
//! \file particle.h
|
||||
//! \brief Particle type
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "openmc/capi.h"
|
||||
|
||||
|
|
@ -33,7 +35,7 @@ constexpr double REL_MAX_LOST_PARTICLES {1.0e-6};
|
|||
|
||||
//! Particle types
|
||||
enum class ParticleType {
|
||||
neutron, photon, electron, positron
|
||||
neutron = 1, photon = 2, electron = 3, positron = 4
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -152,6 +154,12 @@ extern "C" {
|
|||
//! \param message A warning message to display
|
||||
void mark_as_lost(const char* message);
|
||||
|
||||
void mark_as_lost(const std::string& message)
|
||||
{mark_as_lost(message.c_str());}
|
||||
|
||||
void mark_as_lost(const std::stringstream& message)
|
||||
{mark_as_lost(message.str());}
|
||||
|
||||
//! create a particle restart HDF5 file
|
||||
void write_restart();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef OPENMC_POSITION_H
|
||||
#define OPENMC_POSITION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -12,6 +14,7 @@ struct Position {
|
|||
Position() = default;
|
||||
Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { };
|
||||
Position(const double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { };
|
||||
Position(const std::vector<double> xyz) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { };
|
||||
|
||||
// Unary operators
|
||||
Position& operator+=(Position);
|
||||
|
|
@ -63,6 +66,12 @@ inline Position operator*(Position a, Position b) { return a *= b; }
|
|||
inline Position operator*(Position a, double b) { return a *= b; }
|
||||
inline Position operator*(double a, Position b) { return b *= a; }
|
||||
|
||||
inline bool operator==(Position a, Position b)
|
||||
{return a.x == b.x && a.y == b.y && a.z == b.z;}
|
||||
|
||||
inline bool operator!=(Position a, Position b)
|
||||
{return a.x != b.x || a.y != b.y || a.z != b.z;}
|
||||
|
||||
//==============================================================================
|
||||
//! Type representing a vector direction in Cartesian coordinates
|
||||
//==============================================================================
|
||||
|
|
@ -71,4 +80,4 @@ using Direction = Position;
|
|||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_POSITION_H
|
||||
#endif // OPENMC_POSITION_H
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@ namespace openmc {
|
|||
// Defined on Fortran side
|
||||
extern "C" bool openmc_check_overlaps;
|
||||
extern "C" bool openmc_particle_restart_run;
|
||||
extern "C" bool openmc_photon_transport;
|
||||
extern "C" bool openmc_restart_run;
|
||||
extern "C" bool openmc_run_CE;
|
||||
extern "C" int openmc_verbosity;
|
||||
extern "C" bool openmc_write_all_tracks;
|
||||
extern "C" bool openmc_write_initial_source;
|
||||
|
||||
// Defined in .cpp
|
||||
// TODO: Make strings instead of char* once Fortran is gone
|
||||
|
|
|
|||
|
|
@ -1,13 +1,39 @@
|
|||
//! \file simulation.h
|
||||
//! \brief Variables/functions related to a running simulation
|
||||
|
||||
#ifndef OPENMC_SIMULATION_H
|
||||
#define OPENMC_SIMULATION_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
extern "C" int openmc_current_batch;
|
||||
extern "C" int openmc_current_gen;
|
||||
extern "C" int64_t openmc_current_work;
|
||||
extern "C" int openmc_n_lost_particles;
|
||||
extern "C" int openmc_total_gen;
|
||||
extern "C" bool openmc_trace;
|
||||
|
||||
#pragma omp threadprivate(openmc_current_work)
|
||||
extern std::vector<int64_t> work_index;
|
||||
|
||||
#pragma omp threadprivate(openmc_current_work, openmc_trace)
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
//==============================================================================
|
||||
|
||||
//! Initialize simulation
|
||||
extern "C" void openmc_simulation_init_c();
|
||||
|
||||
//! Determine number of particles to transport per process
|
||||
void calculate_work();
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_SIMULATION_H
|
||||
|
|
|
|||
63
include/openmc/source.h
Normal file
63
include/openmc/source.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
//! \file source.h
|
||||
//! \brief External source distributions
|
||||
|
||||
#ifndef OPENMC_SOURCE_H
|
||||
#define OPENMC_SOURCE_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "openmc/distribution_multi.h"
|
||||
#include "openmc/distribution_spatial.h"
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
//! External source distribution
|
||||
//==============================================================================
|
||||
|
||||
class SourceDistribution {
|
||||
public:
|
||||
// Constructors
|
||||
SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy);
|
||||
explicit SourceDistribution(pugi::xml_node node);
|
||||
|
||||
//! Sample from the external source distribution
|
||||
//! \return Sampled site
|
||||
Bank sample() const;
|
||||
|
||||
// Properties
|
||||
double strength() const { return strength_; }
|
||||
private:
|
||||
ParticleType particle_ {ParticleType::neutron}; //!< Type of particle emitted
|
||||
double strength_ {1.0}; //!< Source strength
|
||||
UPtrSpace space_; //!< Spatial distribution
|
||||
UPtrAngle angle_; //!< Angular distribution
|
||||
UPtrDist energy_; //!< Energy distribution
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
extern std::vector<SourceDistribution> external_sources;
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
//==============================================================================
|
||||
|
||||
//! Initialize source bank from file/distribution
|
||||
extern "C" void initialize_source();
|
||||
|
||||
//! Sample a site from all external source distributions in proportion to their
|
||||
//! source strength
|
||||
//! \return Sampled source site
|
||||
extern "C" Bank sample_external_source();
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_SOURCE_H
|
||||
|
|
@ -32,7 +32,7 @@ extern "C" const int BC_PERIODIC;
|
|||
extern "C" int32_t n_surfaces;
|
||||
|
||||
class Surface;
|
||||
extern std::vector<Surface*> global_surfaces;
|
||||
extern std::vector<Surface*> surfaces;
|
||||
|
||||
extern std::map<int, int> surface_map;
|
||||
|
||||
|
|
@ -57,11 +57,12 @@ struct BoundingBox
|
|||
class Surface
|
||||
{
|
||||
public:
|
||||
int id; //!< Unique ID
|
||||
//int neighbor_pos[], //!< List of cells on positive side
|
||||
// neighbor_neg[]; //!< List of cells on negative side
|
||||
int bc; //!< Boundary condition
|
||||
std::string name; //!< User-defined name
|
||||
int id_; //!< Unique ID
|
||||
int bc_; //!< Boundary condition
|
||||
std::string name_; //!< User-defined name
|
||||
|
||||
std::vector<int> neighbor_pos_; //!< List of cells on positive side
|
||||
std::vector<int> neighbor_neg_; //!< List of cells on negative side
|
||||
|
||||
explicit Surface(pugi::xml_node surf_node);
|
||||
|
||||
|
|
@ -120,7 +121,7 @@ protected:
|
|||
class PeriodicSurface : public Surface
|
||||
{
|
||||
public:
|
||||
int i_periodic{C_NONE}; //!< Index of corresponding periodic surface
|
||||
int i_periodic_{C_NONE}; //!< Index of corresponding periodic surface
|
||||
|
||||
explicit PeriodicSurface(pugi::xml_node surf_node);
|
||||
|
||||
|
|
@ -147,7 +148,7 @@ public:
|
|||
|
||||
class SurfaceXPlane : public PeriodicSurface
|
||||
{
|
||||
double x0;
|
||||
double x0_;
|
||||
public:
|
||||
explicit SurfaceXPlane(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -167,7 +168,7 @@ public:
|
|||
|
||||
class SurfaceYPlane : public PeriodicSurface
|
||||
{
|
||||
double y0;
|
||||
double y0_;
|
||||
public:
|
||||
explicit SurfaceYPlane(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -187,7 +188,7 @@ public:
|
|||
|
||||
class SurfaceZPlane : public PeriodicSurface
|
||||
{
|
||||
double z0;
|
||||
double z0_;
|
||||
public:
|
||||
explicit SurfaceZPlane(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -207,7 +208,7 @@ public:
|
|||
|
||||
class SurfacePlane : public PeriodicSurface
|
||||
{
|
||||
double A, B, C, D;
|
||||
double A_, B_, C_, D_;
|
||||
public:
|
||||
explicit SurfacePlane(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -228,7 +229,7 @@ public:
|
|||
|
||||
class SurfaceXCylinder : public Surface
|
||||
{
|
||||
double y0, z0, radius;
|
||||
double y0_, z0_, radius_;
|
||||
public:
|
||||
explicit SurfaceXCylinder(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -246,7 +247,7 @@ public:
|
|||
|
||||
class SurfaceYCylinder : public Surface
|
||||
{
|
||||
double x0, z0, radius;
|
||||
double x0_, z0_, radius_;
|
||||
public:
|
||||
explicit SurfaceYCylinder(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -264,7 +265,7 @@ public:
|
|||
|
||||
class SurfaceZCylinder : public Surface
|
||||
{
|
||||
double x0, y0, radius;
|
||||
double x0_, y0_, radius_;
|
||||
public:
|
||||
explicit SurfaceZCylinder(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -282,7 +283,7 @@ public:
|
|||
|
||||
class SurfaceSphere : public Surface
|
||||
{
|
||||
double x0, y0, z0, radius;
|
||||
double x0_, y0_, z0_, radius_;
|
||||
public:
|
||||
explicit SurfaceSphere(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -300,7 +301,7 @@ public:
|
|||
|
||||
class SurfaceXCone : public Surface
|
||||
{
|
||||
double x0, y0, z0, radius_sq;
|
||||
double x0_, y0_, z0_, radius_sq_;
|
||||
public:
|
||||
explicit SurfaceXCone(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -318,7 +319,7 @@ public:
|
|||
|
||||
class SurfaceYCone : public Surface
|
||||
{
|
||||
double x0, y0, z0, radius_sq;
|
||||
double x0_, y0_, z0_, radius_sq_;
|
||||
public:
|
||||
explicit SurfaceYCone(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -336,7 +337,7 @@ public:
|
|||
|
||||
class SurfaceZCone : public Surface
|
||||
{
|
||||
double x0, y0, z0, radius_sq;
|
||||
double x0_, y0_, z0_, radius_sq_;
|
||||
public:
|
||||
explicit SurfaceZCone(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -354,7 +355,7 @@ public:
|
|||
class SurfaceQuadric : public Surface
|
||||
{
|
||||
// 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;
|
||||
double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_;
|
||||
public:
|
||||
explicit SurfaceQuadric(pugi::xml_node surf_node);
|
||||
double evaluate(Position r) const;
|
||||
|
|
@ -373,10 +374,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(Surface* surf, hid_t group);
|
||||
int surface_i_periodic(PeriodicSurface* surf);
|
||||
bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other,
|
||||
double xyz[3], double uvw[3]);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class Cell(_FortranObjectWithID):
|
|||
Which instance of the cell
|
||||
|
||||
"""
|
||||
_dll.openmc_cell_set_temperature(self._index, T, instance)
|
||||
_dll.openmc_cell_set_temperature(self._index, T, c_int32(instance))
|
||||
|
||||
|
||||
class _CellMapping(Mapping):
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class Cell(IDManagerMixin):
|
|||
|
||||
.. math::
|
||||
|
||||
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\theta \sin\psi
|
||||
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\phi \sin\psi
|
||||
+ \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi
|
||||
\sin\theta \cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi +
|
||||
\sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi
|
||||
|
|
|
|||
14
src/api.F90
14
src/api.F90
|
|
@ -20,7 +20,6 @@ module openmc_api
|
|||
use random_lcg, only: openmc_get_seed, openmc_set_seed
|
||||
use settings
|
||||
use simulation_header
|
||||
use source_header, only: openmc_extend_sources, openmc_source_set_strength
|
||||
use state_point, only: openmc_statepoint_write
|
||||
use tally_header
|
||||
use tally_filter_header
|
||||
|
|
@ -38,13 +37,11 @@ module openmc_api
|
|||
public :: openmc_cell_filter_get_bins
|
||||
public :: openmc_cell_get_id
|
||||
public :: openmc_cell_set_id
|
||||
public :: openmc_cell_set_temperature
|
||||
public :: openmc_energy_filter_get_bins
|
||||
public :: openmc_energy_filter_set_bins
|
||||
public :: openmc_extend_filters
|
||||
public :: openmc_extend_cells
|
||||
public :: openmc_extend_materials
|
||||
public :: openmc_extend_sources
|
||||
public :: openmc_extend_tallies
|
||||
public :: openmc_filter_get_id
|
||||
public :: openmc_filter_get_type
|
||||
|
|
@ -83,7 +80,6 @@ module openmc_api
|
|||
public :: openmc_simulation_finalize
|
||||
public :: openmc_simulation_init
|
||||
public :: openmc_source_bank
|
||||
public :: openmc_source_set_strength
|
||||
public :: openmc_tally_allocate
|
||||
public :: openmc_tally_get_estimator
|
||||
public :: openmc_tally_get_id
|
||||
|
|
@ -210,8 +206,8 @@ contains
|
|||
err = E_UNASSIGNED
|
||||
|
||||
if (found) then
|
||||
index = p % coord(p % n_coord) % cell
|
||||
instance = p % cell_instance - 1
|
||||
index = p % coord(p % n_coord) % cell + 1
|
||||
instance = p % cell_instance
|
||||
err = 0
|
||||
else
|
||||
err = E_GEOMETRY
|
||||
|
|
@ -301,12 +297,16 @@ contains
|
|||
use plot_header
|
||||
use sab_header
|
||||
use settings
|
||||
use source_header
|
||||
use surface_header
|
||||
use tally_derivative_header
|
||||
use trigger_header
|
||||
use volume_header
|
||||
|
||||
interface
|
||||
subroutine free_memory_source() bind(C)
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
call free_memory_geometry()
|
||||
call free_memory_surfaces()
|
||||
call free_memory_material()
|
||||
|
|
|
|||
386
src/cell.cpp
386
src/cell.cpp
|
|
@ -7,36 +7,27 @@
|
|||
#include "openmc/capi.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/geometry.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/lattice.h"
|
||||
#include "openmc/material.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/surface.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Constants
|
||||
//==============================================================================
|
||||
|
||||
// TODO: Convert to enum
|
||||
constexpr int32_t OP_LEFT_PAREN {std::numeric_limits<int32_t>::max()};
|
||||
constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits<int32_t>::max() - 1};
|
||||
constexpr int32_t OP_COMPLEMENT {std::numeric_limits<int32_t>::max() - 2};
|
||||
constexpr int32_t OP_INTERSECTION {std::numeric_limits<int32_t>::max() - 3};
|
||||
constexpr int32_t OP_UNION {std::numeric_limits<int32_t>::max() - 4};
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
int32_t n_cells {0};
|
||||
|
||||
std::vector<Cell*> global_cells;
|
||||
std::vector<Cell*> cells;
|
||||
std::unordered_map<int32_t, int32_t> cell_map;
|
||||
|
||||
std::vector<Universe*> global_universes;
|
||||
std::vector<Universe*> universes;
|
||||
std::unordered_map<int32_t, int32_t> universe_map;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -192,6 +183,28 @@ generate_rpn(int32_t cell_id, std::vector<int32_t> infix)
|
|||
return rpn;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Universe implementation
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Universe::to_hdf5(hid_t universes_group) const
|
||||
{
|
||||
// Create a group for this universe.
|
||||
std::stringstream group_name;
|
||||
group_name << "universe " << id_;
|
||||
auto group = create_group(universes_group, group_name);
|
||||
|
||||
// Write the contained cells.
|
||||
if (cells_.size() > 0) {
|
||||
std::vector<int32_t> cell_ids;
|
||||
for (auto i_cell : cells_) cell_ids.push_back(cells[i_cell]->id_);
|
||||
write_dataset(group, "cells", cell_ids);
|
||||
}
|
||||
|
||||
close_group(group);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Cell implementation
|
||||
//==============================================================================
|
||||
|
|
@ -199,19 +212,19 @@ generate_rpn(int32_t cell_id, std::vector<int32_t> infix)
|
|||
Cell::Cell(pugi::xml_node cell_node)
|
||||
{
|
||||
if (check_for_node(cell_node, "id")) {
|
||||
id = std::stoi(get_node_value(cell_node, "id"));
|
||||
id_ = std::stoi(get_node_value(cell_node, "id"));
|
||||
} else {
|
||||
fatal_error("Must specify id of cell in geometry XML file.");
|
||||
}
|
||||
|
||||
if (check_for_node(cell_node, "name")) {
|
||||
name = get_node_value(cell_node, "name");
|
||||
name_ = get_node_value(cell_node, "name");
|
||||
}
|
||||
|
||||
if (check_for_node(cell_node, "universe")) {
|
||||
universe = std::stoi(get_node_value(cell_node, "universe"));
|
||||
universe_ = std::stoi(get_node_value(cell_node, "universe"));
|
||||
} else {
|
||||
universe = 0;
|
||||
universe_ = 0;
|
||||
}
|
||||
|
||||
// Make sure that either material or fill was specified, but not both.
|
||||
|
|
@ -219,20 +232,20 @@ Cell::Cell(pugi::xml_node cell_node)
|
|||
bool material_present = check_for_node(cell_node, "material");
|
||||
if (!(fill_present || material_present)) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Neither material nor fill was specified for cell " << id;
|
||||
err_msg << "Neither material nor fill was specified for cell " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
if (fill_present && material_present) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cell " << id << " has both a material and a fill specified; "
|
||||
err_msg << "Cell " << id_ << " has both a material and a fill specified; "
|
||||
<< "only one can be specified per cell";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
||||
if (fill_present) {
|
||||
fill = std::stoi(get_node_value(cell_node, "fill"));
|
||||
fill_ = std::stoi(get_node_value(cell_node, "fill"));
|
||||
} else {
|
||||
fill = C_NONE;
|
||||
fill_ = C_NONE;
|
||||
}
|
||||
|
||||
// Read the material element. There can be zero materials (filled with a
|
||||
|
|
@ -242,21 +255,51 @@ Cell::Cell(pugi::xml_node cell_node)
|
|||
std::vector<std::string> mats
|
||||
{get_node_array<std::string>(cell_node, "material", true)};
|
||||
if (mats.size() > 0) {
|
||||
material.reserve(mats.size());
|
||||
material_.reserve(mats.size());
|
||||
for (std::string mat : mats) {
|
||||
if (mat.compare("void") == 0) {
|
||||
material.push_back(MATERIAL_VOID);
|
||||
material_.push_back(MATERIAL_VOID);
|
||||
} else {
|
||||
material.push_back(std::stoi(mat));
|
||||
material_.push_back(std::stoi(mat));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "An empty material element was specified for cell " << id;
|
||||
err_msg << "An empty material element was specified for cell " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the temperature element which may be distributed like materials.
|
||||
if (check_for_node(cell_node, "temperature")) {
|
||||
sqrtkT_ = get_node_array<double>(cell_node, "temperature");
|
||||
sqrtkT_.shrink_to_fit();
|
||||
|
||||
// Make sure this is a material-filled cell.
|
||||
if (material_.size() == 0) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cell " << id_ << " was specified with a temperature but "
|
||||
"no material. Temperature specification is only valid for cells "
|
||||
"filled with a material.";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
||||
// Make sure all temperatures are non-negative.
|
||||
for (auto T : sqrtkT_) {
|
||||
if (T < 0) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cell " << id_
|
||||
<< " was specified with a negative temperature";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to sqrt(k*T).
|
||||
for (auto& T : sqrtkT_) {
|
||||
T = std::sqrt(K_BOLTZMANN * T);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the region specification.
|
||||
std::string region_spec;
|
||||
if (check_for_node(cell_node, "region")) {
|
||||
|
|
@ -264,28 +307,87 @@ Cell::Cell(pugi::xml_node cell_node)
|
|||
}
|
||||
|
||||
// Get a tokenized representation of the region specification.
|
||||
region = tokenize(region_spec);
|
||||
region.shrink_to_fit();
|
||||
region_ = tokenize(region_spec);
|
||||
region_.shrink_to_fit();
|
||||
|
||||
// Convert user IDs to surface indices.
|
||||
for (auto &r : region) {
|
||||
for (auto& r : region_) {
|
||||
if (r < OP_UNION) {
|
||||
r = copysign(surface_map[abs(r)] + 1, r);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the infix region spec to RPN.
|
||||
rpn = generate_rpn(id, region);
|
||||
rpn.shrink_to_fit();
|
||||
rpn_ = generate_rpn(id_, region_);
|
||||
rpn_.shrink_to_fit();
|
||||
|
||||
// Check if this is a simple cell.
|
||||
simple = true;
|
||||
for (int32_t token : rpn) {
|
||||
simple_ = true;
|
||||
for (int32_t token : rpn_) {
|
||||
if ((token == OP_COMPLEMENT) || (token == OP_UNION)) {
|
||||
simple = false;
|
||||
simple_ = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the translation vector.
|
||||
if (check_for_node(cell_node, "translation")) {
|
||||
if (fill_ == C_NONE) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cannot apply a translation to cell " << id_
|
||||
<< " because it is not filled with another universe";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
||||
auto xyz {get_node_array<double>(cell_node, "translation")};
|
||||
if (xyz.size() != 3) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Non-3D translation vector applied to cell " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
translation_ = xyz;
|
||||
}
|
||||
|
||||
// Read the rotation transform.
|
||||
if (check_for_node(cell_node, "rotation")) {
|
||||
if (fill_ == C_NONE) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cannot apply a rotation to cell " << id_
|
||||
<< " because it is not filled with another universe";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
||||
auto rot {get_node_array<double>(cell_node, "rotation")};
|
||||
if (rot.size() != 3) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Non-3D rotation vector applied to cell " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
||||
// Store the rotation angles.
|
||||
rotation_.reserve(12);
|
||||
rotation_.push_back(rot[0]);
|
||||
rotation_.push_back(rot[1]);
|
||||
rotation_.push_back(rot[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;
|
||||
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));
|
||||
rotation_.push_back(std::sin(phi) * std::sin(psi)
|
||||
+ std::cos(phi) * std::sin(theta) * std::cos(psi));
|
||||
rotation_.push_back(std::cos(theta) * std::sin(psi));
|
||||
rotation_.push_back(std::cos(phi) * std::cos(psi)
|
||||
+ std::sin(phi) * std::sin(theta) * std::sin(psi));
|
||||
rotation_.push_back(-std::sin(phi) * std::cos(psi)
|
||||
+ std::cos(phi) * std::sin(theta) * std::sin(psi));
|
||||
rotation_.push_back(-std::sin(theta));
|
||||
rotation_.push_back(std::sin(phi) * std::cos(theta));
|
||||
rotation_.push_back(std::cos(phi) * std::cos(theta));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -293,7 +395,7 @@ Cell::Cell(pugi::xml_node cell_node)
|
|||
bool
|
||||
Cell::contains(Position r, Direction u, int32_t on_surface) const
|
||||
{
|
||||
if (simple) {
|
||||
if (simple_) {
|
||||
return contains_simple(r, u, on_surface);
|
||||
} else {
|
||||
return contains_complex(r, u, on_surface);
|
||||
|
|
@ -308,14 +410,14 @@ Cell::distance(Position r, Direction u, int32_t on_surface) const
|
|||
double min_dist {INFTY};
|
||||
int32_t i_surf {std::numeric_limits<int32_t>::max()};
|
||||
|
||||
for (int32_t token : rpn) {
|
||||
for (int32_t token : rpn_) {
|
||||
// Ignore this token if it corresponds to an operator rather than a region.
|
||||
if (token >= OP_UNION) continue;
|
||||
|
||||
// Calculate the distance to this surface.
|
||||
// Note the off-by-one indexing
|
||||
bool coincident {token == on_surface};
|
||||
double d {global_surfaces[abs(token)-1]->distance(r, u, coincident)};
|
||||
double d {surfaces[abs(token)-1]->distance(r, u, coincident)};
|
||||
|
||||
// Check if this distance is the new minimum.
|
||||
if (d < min_dist) {
|
||||
|
|
@ -332,19 +434,23 @@ Cell::distance(Position r, Direction u, int32_t on_surface) const
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
Cell::to_hdf5(hid_t cell_group) const
|
||||
Cell::to_hdf5(hid_t cells_group) const
|
||||
{
|
||||
if (!name.empty()) {
|
||||
write_string(cell_group, "name", name, false);
|
||||
// Create a group for this cell.
|
||||
std::stringstream group_name;
|
||||
group_name << "cell " << id_;
|
||||
auto group = create_group(cells_group, group_name);
|
||||
|
||||
if (!name_.empty()) {
|
||||
write_string(group, "name", name_, false);
|
||||
}
|
||||
|
||||
//TODO: Fix the off-by-one indexing.
|
||||
write_dataset(cell_group, "universe", global_universes[universe-1]->id);
|
||||
write_dataset(group, "universe", universes[universe_]->id_);
|
||||
|
||||
// Write the region specification.
|
||||
if (!region.empty()) {
|
||||
if (!region_.empty()) {
|
||||
std::stringstream region_spec {};
|
||||
for (int32_t token : region) {
|
||||
for (int32_t token : region_) {
|
||||
if (token == OP_LEFT_PAREN) {
|
||||
region_spec << " (";
|
||||
} else if (token == OP_RIGHT_PAREN) {
|
||||
|
|
@ -357,11 +463,51 @@ Cell::to_hdf5(hid_t cell_group) const
|
|||
} else {
|
||||
// Note the off-by-one indexing
|
||||
region_spec << " "
|
||||
<< copysign(global_surfaces[abs(token)-1]->id, token);
|
||||
<< copysign(surfaces[abs(token)-1]->id_, token);
|
||||
}
|
||||
}
|
||||
write_string(cell_group, "region", region_spec.str(), false);
|
||||
write_string(group, "region", region_spec.str(), false);
|
||||
}
|
||||
|
||||
// Write fill information.
|
||||
if (type_ == FILL_MATERIAL) {
|
||||
write_dataset(group, "fill_type", "material");
|
||||
std::vector<int32_t> mat_ids;
|
||||
for (auto i_mat : material_) {
|
||||
if (i_mat != MATERIAL_VOID) {
|
||||
mat_ids.push_back(materials[i_mat]->id);
|
||||
} else {
|
||||
mat_ids.push_back(MATERIAL_VOID);
|
||||
}
|
||||
}
|
||||
if (mat_ids.size() == 1) {
|
||||
write_dataset(group, "material", mat_ids[0]);
|
||||
} else {
|
||||
write_dataset(group, "material", mat_ids);
|
||||
}
|
||||
|
||||
std::vector<double> temps;
|
||||
for (auto sqrtkT_val : sqrtkT_)
|
||||
temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN);
|
||||
write_dataset(group, "temperature", temps);
|
||||
|
||||
} else if (type_ == FILL_UNIVERSE) {
|
||||
write_dataset(group, "fill_type", "universe");
|
||||
write_dataset(group, "fill", universes[fill_]->id_);
|
||||
if (translation_ != Position(0, 0, 0)) {
|
||||
write_dataset(group, "translation", translation_);
|
||||
}
|
||||
if (!rotation_.empty()) {
|
||||
std::array<double, 3> rot {rotation_[0], rotation_[1], rotation_[2]};
|
||||
write_dataset(group, "rotation", rot);
|
||||
}
|
||||
|
||||
} else if (type_ == FILL_LATTICE) {
|
||||
write_dataset(group, "fill_type", "lattice");
|
||||
write_dataset(group, "lattice", lattices[fill_]->id_);
|
||||
}
|
||||
|
||||
close_group(group);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -369,7 +515,7 @@ Cell::to_hdf5(hid_t cell_group) const
|
|||
bool
|
||||
Cell::contains_simple(Position r, Direction u, int32_t on_surface) const
|
||||
{
|
||||
for (int32_t token : rpn) {
|
||||
for (int32_t token : rpn_) {
|
||||
if (token < OP_UNION) {
|
||||
// If the token is not an operator, evaluate the sense of particle with
|
||||
// respect to the surface and see if the token matches the sense. If the
|
||||
|
|
@ -380,7 +526,7 @@ Cell::contains_simple(Position r, Direction u, int32_t on_surface) const
|
|||
return false;
|
||||
} else {
|
||||
// Note the off-by-one indexing
|
||||
bool sense = global_surfaces[abs(token)-1]->sense(r, u);
|
||||
bool sense = surfaces[abs(token)-1]->sense(r, u);
|
||||
if (sense != (token > 0)) {return false;}
|
||||
}
|
||||
}
|
||||
|
|
@ -395,10 +541,10 @@ Cell::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.
|
||||
bool stack[rpn.size()];
|
||||
bool stack[rpn_.size()];
|
||||
int i_stack = -1;
|
||||
|
||||
for (int32_t token : rpn) {
|
||||
for (int32_t token : rpn_) {
|
||||
// If the token is a binary operator (intersection/union), apply it to
|
||||
// the last two items on the stack. If the token is a unary operator
|
||||
// (complement), apply it to the last item on the stack.
|
||||
|
|
@ -422,7 +568,7 @@ Cell::contains_complex(Position r, Direction u, int32_t on_surface) const
|
|||
stack[i_stack] = false;
|
||||
} else {
|
||||
// Note the off-by-one indexing
|
||||
bool sense = global_surfaces[abs(token)-1]->sense(r, u);
|
||||
bool sense = surfaces[abs(token)-1]->sense(r, u);
|
||||
stack[i_stack] = (sense == (token > 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -453,25 +599,28 @@ read_cells(pugi::xml_node* node)
|
|||
}
|
||||
|
||||
// Loop over XML cell elements and populate the array.
|
||||
global_cells.reserve(n_cells);
|
||||
cells.reserve(n_cells);
|
||||
for (pugi::xml_node cell_node: node->children("cell")) {
|
||||
global_cells.push_back(new Cell(cell_node));
|
||||
cells.push_back(new Cell(cell_node));
|
||||
}
|
||||
|
||||
// Populate the Universe vector and map.
|
||||
for (int i = 0; i < global_cells.size(); i++) {
|
||||
int32_t uid = global_cells[i]->universe;
|
||||
for (int i = 0; i < cells.size(); i++) {
|
||||
int32_t uid = cells[i]->universe_;
|
||||
auto it = universe_map.find(uid);
|
||||
if (it == universe_map.end()) {
|
||||
global_universes.push_back(new Universe());
|
||||
global_universes.back()->id = uid;
|
||||
global_universes.back()->cells.push_back(i);
|
||||
universe_map[uid] = global_universes.size() - 1;
|
||||
universes.push_back(new Universe());
|
||||
universes.back()->id_ = uid;
|
||||
universes.back()->cells_.push_back(i);
|
||||
universe_map[uid] = universes.size() - 1;
|
||||
} else {
|
||||
global_universes[it->second]->cells.push_back(i);
|
||||
universes[it->second]->cells_.push_back(i);
|
||||
}
|
||||
}
|
||||
global_universes.shrink_to_fit();
|
||||
universes.shrink_to_fit();
|
||||
|
||||
// Allocate the cell overlap count if necessary.
|
||||
if (openmc_check_overlaps) overlap_check_count.resize(n_cells, 0);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -481,15 +630,15 @@ read_cells(pugi::xml_node* node)
|
|||
extern "C" int
|
||||
openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n)
|
||||
{
|
||||
if (index >= 1 && index <= global_cells.size()) {
|
||||
if (index >= 1 && index <= cells.size()) {
|
||||
//TODO: off-by-one
|
||||
Cell& c {*global_cells[index - 1]};
|
||||
*type = c.type;
|
||||
if (c.type == FILL_MATERIAL) {
|
||||
*indices = c.material.data();
|
||||
*n = c.material.size();
|
||||
Cell& c {*cells[index - 1]};
|
||||
*type = c.type_;
|
||||
if (c.type_ == FILL_MATERIAL) {
|
||||
*indices = c.material_.data();
|
||||
*n = c.material_.size();
|
||||
} else {
|
||||
*indices = &c.fill;
|
||||
*indices = &c.fill_;
|
||||
*n = 1;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -503,29 +652,29 @@ extern "C" int
|
|||
openmc_cell_set_fill(int32_t index, int type, int32_t n,
|
||||
const int32_t* indices)
|
||||
{
|
||||
if (index >= 1 && index <= global_cells.size()) {
|
||||
if (index >= 1 && index <= cells.size()) {
|
||||
//TODO: off-by-one
|
||||
Cell& c {*global_cells[index - 1]};
|
||||
Cell& c {*cells[index - 1]};
|
||||
if (type == FILL_MATERIAL) {
|
||||
c.type = FILL_MATERIAL;
|
||||
c.material.clear();
|
||||
c.type_ = FILL_MATERIAL;
|
||||
c.material_.clear();
|
||||
for (int i = 0; i < n; i++) {
|
||||
int i_mat = indices[i];
|
||||
if (i_mat == MATERIAL_VOID) {
|
||||
c.material.push_back(MATERIAL_VOID);
|
||||
} else if (i_mat >= 1 && i_mat <= global_materials.size()) {
|
||||
c.material_.push_back(MATERIAL_VOID);
|
||||
} else if (i_mat >= 1 && i_mat <= materials.size()) {
|
||||
//TODO: off-by-one
|
||||
c.material.push_back(i_mat - 1);
|
||||
c.material_.push_back(i_mat - 1);
|
||||
} else {
|
||||
set_errmsg("Index in materials array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
}
|
||||
c.material.shrink_to_fit();
|
||||
c.material_.shrink_to_fit();
|
||||
} else if (type == FILL_UNIVERSE) {
|
||||
c.type = FILL_UNIVERSE;
|
||||
c.type_ = FILL_UNIVERSE;
|
||||
} else {
|
||||
c.type = FILL_LATTICE;
|
||||
c.type_ = FILL_LATTICE;
|
||||
}
|
||||
} else {
|
||||
set_errmsg("Index in cells array is out of bounds.");
|
||||
|
|
@ -534,66 +683,85 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n,
|
|||
return 0;
|
||||
}
|
||||
|
||||
//TODO: make sure data is loaded for this temperature
|
||||
extern "C" int
|
||||
openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance)
|
||||
{
|
||||
if (index >= 1 && index <= cells.size()) {
|
||||
//TODO: off-by-one
|
||||
Cell& c {*cells[index - 1]};
|
||||
|
||||
if (instance) {
|
||||
if (*instance >= 0 && *instance < c.sqrtkT_.size()) {
|
||||
c.sqrtkT_[*instance] = std::sqrt(K_BOLTZMANN * T);
|
||||
} else {
|
||||
strcpy(openmc_err_msg, "Distribcell instance is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
} else {
|
||||
for (auto& T_ : c.sqrtkT_) {
|
||||
T_ = std::sqrt(K_BOLTZMANN * T);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
strcpy(openmc_err_msg, "Index in cells array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Fortran compatibility functions
|
||||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
Cell* cell_pointer(int32_t cell_ind) {return global_cells[cell_ind];}
|
||||
Cell* cell_pointer(int32_t cell_ind) {return cells[cell_ind];}
|
||||
|
||||
int32_t cell_id(Cell* c) {return c->id;}
|
||||
int32_t cell_id(Cell* c) {return c->id_;}
|
||||
|
||||
void cell_set_id(Cell* c, int32_t id) {c->id = id;}
|
||||
void cell_set_id(Cell* c, int32_t id) {c->id_ = id;}
|
||||
|
||||
int cell_type(Cell* c) {return c->type;}
|
||||
int cell_type(Cell* c) {return c->type_;}
|
||||
|
||||
int32_t cell_universe(Cell* c) {return c->universe;}
|
||||
int32_t cell_universe(Cell* c) {return c->universe_;}
|
||||
|
||||
int32_t cell_fill(Cell* c) {return c->fill;}
|
||||
int32_t cell_fill(Cell* c) {return c->fill_;}
|
||||
|
||||
int32_t cell_n_instances(Cell* c) {return c->n_instances;}
|
||||
int32_t cell_n_instances(Cell* c) {return c->n_instances_;}
|
||||
|
||||
int cell_material_size(Cell* c) {return c->material.size();}
|
||||
int cell_distribcell_index(Cell* c) {return c->distribcell_index_;}
|
||||
|
||||
int cell_material_size(Cell* c) {return c->material_.size();}
|
||||
|
||||
//TODO: off-by-one
|
||||
int32_t cell_material(Cell* c, int i)
|
||||
{
|
||||
int32_t mat = c->material[i-1];
|
||||
int32_t mat = c->material_[i-1];
|
||||
if (mat == MATERIAL_VOID) return MATERIAL_VOID;
|
||||
return mat + 1;
|
||||
}
|
||||
|
||||
bool cell_simple(Cell* c) {return c->simple;}
|
||||
int cell_sqrtkT_size(Cell* c) {return c->sqrtkT_.size();}
|
||||
|
||||
bool cell_contains(Cell* c, double xyz[3], double uvw[3], int32_t on_surface)
|
||||
{
|
||||
Position r {xyz};
|
||||
Direction u {uvw};
|
||||
return c->contains(r, u, on_surface);
|
||||
}
|
||||
double cell_sqrtkT(Cell* c, int i) {return c->sqrtkT_[i];}
|
||||
|
||||
void cell_distance(Cell* c, double xyz[3], double uvw[3], int32_t on_surface,
|
||||
double* min_dist, int32_t* i_surf)
|
||||
{
|
||||
Position r {xyz};
|
||||
Direction u {uvw};
|
||||
std::pair<double, int32_t> out = c->distance(r, u, on_surface);
|
||||
*min_dist = out.first;
|
||||
*i_surf = out.second;
|
||||
}
|
||||
|
||||
int32_t cell_offset(Cell* c, int map) {return c->offset[map];}
|
||||
|
||||
void cell_to_hdf5(Cell* c, hid_t group) {c->to_hdf5(group);}
|
||||
int32_t cell_offset(Cell* c, int map) {return c->offset_[map];}
|
||||
|
||||
void extend_cells_c(int32_t n)
|
||||
{
|
||||
global_cells.reserve(global_cells.size() + n);
|
||||
cells.reserve(cells.size() + n);
|
||||
for (int32_t i = 0; i < n; i++) {
|
||||
global_cells.push_back(new Cell());
|
||||
cells.push_back(new Cell());
|
||||
}
|
||||
n_cells = global_cells.size();
|
||||
n_cells = cells.size();
|
||||
}
|
||||
|
||||
int32_t universe_id(int i_univ) {return universes[i_univ]->id_;}
|
||||
|
||||
void universes_to_hdf5(hid_t universes_group)
|
||||
{for (Universe* u : universes) u->to_hdf5(universes_group);}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,30 @@
|
|||
#include <cmath> // for sqrt, sin, cos, max
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/math_functions.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// UnitSphereDistribution implementation
|
||||
//==============================================================================
|
||||
|
||||
UnitSphereDistribution::UnitSphereDistribution(pugi::xml_node node)
|
||||
{
|
||||
// Read reference directional unit vector
|
||||
if (check_for_node(node, "reference_uvw")) {
|
||||
auto u_ref = get_node_array<double>(node, "reference_uvw");
|
||||
if (u_ref.size() != 3)
|
||||
fatal_error("Angular distribution reference direction must have "
|
||||
"three parameters specified.");
|
||||
u_ref_ = Direction(u_ref.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// PolarAzimuthal implementation
|
||||
//==============================================================================
|
||||
|
|
@ -16,15 +35,33 @@ namespace openmc {
|
|||
PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) :
|
||||
UnitSphereDistribution{u}, mu_{std::move(mu)}, phi_{std::move(phi)} { }
|
||||
|
||||
PolarAzimuthal::PolarAzimuthal(pugi::xml_node node)
|
||||
: UnitSphereDistribution{node}
|
||||
{
|
||||
if (check_for_node(node, "mu")) {
|
||||
pugi::xml_node node_dist = node.child("mu");
|
||||
mu_ = distribution_from_xml(node_dist);
|
||||
} else {
|
||||
mu_ = UPtrDist{new Uniform(-1., 1.)};
|
||||
}
|
||||
|
||||
if (check_for_node(node, "phi")) {
|
||||
pugi::xml_node node_dist = node.child("phi");
|
||||
phi_ = distribution_from_xml(node_dist);
|
||||
} else {
|
||||
phi_ = UPtrDist{new Uniform(0.0, 2.0*PI)};
|
||||
}
|
||||
}
|
||||
|
||||
Direction PolarAzimuthal::sample() const
|
||||
{
|
||||
// Sample cosine of polar angle
|
||||
double mu = mu_->sample();
|
||||
if (mu == 1.0) return u_ref;
|
||||
if (mu == 1.0) return u_ref_;
|
||||
|
||||
// Sample azimuthal angle
|
||||
double phi = phi_->sample();
|
||||
return rotate_angle(u_ref, mu, &phi);
|
||||
return rotate_angle(u_ref_, mu, &phi);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -45,7 +82,7 @@ Direction Isotropic::sample() const
|
|||
|
||||
Direction Monodirectional::sample() const
|
||||
{
|
||||
return u_ref;
|
||||
return u_ref_;
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -1,257 +0,0 @@
|
|||
module distribution_multivariate
|
||||
|
||||
use constants, only: ONE, TWO, PI
|
||||
use distribution_univariate
|
||||
use error, only: fatal_error
|
||||
use random_lcg, only: prn
|
||||
use math, only: rotate_angle
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
|
||||
!===============================================================================
|
||||
! UNITSPHEREDISTRIBUTION type defines a probability density function for points
|
||||
! on the unit sphere. Extensions of this type are used to sample angular
|
||||
! distributions for starting sources
|
||||
!===============================================================================
|
||||
|
||||
type, abstract :: UnitSphereDistribution
|
||||
real(8) :: reference_uvw(3)
|
||||
contains
|
||||
procedure(unitsphere_distribution_sample_), deferred :: sample
|
||||
end type UnitSphereDistribution
|
||||
|
||||
abstract interface
|
||||
function unitsphere_distribution_sample_(this) result(uvw)
|
||||
import UnitSphereDistribution
|
||||
class(UnitSphereDistribution), intent(in) :: this
|
||||
real(8) :: uvw(3)
|
||||
end function unitsphere_distribution_sample_
|
||||
end interface
|
||||
|
||||
!===============================================================================
|
||||
! Derived classes of UnitSphereDistribution
|
||||
!===============================================================================
|
||||
|
||||
! Explicit distribution of polar and azimuthal angles
|
||||
type, extends(UnitSphereDistribution) :: PolarAzimuthal
|
||||
class(Distribution), allocatable :: mu
|
||||
class(Distribution), allocatable :: phi
|
||||
contains
|
||||
procedure :: sample => polar_azimuthal_sample
|
||||
end type PolarAzimuthal
|
||||
|
||||
! Uniform distribution on the unit sphere
|
||||
type, extends(UnitSphereDistribution) :: Isotropic
|
||||
contains
|
||||
procedure :: sample => isotropic_sample
|
||||
end type Isotropic
|
||||
|
||||
! Monodirectional distribution
|
||||
type, extends(UnitSphereDistribution) :: Monodirectional
|
||||
contains
|
||||
procedure :: sample => monodirectional_sample
|
||||
end type Monodirectional
|
||||
|
||||
!===============================================================================
|
||||
! SPATIALDISTRIBUTION type defines a probability density function for arbitrary
|
||||
! points in Euclidean space.
|
||||
!===============================================================================
|
||||
|
||||
type, abstract :: SpatialDistribution
|
||||
contains
|
||||
procedure(spatial_distribution_from_xml_), deferred :: from_xml
|
||||
procedure(spatial_distribution_sample_), deferred :: sample
|
||||
end type SpatialDistribution
|
||||
|
||||
abstract interface
|
||||
subroutine spatial_distribution_from_xml_(this, node)
|
||||
import SpatialDistribution, XMLNode
|
||||
class(SpatialDistribution), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
end subroutine spatial_distribution_from_xml_
|
||||
|
||||
function spatial_distribution_sample_(this) result(xyz)
|
||||
import SpatialDistribution
|
||||
class(SpatialDistribution), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
end function spatial_distribution_sample_
|
||||
end interface
|
||||
|
||||
type, extends(SpatialDistribution) :: CartesianIndependent
|
||||
class(Distribution), allocatable :: x
|
||||
class(Distribution), allocatable :: y
|
||||
class(Distribution), allocatable :: z
|
||||
contains
|
||||
procedure :: from_xml => cartesian_independent_from_xml
|
||||
procedure :: sample => cartesian_independent_sample
|
||||
end type CartesianIndependent
|
||||
|
||||
type, extends(SpatialDistribution) :: SpatialBox
|
||||
real(8) :: lower_left(3)
|
||||
real(8) :: upper_right(3)
|
||||
logical :: only_fissionable = .false.
|
||||
contains
|
||||
procedure :: from_xml => spatial_box_from_xml
|
||||
procedure :: sample => spatial_box_sample
|
||||
end type SpatialBox
|
||||
|
||||
type, extends(SpatialDistribution) :: SpatialPoint
|
||||
real(8) :: xyz(3)
|
||||
contains
|
||||
procedure :: from_xml => spatial_point_from_xml
|
||||
procedure :: sample => spatial_point_sample
|
||||
end type SpatialPoint
|
||||
|
||||
contains
|
||||
|
||||
function polar_azimuthal_sample(this) result(uvw)
|
||||
class(PolarAzimuthal), intent(in) :: this
|
||||
real(8) :: uvw(3)
|
||||
|
||||
real(8) :: mu ! cosine of polar angle
|
||||
real(8) :: phi ! azimuthal angle
|
||||
|
||||
! Sample cosine of polar angle
|
||||
mu = this % mu % sample()
|
||||
if (mu == ONE) then
|
||||
uvw(:) = this % reference_uvw
|
||||
else
|
||||
! Sample azimuthal angle
|
||||
phi = this % phi % sample()
|
||||
uvw = rotate_angle(this % reference_uvw, mu, phi)
|
||||
end if
|
||||
end function polar_azimuthal_sample
|
||||
|
||||
function isotropic_sample(this) result(uvw)
|
||||
class(Isotropic), intent(in) :: this
|
||||
real(8) :: uvw(3)
|
||||
|
||||
real(8) :: phi
|
||||
real(8) :: mu
|
||||
|
||||
phi = TWO*PI*prn()
|
||||
mu = TWO*prn() - ONE
|
||||
uvw(1) = mu
|
||||
uvw(2) = sqrt(ONE - mu*mu) * cos(phi)
|
||||
uvw(3) = sqrt(ONE - mu*mu) * sin(phi)
|
||||
end function isotropic_sample
|
||||
|
||||
function monodirectional_sample(this) result(uvw)
|
||||
class(Monodirectional), intent(in) :: this
|
||||
real(8) :: uvw(3)
|
||||
|
||||
uvw(:) = this % reference_uvw
|
||||
end function monodirectional_sample
|
||||
|
||||
subroutine cartesian_independent_from_xml(this, node)
|
||||
class(CartesianIndependent), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
type(XMLNode) :: node_dist
|
||||
|
||||
! Read distribution for x coordinate
|
||||
if (check_for_node(node, "x")) then
|
||||
node_dist = node % child("x")
|
||||
call distribution_from_xml(this % x, node_dist)
|
||||
else
|
||||
allocate(Discrete :: this % x)
|
||||
select type (dist => this % x)
|
||||
type is (Discrete)
|
||||
allocate(dist % x(1), dist % p(1))
|
||||
dist % x(1) = ZERO
|
||||
dist % p(1) = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
! Read distribution for y coordinate
|
||||
if (check_for_node(node, "y")) then
|
||||
node_dist = node % child("y")
|
||||
call distribution_from_xml(this % y, node_dist)
|
||||
else
|
||||
allocate(Discrete :: this % y)
|
||||
select type (dist => this % y)
|
||||
type is (Discrete)
|
||||
allocate(dist % x(1), dist % p(1))
|
||||
dist % x(1) = ZERO
|
||||
dist % p(1) = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
if (check_for_node(node, "z")) then
|
||||
node_dist = node % child("z")
|
||||
call distribution_from_xml(this % z, node_dist)
|
||||
else
|
||||
allocate(Discrete :: this % z)
|
||||
select type (dist => this % z)
|
||||
type is (Discrete)
|
||||
allocate(dist % x(1), dist % p(1))
|
||||
dist % x(1) = ZERO
|
||||
dist % p(1) = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
end subroutine cartesian_independent_from_xml
|
||||
|
||||
function cartesian_independent_sample(this) result(xyz)
|
||||
class(CartesianIndependent), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
|
||||
xyz(1) = this % x % sample()
|
||||
xyz(2) = this % y % sample()
|
||||
xyz(3) = this % z % sample()
|
||||
end function cartesian_independent_sample
|
||||
|
||||
subroutine spatial_box_from_xml(this, node)
|
||||
class(SpatialBox), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
real(8), allocatable :: temp_real(:)
|
||||
|
||||
! Make sure correct number of parameters are given
|
||||
if (node_word_count(node, "parameters") /= 6) then
|
||||
call fatal_error('Box/fission spatial source must have &
|
||||
&six parameters specified.')
|
||||
end if
|
||||
|
||||
! Read lower-right/upper-left coordinates
|
||||
allocate(temp_real(6))
|
||||
call get_node_array(node, "parameters", temp_real)
|
||||
this % lower_left(:) = temp_real(1:3)
|
||||
this % upper_right(:) = temp_real(4:6)
|
||||
deallocate(temp_real)
|
||||
end subroutine spatial_box_from_xml
|
||||
|
||||
function spatial_box_sample(this) result(xyz)
|
||||
class(SpatialBox), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
|
||||
integer :: i
|
||||
real(8) :: r(3)
|
||||
|
||||
r = [ (prn(), i = 1,3) ]
|
||||
xyz(:) = this % lower_left + r*(this % upper_right - this % lower_left)
|
||||
end function spatial_box_sample
|
||||
|
||||
subroutine spatial_point_from_xml(this, node)
|
||||
class(SpatialPoint), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
! Make sure correct number of parameters are given
|
||||
if (node_word_count(node, "parameters") /= 3) then
|
||||
call fatal_error('Point spatial source must have &
|
||||
&three parameters specified.')
|
||||
end if
|
||||
|
||||
! Read location of point source
|
||||
call get_node_array(node, "parameters", this % xyz)
|
||||
end subroutine spatial_point_from_xml
|
||||
|
||||
function spatial_point_sample(this) result(xyz)
|
||||
class(SpatialPoint), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
|
||||
xyz(:) = this % xyz
|
||||
end function spatial_point_sample
|
||||
|
||||
end module distribution_multivariate
|
||||
|
|
@ -55,7 +55,8 @@ Position CartesianIndependent::sample() const
|
|||
// SpatialBox implementation
|
||||
//==============================================================================
|
||||
|
||||
SpatialBox::SpatialBox(pugi::xml_node node)
|
||||
SpatialBox::SpatialBox(pugi::xml_node node, bool fission)
|
||||
: only_fissionable_{fission}
|
||||
{
|
||||
// Read lower-right/upper-left coordinates
|
||||
auto params = get_node_array<double>(node, "parameters");
|
||||
|
|
|
|||
|
|
@ -1,373 +0,0 @@
|
|||
module distribution_univariate
|
||||
|
||||
use constants, only: ZERO, ONE, HALF, HISTOGRAM, LINEAR_LINEAR, &
|
||||
MAX_LINE_LEN, MAX_WORD_LEN
|
||||
use error, only: fatal_error
|
||||
use random_lcg, only: prn
|
||||
use math, only: maxwell_spectrum, watt_spectrum
|
||||
use pugixml
|
||||
use string, only: to_lower
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
|
||||
!===============================================================================
|
||||
! DISTRIBUTION type defines a probability density function
|
||||
!===============================================================================
|
||||
|
||||
type, abstract :: Distribution
|
||||
contains
|
||||
procedure(distribution_sample_), deferred :: sample
|
||||
end type Distribution
|
||||
|
||||
type DistributionContainer
|
||||
class(Distribution), allocatable :: obj
|
||||
end type DistributionContainer
|
||||
|
||||
abstract interface
|
||||
function distribution_sample_(this) result(x)
|
||||
import Distribution
|
||||
class(Distribution), intent(in) :: this
|
||||
real(8) :: x
|
||||
end function distribution_sample_
|
||||
end interface
|
||||
|
||||
!===============================================================================
|
||||
! Derived classes of Distribution
|
||||
!===============================================================================
|
||||
|
||||
! Discrete distribution
|
||||
type, extends(Distribution) :: Discrete
|
||||
real(8), allocatable :: x(:)
|
||||
real(8), allocatable :: p(:)
|
||||
contains
|
||||
procedure :: sample => discrete_sample
|
||||
procedure :: initialize => discrete_initialize
|
||||
end type Discrete
|
||||
|
||||
! Uniform distribution over the interval [a,b]
|
||||
type, extends(Distribution) :: Uniform
|
||||
real(8) :: a
|
||||
real(8) :: b
|
||||
contains
|
||||
procedure :: sample => uniform_sample
|
||||
end type Uniform
|
||||
|
||||
! Maxwellian distribution of form c*E*exp(-E/a)
|
||||
type, extends(Distribution) :: Maxwell
|
||||
real(8) :: theta
|
||||
contains
|
||||
procedure :: sample => maxwell_sample
|
||||
end type Maxwell
|
||||
|
||||
! Watt fission spectrum with form c*exp(-E/a)*sinh(sqrt(b*E))
|
||||
type, extends(Distribution) :: Watt
|
||||
real(8) :: a
|
||||
real(8) :: b
|
||||
contains
|
||||
procedure :: sample => watt_sample
|
||||
end type Watt
|
||||
|
||||
! Histogram or linear-linear interpolated tabular distribution
|
||||
type, extends(Distribution) :: Tabular
|
||||
integer :: interpolation
|
||||
real(8), allocatable :: x(:) ! tabulated independent variable
|
||||
real(8), allocatable :: p(:) ! tabulated probability density
|
||||
real(8), allocatable :: c(:) ! cumulative distribution at tabulated values
|
||||
contains
|
||||
procedure :: sample => tabular_sample
|
||||
procedure :: initialize => tabular_initialize
|
||||
end type Tabular
|
||||
|
||||
type, extends(Distribution) :: Equiprobable
|
||||
real(8), allocatable :: x(:)
|
||||
contains
|
||||
procedure :: sample => equiprobable_sample
|
||||
end type Equiprobable
|
||||
|
||||
contains
|
||||
|
||||
function discrete_sample(this) result(x)
|
||||
class(Discrete), intent(in) :: this
|
||||
real(8) :: x
|
||||
|
||||
integer :: i ! loop counter
|
||||
integer :: n ! size of distribution
|
||||
real(8) :: c ! cumulative frequency
|
||||
real(8) :: xi ! sampled CDF value
|
||||
|
||||
n = size(this%x)
|
||||
if (n > 1) then
|
||||
xi = prn()
|
||||
c = ZERO
|
||||
do i = 1, size(this%x)
|
||||
c = c + this%p(i)
|
||||
if (xi < c) exit
|
||||
end do
|
||||
x = this%x(i)
|
||||
else
|
||||
x = this%x(1)
|
||||
end if
|
||||
end function discrete_sample
|
||||
|
||||
subroutine discrete_initialize(this, x, p)
|
||||
class(Discrete), intent(inout) :: this
|
||||
real(8), intent(in) :: x(:)
|
||||
real(8), intent(in) :: p(:)
|
||||
|
||||
integer :: n
|
||||
|
||||
! Check length of x, p arrays
|
||||
if (size(x) /= size(p)) then
|
||||
call fatal_error('Tabulated probabilities not of same length as &
|
||||
&independent variable.')
|
||||
end if
|
||||
|
||||
! Copy probability density function
|
||||
n = size(x)
|
||||
allocate(this%x(n), this%p(n))
|
||||
this%x(:) = x(:)
|
||||
this%p(:) = p(:)
|
||||
|
||||
! Normalize density function
|
||||
this%p(:) = this%p(:)/sum(this%p)
|
||||
end subroutine
|
||||
|
||||
function uniform_sample(this) result(x)
|
||||
class(Uniform), intent(in) :: this
|
||||
real(8) :: x
|
||||
|
||||
x = this%a + prn()*(this%b - this%a)
|
||||
end function uniform_sample
|
||||
|
||||
function maxwell_sample(this) result(x)
|
||||
class(Maxwell), intent(in) :: this
|
||||
real(8) :: x
|
||||
|
||||
x = maxwell_spectrum(this%theta)
|
||||
end function maxwell_sample
|
||||
|
||||
function watt_sample(this) result(x)
|
||||
class(Watt), intent(in) :: this
|
||||
real(8) :: x
|
||||
|
||||
x = watt_spectrum(this%a, this%b)
|
||||
end function watt_sample
|
||||
|
||||
function tabular_sample(this) result(x)
|
||||
class(Tabular), intent(in) :: this
|
||||
real(8) :: x
|
||||
|
||||
integer :: i
|
||||
real(8) :: c ! sampled cumulative frequency
|
||||
real(8) :: m ! slope of PDF
|
||||
real(8) :: x_i, x_i1 ! i-th and (i+1)th x values
|
||||
real(8) :: c_i, c_i1 ! i-th and (i+1)th cumulative distribution values
|
||||
real(8) :: p_i, p_i1 ! i-th and (i+1)th probability density values
|
||||
|
||||
! Sample value of CDF
|
||||
c = prn()
|
||||
|
||||
! Find first CDF bin which is above the sampled value
|
||||
c_i = this%c(1)
|
||||
do i = 1, size(this%c) - 1
|
||||
c_i1 = this%c(i + 1)
|
||||
if (c <= c_i1) exit
|
||||
c_i = c_i1
|
||||
end do
|
||||
|
||||
! Determine bounding PDF values
|
||||
x_i = this%x(i)
|
||||
p_i = this%p(i)
|
||||
|
||||
if (this%interpolation == HISTOGRAM) then
|
||||
! Histogram interpolation
|
||||
if (p_i > ZERO) then
|
||||
x = x_i + (c - c_i)/p_i
|
||||
else
|
||||
x = x_i
|
||||
end if
|
||||
else
|
||||
! Linear-linear interpolation
|
||||
x_i1 = this%x(i + 1)
|
||||
p_i1 = this%p(i + 1)
|
||||
|
||||
m = (p_i1 - p_i)/(x_i1 - x_i)
|
||||
if (m == ZERO) then
|
||||
x = x_i + (c - c_i)/p_i
|
||||
else
|
||||
x = x_i + (sqrt(max(ZERO, p_i*p_i + 2*m*(c - c_i))) - p_i)/m
|
||||
end if
|
||||
end if
|
||||
end function tabular_sample
|
||||
|
||||
subroutine tabular_initialize(this, x, p, interp)
|
||||
class(Tabular), intent(inout) :: this
|
||||
real(8), intent(in) :: x(:)
|
||||
real(8), intent(in) :: p(:)
|
||||
integer, intent(in) :: interp
|
||||
|
||||
integer :: i
|
||||
integer :: n
|
||||
|
||||
! Check interpolation parameter
|
||||
if (interp /= HISTOGRAM .and. interp /= LINEAR_LINEAR) then
|
||||
call fatal_error('Only histogram and linear-linear interpolation for tabular &
|
||||
&distribution is supported.')
|
||||
end if
|
||||
|
||||
! Check length of x, p arrays
|
||||
if (size(x) /= size(p)) then
|
||||
call fatal_error('Tabulated probabilities not of same length as &
|
||||
&independent variable.')
|
||||
end if
|
||||
|
||||
! Copy probability density function and interpolation parameter
|
||||
n = size(x)
|
||||
allocate(this%x(n), this%p(n), this%c(n))
|
||||
this%interpolation = interp
|
||||
this%x(:) = x(:)
|
||||
this%p(:) = p(:)
|
||||
|
||||
! Calculate cumulative distribution function
|
||||
this%c(1) = ZERO
|
||||
do i = 2, n
|
||||
if (this%interpolation == HISTOGRAM) then
|
||||
this%c(i) = this%c(i-1) + this%p(i-1)*(this%x(i) - this%x(i-1))
|
||||
elseif (this%interpolation == LINEAR_LINEAR) then
|
||||
this%c(i) = this%c(i-1) + HALF*(this%p(i-1) + this%p(i)) * &
|
||||
(this%x(i) - this%x(i-1))
|
||||
end if
|
||||
end do
|
||||
|
||||
! Normalize density and distribution functions
|
||||
this%p(:) = this%p(:)/this%c(n)
|
||||
this%c(:) = this%c(:)/this%c(n)
|
||||
end subroutine tabular_initialize
|
||||
|
||||
function equiprobable_sample(this) result(x)
|
||||
class(Equiprobable), intent(in) :: this
|
||||
real(8) :: x
|
||||
|
||||
integer :: i
|
||||
integer :: n
|
||||
real(8) :: r
|
||||
real(8) :: xl, xr
|
||||
|
||||
n = size(this%x)
|
||||
|
||||
r = prn()
|
||||
i = 1 + int((n - 1)*r)
|
||||
|
||||
xl = this%x(i)
|
||||
xr = this%x(i+1)
|
||||
x = xl + ((n - 1)*r - i + ONE) * (xr - xl)
|
||||
end function equiprobable_sample
|
||||
|
||||
subroutine distribution_from_xml(dist, node_dist)
|
||||
class(Distribution), allocatable, intent(inout) :: dist
|
||||
type(XMLNode), intent(in) :: node_dist
|
||||
|
||||
character(MAX_WORD_LEN) :: type
|
||||
character(MAX_LINE_LEN) :: temp_str
|
||||
integer :: n
|
||||
integer :: temp_int
|
||||
real(8), allocatable :: temp_real(:)
|
||||
|
||||
if (check_for_node(node_dist, "type")) then
|
||||
! Determine type of distribution
|
||||
call get_node_value(node_dist, "type", type)
|
||||
|
||||
! Determine number of parameters specified
|
||||
if (check_for_node(node_dist, "parameters")) then
|
||||
n = node_word_count(node_dist, "parameters")
|
||||
else
|
||||
n = 0
|
||||
end if
|
||||
|
||||
! Allocate extension of Distribution
|
||||
select case (to_lower(type))
|
||||
case ('uniform')
|
||||
allocate(Uniform :: dist)
|
||||
if (n /= 2) then
|
||||
call fatal_error('Uniform distribution must have two &
|
||||
¶meters specified.')
|
||||
end if
|
||||
|
||||
case ('maxwell')
|
||||
allocate(Maxwell :: dist)
|
||||
if (n /= 1) then
|
||||
call fatal_error('Maxwell energy distribution must have one &
|
||||
¶meter specified.')
|
||||
end if
|
||||
|
||||
case ('watt')
|
||||
allocate(Watt :: dist)
|
||||
if (n /= 2) then
|
||||
call fatal_error('Watt energy distribution must have two &
|
||||
¶meters specified.')
|
||||
end if
|
||||
|
||||
case ('discrete')
|
||||
allocate(Discrete :: dist)
|
||||
|
||||
case ('tabular')
|
||||
allocate(Tabular :: dist)
|
||||
|
||||
case default
|
||||
call fatal_error('Invalid distribution type: ' // trim(type) // '.')
|
||||
|
||||
end select
|
||||
|
||||
! Read parameters and interpolation for distribution
|
||||
select type (dist)
|
||||
type is (Uniform)
|
||||
allocate(temp_real(2))
|
||||
call get_node_array(node_dist, "parameters", temp_real)
|
||||
dist%a = temp_real(1)
|
||||
dist%b = temp_real(2)
|
||||
deallocate(temp_real)
|
||||
|
||||
type is (Maxwell)
|
||||
call get_node_value(node_dist, "parameters", dist%theta)
|
||||
|
||||
type is (Watt)
|
||||
allocate(temp_real(2))
|
||||
call get_node_array(node_dist, "parameters", temp_real)
|
||||
dist%a = temp_real(1)
|
||||
dist%b = temp_real(2)
|
||||
deallocate(temp_real)
|
||||
|
||||
type is (Discrete)
|
||||
allocate(temp_real(n))
|
||||
call get_node_array(node_dist, "parameters", temp_real)
|
||||
call dist%initialize(temp_real(1:n/2), temp_real(n/2+1:n))
|
||||
deallocate(temp_real)
|
||||
|
||||
type is (Tabular)
|
||||
! Read interpolation
|
||||
if (check_for_node(node_dist, "interpolation")) then
|
||||
call get_node_value(node_dist, "interpolation", temp_str)
|
||||
select case(to_lower(temp_str))
|
||||
case ('histogram')
|
||||
temp_int = HISTOGRAM
|
||||
case ('linear-linear')
|
||||
temp_int = LINEAR_LINEAR
|
||||
case default
|
||||
call fatal_error("Unknown interpolation type for distribution: " &
|
||||
// trim(temp_str))
|
||||
end select
|
||||
else
|
||||
temp_int = HISTOGRAM
|
||||
end if
|
||||
|
||||
! Read and initialize tabular distribution
|
||||
allocate(temp_real(n))
|
||||
call get_node_array(node_dist, "parameters", temp_real)
|
||||
call dist%initialize(temp_real(1:n/2), temp_real(n/2+1:n), temp_int)
|
||||
deallocate(temp_real)
|
||||
end select
|
||||
end if
|
||||
end subroutine distribution_from_xml
|
||||
|
||||
end module distribution_univariate
|
||||
|
|
@ -270,8 +270,9 @@ contains
|
|||
character(kind=C_CHAR), intent(in) :: message(message_len)
|
||||
integer(C_INT), intent(in), value :: level
|
||||
character(message_len+1) :: message_out
|
||||
! Using * in the internal write adds an extra space at the beginning
|
||||
write(message_out, *) message
|
||||
call write_message(message_out, level)
|
||||
call write_message(message_out(2:), level)
|
||||
end subroutine write_message_from_c
|
||||
|
||||
end module error
|
||||
|
|
|
|||
544
src/geometry.F90
544
src/geometry.F90
|
|
@ -15,529 +15,67 @@ module geometry
|
|||
implicit none
|
||||
|
||||
interface
|
||||
function cell_contains_c(cell_ptr, xyz, uvw, on_surface) &
|
||||
bind(C, name="cell_contains") result(in_cell)
|
||||
import C_PTR, C_DOUBLE, C_INT32_T, C_BOOL
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
real(C_DOUBLE), intent(in) :: uvw(3)
|
||||
integer(C_INT32_T), intent(in), value :: on_surface
|
||||
logical(C_BOOL) :: in_cell
|
||||
end function cell_contains_c
|
||||
|
||||
function count_universe_instances(search_univ, target_univ_id) bind(C) &
|
||||
result(count)
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT32_T), intent(in), value :: search_univ
|
||||
integer(C_INT32_T), intent(in), value :: target_univ_id
|
||||
integer(C_INT) :: count
|
||||
end function
|
||||
end function count_universe_instances
|
||||
|
||||
subroutine check_cell_overlap(p) bind(C)
|
||||
import Particle
|
||||
type(Particle), intent(in) :: p
|
||||
end subroutine check_cell_overlap
|
||||
|
||||
function find_cell_c(p, search_surf) &
|
||||
bind(C, name="find_cell") result(found)
|
||||
import Particle, C_INT, C_BOOL
|
||||
type(Particle), intent(inout) :: p
|
||||
integer(C_INT), intent(in), value :: search_surf
|
||||
logical(C_BOOL) :: found
|
||||
end function find_cell_c
|
||||
|
||||
subroutine cross_lattice(p, lattice_translation) &
|
||||
bind(C, name="cross_lattice")
|
||||
import Particle, C_INT
|
||||
type(Particle), intent(inout) :: p
|
||||
integer(C_INT), intent(in) :: lattice_translation(3)
|
||||
end subroutine cross_lattice
|
||||
|
||||
subroutine distance_to_boundary(p, dist, surface_crossed, &
|
||||
lattice_translation, next_level) bind(C)
|
||||
import Particle, C_DOUBLE, C_INT
|
||||
type(Particle), intent(inout) :: p
|
||||
real(C_DOUBLE), intent(out) :: dist
|
||||
integer(C_INT), intent(out) :: surface_crossed
|
||||
integer(C_INT), intent(out) :: lattice_translation(3)
|
||||
integer(C_INT), intent(out) :: next_level
|
||||
end subroutine distance_to_boundary
|
||||
|
||||
subroutine neighbor_lists() bind(C)
|
||||
end subroutine neighbor_lists
|
||||
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
|
||||
|
||||
!===============================================================================
|
||||
! CHECK_CELL_OVERLAP checks for overlapping cells at the current particle's
|
||||
! position using cell_contains and the LocalCoord's built up by find_cell
|
||||
!===============================================================================
|
||||
|
||||
subroutine check_cell_overlap(p)
|
||||
|
||||
type(Particle), intent(inout) :: p
|
||||
|
||||
integer :: i ! cell loop index on a level
|
||||
integer :: j ! coordinate level index
|
||||
integer :: n_coord ! saved number of coordinate levels
|
||||
integer :: n ! number of cells to search on a level
|
||||
integer :: index_cell ! index in cells array
|
||||
type(Cell), pointer :: c ! pointer to cell
|
||||
type(Universe), pointer :: univ ! universe to search in
|
||||
|
||||
! loop through each coordinate level
|
||||
n_coord = p % n_coord
|
||||
do j = 1, n_coord
|
||||
p % n_coord = j
|
||||
univ => universes(p % coord(j) % universe)
|
||||
n = size(univ % cells)
|
||||
|
||||
! loop through each cell on this level
|
||||
do i = 1, n
|
||||
index_cell = univ % cells(i)
|
||||
c => cells(index_cell)
|
||||
|
||||
if (cell_contains(c, p)) then
|
||||
! the particle should only be contained in one cell per level
|
||||
if (index_cell /= p % coord(j) % cell) then
|
||||
call fatal_error("Overlapping cells detected: " &
|
||||
&// trim(to_str(cells(index_cell) % id())) // ", " &
|
||||
&// trim(to_str(cells(p % coord(j) % cell) % id())) &
|
||||
&// " on universe " // trim(to_str(univ % id)))
|
||||
end if
|
||||
|
||||
overlap_check_cnt(index_cell) = overlap_check_cnt(index_cell) + 1
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
end do
|
||||
|
||||
end subroutine check_cell_overlap
|
||||
|
||||
!===============================================================================
|
||||
! 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
|
||||
! as it's within the geometry
|
||||
!===============================================================================
|
||||
|
||||
recursive subroutine find_cell(p, found, search_cells)
|
||||
subroutine find_cell(p, found, search_surf)
|
||||
type(Particle), intent(inout) :: p
|
||||
logical, intent(inout) :: found
|
||||
integer, optional, intent(in) :: search_surf
|
||||
|
||||
type(Particle), intent(inout) :: p
|
||||
logical, intent(inout) :: found
|
||||
integer, optional :: search_cells(:)
|
||||
integer :: i ! index over cells
|
||||
integer :: j, k ! coordinate level index
|
||||
integer :: offset ! instance # of a distributed cell
|
||||
integer :: distribcell_index
|
||||
integer :: i_xyz(3) ! indices in lattice
|
||||
integer :: n ! number of cells to search
|
||||
integer :: i_cell ! index in cells array
|
||||
integer :: i_universe ! index in universes array
|
||||
logical :: use_search_cells ! use cells provided as argument
|
||||
|
||||
do j = p % n_coord + 1, MAX_COORD
|
||||
call reset_coord(p % coord(j))
|
||||
end do
|
||||
j = p % n_coord
|
||||
|
||||
! Determine universe (if not yet set, use root universe)
|
||||
i_universe = p % coord(j) % universe
|
||||
if (i_universe == C_NONE) then
|
||||
p % coord(j) % universe = root_universe
|
||||
i_universe = root_universe
|
||||
end if
|
||||
|
||||
! set size of list to search
|
||||
if (present(search_cells)) then
|
||||
use_search_cells = .true.
|
||||
n = size(search_cells)
|
||||
if (present(search_surf)) then
|
||||
found = find_cell_c(p, search_surf)
|
||||
else
|
||||
use_search_cells = .false.
|
||||
n = size(universes(i_universe) % cells)
|
||||
end if
|
||||
|
||||
found = .false.
|
||||
CELL_LOOP: do i = 1, n
|
||||
! select cells based on whether we are searching a universe or a provided
|
||||
! list of cells (this would be for lists of neighbor cells)
|
||||
if (use_search_cells) then
|
||||
i_cell = search_cells(i)
|
||||
! check to make sure search cell is in same universe
|
||||
if (cells(i_cell) % universe() /= i_universe) cycle
|
||||
else
|
||||
i_cell = universes(i_universe) % cells(i)
|
||||
end if
|
||||
|
||||
! Move on to the next cell if the particle is not inside this cell
|
||||
if (cell_contains(cells(i_cell), p)) then
|
||||
! Set cell on this level
|
||||
p % coord(j) % cell = i_cell
|
||||
|
||||
! 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
|
||||
|
||||
found = .true.
|
||||
exit
|
||||
end if
|
||||
end do CELL_LOOP
|
||||
|
||||
if (found) then
|
||||
associate(c => cells(i_cell))
|
||||
CELL_TYPE: if (c % type() == FILL_MATERIAL) then
|
||||
! ======================================================================
|
||||
! AT LOWEST UNIVERSE, TERMINATE SEARCH
|
||||
|
||||
! Save previous material and temperature
|
||||
p % last_material = p % material
|
||||
p % last_sqrtkT = p % sqrtkT
|
||||
|
||||
! Get distributed offset
|
||||
if (c % material_size() > 1 .or. size(c % sqrtkT) > 1) then
|
||||
! Distributed instances of this cell have different
|
||||
! materials/temperatures. Determine which instance this is for
|
||||
! assigning the matching material/temperature.
|
||||
distribcell_index = c % distribcell_index
|
||||
offset = 0
|
||||
do k = 1, p % n_coord
|
||||
if (cells(p % coord(k) % cell) % type() == FILL_UNIVERSE) then
|
||||
offset = offset + cells(p % coord(k) % cell) &
|
||||
% offset(distribcell_index-1)
|
||||
elseif (cells(p % coord(k) % cell) % type() == FILL_LATTICE) then
|
||||
if (lattices(p % coord(k + 1) % lattice) % obj &
|
||||
% are_valid_indices([&
|
||||
p % coord(k + 1) % lattice_x, &
|
||||
p % coord(k + 1) % lattice_y, &
|
||||
p % coord(k + 1) % lattice_z])) then
|
||||
offset = offset + lattices(p % coord(k + 1) % lattice) % obj &
|
||||
% offset(distribcell_index - 1, &
|
||||
[p % coord(k + 1) % lattice_x, &
|
||||
p % coord(k + 1) % lattice_y, &
|
||||
p % coord(k + 1) % lattice_z])
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
|
||||
! Keep track of which instance of the cell the particle is in
|
||||
p % cell_instance = offset + 1
|
||||
else
|
||||
p % cell_instance = 1
|
||||
end if
|
||||
|
||||
! Save the material
|
||||
if (c % material_size() > 1) then
|
||||
p % material = c % material(offset + 1)
|
||||
else
|
||||
p % material = c % material(1)
|
||||
end if
|
||||
|
||||
! Save the temperature
|
||||
if (size(c % sqrtkT) > 1) then
|
||||
p % sqrtkT = c % sqrtkT(offset + 1)
|
||||
else
|
||||
p % sqrtkT = c % sqrtkT(1)
|
||||
end if
|
||||
|
||||
elseif (c % type() == FILL_UNIVERSE) then CELL_TYPE
|
||||
! ======================================================================
|
||||
! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL
|
||||
|
||||
! Store lower level coordinates
|
||||
p % coord(j + 1) % xyz = p % coord(j) % xyz
|
||||
p % coord(j + 1) % uvw = p % coord(j) % uvw
|
||||
|
||||
! Move particle to next level and set universe
|
||||
j = j + 1
|
||||
p % n_coord = j
|
||||
p % coord(j) % universe = c % fill() + 1
|
||||
|
||||
! Apply translation
|
||||
if (allocated(c % translation)) then
|
||||
p % coord(j) % xyz = p % coord(j) % xyz - c % translation
|
||||
end if
|
||||
|
||||
! Apply rotation
|
||||
if (allocated(c % rotation_matrix)) then
|
||||
p % coord(j) % xyz = matmul(c % rotation_matrix, p % coord(j) % xyz)
|
||||
p % coord(j) % uvw = matmul(c % rotation_matrix, p % coord(j) % uvw)
|
||||
p % coord(j) % rotated = .true.
|
||||
end if
|
||||
|
||||
call find_cell(p, found)
|
||||
j = p % n_coord
|
||||
|
||||
elseif (c % type() == FILL_LATTICE) then CELL_TYPE
|
||||
! ======================================================================
|
||||
! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL
|
||||
|
||||
associate (lat => lattices(c % fill() + 1) % obj)
|
||||
! Determine lattice indices
|
||||
i_xyz = lat % get_indices(p % coord(j) % xyz + TINY_BIT * p % coord(j) % uvw)
|
||||
|
||||
! Store lower level coordinates
|
||||
p % coord(j + 1) % xyz = lat % get_local_xyz(p % coord(j) % xyz, i_xyz)
|
||||
p % coord(j + 1) % uvw = p % coord(j) % uvw
|
||||
|
||||
! set particle lattice indices
|
||||
p % coord(j + 1) % lattice = c % fill() + 1
|
||||
p % coord(j + 1) % lattice_x = i_xyz(1)
|
||||
p % coord(j + 1) % lattice_y = i_xyz(2)
|
||||
p % coord(j + 1) % lattice_z = i_xyz(3)
|
||||
|
||||
! Set the next lowest coordinate level.
|
||||
if (lat % are_valid_indices(i_xyz)) then
|
||||
! Particle is inside the lattice.
|
||||
p % coord(j + 1) % universe = &
|
||||
lat % get([i_xyz(1), i_xyz(2), i_xyz(3)]) + 1
|
||||
|
||||
else
|
||||
! Particle is outside the lattice.
|
||||
if (lat % outer() == NO_OUTER_UNIVERSE) then
|
||||
call warning("Particle " // trim(to_str(p %id)) &
|
||||
// " is outside lattice " // trim(to_str(lat % id())) &
|
||||
// " but the lattice has no defined outer universe.")
|
||||
found = .false.
|
||||
return
|
||||
else
|
||||
p % coord(j + 1) % universe = lat % outer() + 1
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
|
||||
! Move particle to next level and search for the lower cells.
|
||||
j = j + 1
|
||||
p % n_coord = j
|
||||
|
||||
call find_cell(p, found)
|
||||
j = p % n_coord
|
||||
|
||||
end if CELL_TYPE
|
||||
end associate
|
||||
found = find_cell_c(p, 0)
|
||||
end if
|
||||
|
||||
end subroutine find_cell
|
||||
|
||||
!===============================================================================
|
||||
! CROSS_LATTICE moves a particle into a new lattice element
|
||||
!===============================================================================
|
||||
|
||||
subroutine cross_lattice(p, lattice_translation)
|
||||
|
||||
type(Particle), intent(inout) :: p
|
||||
integer, intent(in) :: lattice_translation(3)
|
||||
integer :: j
|
||||
integer :: i_xyz(3) ! indices in lattice
|
||||
logical :: found ! particle found in cell?
|
||||
class(Lattice), pointer :: lat
|
||||
|
||||
j = p % n_coord
|
||||
lat => lattices(p % coord(j) % lattice) % obj
|
||||
|
||||
if (verbosity >= 10 .or. trace) then
|
||||
call write_message(" Crossing lattice " // trim(to_str(lat % id())) &
|
||||
&// ". Current position (" // trim(to_str(p % coord(j) % lattice_x)) &
|
||||
&// "," // trim(to_str(p % coord(j) % lattice_y)) // "," &
|
||||
&// trim(to_str(p % coord(j) % lattice_z)) // ")")
|
||||
end if
|
||||
|
||||
! Set the lattice indices.
|
||||
p % coord(j) % lattice_x = p % coord(j) % lattice_x + lattice_translation(1)
|
||||
p % coord(j) % lattice_y = p % coord(j) % lattice_y + lattice_translation(2)
|
||||
p % coord(j) % lattice_z = p % coord(j) % lattice_z + lattice_translation(3)
|
||||
i_xyz(1) = p % coord(j) % lattice_x
|
||||
i_xyz(2) = p % coord(j) % lattice_y
|
||||
i_xyz(3) = p % coord(j) % lattice_z
|
||||
|
||||
! Set the new coordinate position.
|
||||
p % coord(j) % xyz = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz)
|
||||
|
||||
OUTSIDE_LAT: if (.not. lat % are_valid_indices(i_xyz)) then
|
||||
! The particle is outside the lattice. Search for it from base coord
|
||||
p % n_coord = 1
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
if (p % alive) then ! Particle may have been killed in find_cell
|
||||
call particle_mark_as_lost(p, "Could not locate particle " &
|
||||
// trim(to_str(p % id)) // " after crossing a lattice boundary.")
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
else OUTSIDE_LAT
|
||||
|
||||
! Find cell in next lattice element
|
||||
p % coord(j) % universe = &
|
||||
lat % get([i_xyz(1), i_xyz(2), i_xyz(3)]) + 1
|
||||
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
! In some circumstances, a particle crossing the corner of a cell may
|
||||
! not be able to be found in the next universe. In this scenario we cut
|
||||
! off all lower-level coordinates and search from universe zero
|
||||
|
||||
! Remove lower coordinates
|
||||
p % n_coord = 1
|
||||
|
||||
! Search for particle
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
call particle_mark_as_lost(p, "Could not locate particle " // &
|
||||
trim(to_str(p % id)) // " after crossing a lattice boundary.")
|
||||
return
|
||||
end if
|
||||
end if
|
||||
end if OUTSIDE_LAT
|
||||
|
||||
end subroutine cross_lattice
|
||||
|
||||
!===============================================================================
|
||||
! DISTANCE_TO_BOUNDARY calculates the distance to the nearest boundary for a
|
||||
! particle 'p' traveling in a certain direction. For a cell in a subuniverse
|
||||
! that has a parent cell, also include the surfaces of the edge of the universe.
|
||||
!===============================================================================
|
||||
|
||||
subroutine distance_to_boundary(p, dist, surface_crossed, lattice_translation, &
|
||||
next_level)
|
||||
type(Particle), intent(inout) :: p
|
||||
real(8), intent(out) :: dist
|
||||
integer, intent(out) :: surface_crossed
|
||||
integer, intent(out) :: lattice_translation(3)
|
||||
integer, intent(out) :: next_level
|
||||
|
||||
integer :: j
|
||||
integer :: i_xyz(3) ! lattice indices
|
||||
integer :: level_surf_cross ! surface crossed on current level
|
||||
integer :: level_lat_trans(3) ! lattice translation on current level
|
||||
real(8) :: xyz_t(3) ! local particle coordinates
|
||||
real(8) :: d_lat ! distance to lattice boundary
|
||||
real(8) :: d_surf ! distance to surface
|
||||
real(8) :: xyz_cross(3) ! coordinates at projected surface crossing
|
||||
real(8) :: surf_uvw(3) ! surface normal direction
|
||||
type(Cell), pointer :: c
|
||||
class(Lattice), pointer :: lat
|
||||
|
||||
! inialize distance to infinity (huge)
|
||||
dist = INFINITY
|
||||
d_lat = INFINITY
|
||||
d_surf = INFINITY
|
||||
lattice_translation(:) = [0, 0, 0]
|
||||
|
||||
next_level = 0
|
||||
|
||||
! Loop over each universe level
|
||||
LEVEL_LOOP: do j = 1, p % n_coord
|
||||
|
||||
! get pointer to cell on this level
|
||||
c => cells(p % coord(j) % cell)
|
||||
|
||||
! =======================================================================
|
||||
! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL
|
||||
|
||||
call c % distance(p % coord(j) % xyz, p % coord(j) % uvw, p % surface, &
|
||||
d_surf, level_surf_cross)
|
||||
|
||||
! =======================================================================
|
||||
! FIND MINIMUM DISTANCE TO LATTICE SURFACES
|
||||
|
||||
LAT_COORD: if (p % coord(j) % lattice /= NONE) then
|
||||
lat => lattices(p % coord(j) % lattice) % obj
|
||||
|
||||
i_xyz(1) = p % coord(j) % lattice_x
|
||||
i_xyz(2) = p % coord(j) % lattice_y
|
||||
i_xyz(3) = p % coord(j) % lattice_z
|
||||
|
||||
LAT_TYPE: select type(lat)
|
||||
|
||||
type is (RectLattice)
|
||||
call lat % distance(p % coord(j) % xyz, p % coord(j) % uvw, &
|
||||
i_xyz, d_lat, level_lat_trans)
|
||||
|
||||
type is (HexLattice) LAT_TYPE
|
||||
xyz_t(1) = p % coord(j-1) % xyz(1)
|
||||
xyz_t(2) = p % coord(j-1) % xyz(2)
|
||||
xyz_t(3) = p % coord(j) % xyz(3)
|
||||
call lat % distance(xyz_t, p % coord(j) % uvw, &
|
||||
i_xyz, d_lat, level_lat_trans)
|
||||
end select LAT_TYPE
|
||||
|
||||
if (d_lat < ZERO) then
|
||||
call particle_mark_as_lost(p, "Particle " // trim(to_str(p % id)) &
|
||||
//" had a negative distance to a lattice boundary. d = " &
|
||||
//trim(to_str(d_lat)))
|
||||
end if
|
||||
end if LAT_COORD
|
||||
|
||||
! If the boundary on this lattice level is coincident with a boundary on
|
||||
! a higher level then we need to make sure that the higher level boundary
|
||||
! is selected. This logic must include consideration of floating point
|
||||
! precision.
|
||||
if (d_surf < d_lat) then
|
||||
if ((dist - d_surf)/dist >= FP_REL_PRECISION) then
|
||||
dist = d_surf
|
||||
|
||||
! If the cell is not simple, it is possible that both the negative and
|
||||
! positive half-space were given in the region specification. Thus, we
|
||||
! have to explicitly check which half-space the particle would be
|
||||
! traveling into if the surface is crossed
|
||||
if (.not. c % simple()) then
|
||||
xyz_cross(:) = p % coord(j) % xyz + d_surf*p % coord(j) % uvw
|
||||
call surfaces(abs(level_surf_cross)) % normal(xyz_cross, surf_uvw)
|
||||
if (dot_product(p % coord(j) % uvw, surf_uvw) > ZERO) then
|
||||
surface_crossed = abs(level_surf_cross)
|
||||
else
|
||||
surface_crossed = -abs(level_surf_cross)
|
||||
end if
|
||||
else
|
||||
surface_crossed = level_surf_cross
|
||||
end if
|
||||
|
||||
lattice_translation(:) = [0, 0, 0]
|
||||
next_level = j
|
||||
end if
|
||||
else
|
||||
if ((dist - d_lat)/dist >= FP_REL_PRECISION) then
|
||||
dist = d_lat
|
||||
surface_crossed = NONE
|
||||
lattice_translation(:) = level_lat_trans
|
||||
next_level = j
|
||||
end if
|
||||
end if
|
||||
|
||||
end do LEVEL_LOOP
|
||||
|
||||
end subroutine distance_to_boundary
|
||||
|
||||
!===============================================================================
|
||||
! NEIGHBOR_LISTS builds a list of neighboring cells to each surface to speed up
|
||||
! searches when a cell boundary is crossed.
|
||||
!===============================================================================
|
||||
|
||||
subroutine neighbor_lists()
|
||||
|
||||
integer :: i ! index in cells/surfaces array
|
||||
integer :: j ! index in region specification
|
||||
integer :: k ! surface half-space spec
|
||||
integer :: n ! size of vector
|
||||
type(VectorInt), allocatable :: neighbor_pos(:)
|
||||
type(VectorInt), allocatable :: neighbor_neg(:)
|
||||
|
||||
call write_message("Building neighboring cells lists for each surface...", &
|
||||
6)
|
||||
|
||||
allocate(neighbor_pos(n_surfaces))
|
||||
allocate(neighbor_neg(n_surfaces))
|
||||
|
||||
do i = 1, n_cells
|
||||
do j = 1, size(cells(i)%region)
|
||||
! Get token from region specification and skip any tokens that
|
||||
! correspond to operators rather than regions
|
||||
k = cells(i)%region(j)
|
||||
if (abs(k) >= OP_UNION) cycle
|
||||
|
||||
! Add this cell ID to neighbor list for k-th surface
|
||||
if (k > 0) then
|
||||
call neighbor_pos(abs(k))%push_back(i)
|
||||
else
|
||||
call neighbor_neg(abs(k))%push_back(i)
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
do i = 1, n_surfaces
|
||||
! Copy positive neighbors to Surface instance
|
||||
n = neighbor_pos(i)%size()
|
||||
if (n > 0) then
|
||||
allocate(surfaces(i)%neighbor_pos(n))
|
||||
surfaces(i)%neighbor_pos(:) = neighbor_pos(i)%data(1:n)
|
||||
end if
|
||||
|
||||
! Copy negative neighbors to Surface instance
|
||||
n = neighbor_neg(i)%size()
|
||||
if (n > 0) then
|
||||
allocate(surfaces(i)%neighbor_neg(n))
|
||||
surfaces(i)%neighbor_neg(:) = neighbor_neg(i)%data(1:n)
|
||||
end if
|
||||
end do
|
||||
|
||||
end subroutine neighbor_lists
|
||||
|
||||
end module geometry
|
||||
|
|
|
|||
406
src/geometry.cpp
Normal file
406
src/geometry.cpp
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
#include "openmc/geometry.h"
|
||||
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
#include "openmc/cell.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/lattice.h"
|
||||
#include "openmc/simulation.h"
|
||||
#include "openmc/surface.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
std::vector<int64_t> overlap_check_count;
|
||||
|
||||
constexpr int F90_NONE {0}; //TODO: replace usage of this with C_NONE
|
||||
|
||||
//==============================================================================
|
||||
|
||||
extern "C" bool
|
||||
check_cell_overlap(Particle* p) {
|
||||
int n_coord = p->n_coord;
|
||||
|
||||
// Loop through each coordinate level
|
||||
for (int j = 0; j < n_coord; j++) {
|
||||
Universe& univ = *universes[p->coord[j].universe];
|
||||
int n = univ.cells_.size();
|
||||
|
||||
// Loop through each cell on this level
|
||||
for (auto index_cell : univ.cells_) {
|
||||
Cell& c = *cells[index_cell];
|
||||
if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) {
|
||||
if (index_cell != p->coord[j].cell) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Overlapping cells detected: " << c.id_ << ", "
|
||||
<< cells[p->coord[j].cell]->id_ << " on universe "
|
||||
<< univ.id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
++overlap_check_count[index_cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
extern "C" bool
|
||||
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) {
|
||||
p->coord[p->n_coord-1].universe = openmc_root_universe;
|
||||
i_universe = openmc_root_universe;
|
||||
}
|
||||
|
||||
// If a surface was indicated, only search cells from the neighbor list of
|
||||
// that surface. The surface index is signed, and the sign signifies whether
|
||||
// the positive or negative side of the surface should be searched.
|
||||
const std::vector<int>* search_cells;
|
||||
if (search_surf > 0) {
|
||||
search_cells = &surfaces[search_surf-1]->neighbor_pos_;
|
||||
} else if (search_surf < 0) {
|
||||
search_cells = &surfaces[-search_surf-1]->neighbor_neg_;
|
||||
} else {
|
||||
// No surface was indicated, search all cells in the universe.
|
||||
search_cells = &universes[i_universe]->cells_;
|
||||
}
|
||||
|
||||
// Find which cell of this universe the particle is in.
|
||||
bool found = false;
|
||||
int32_t i_cell;
|
||||
for (int i = 0; i < search_cells->size(); i++) {
|
||||
i_cell = (*search_cells)[i];
|
||||
|
||||
// Make sure the search cell is in the same universe.
|
||||
if (cells[i_cell]->universe_ != i_universe) continue;
|
||||
|
||||
Position r {p->coord[p->n_coord-1].xyz};
|
||||
Direction u {p->coord[p->n_coord-1].uvw};
|
||||
int32_t surf = p->surface;
|
||||
if (cells[i_cell]->contains(r, u, surf)) {
|
||||
p->coord[p->n_coord-1].cell = i_cell;
|
||||
|
||||
if (openmc_verbosity >= 10 || openmc_trace) {
|
||||
std::stringstream msg;
|
||||
msg << " Entering cell " << cells[i_cell]->id_;
|
||||
write_message(msg, 1);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
Cell& c {*cells[i_cell]};
|
||||
if (c.type_ == FILL_MATERIAL) {
|
||||
//=======================================================================
|
||||
//! Found a material cell which means this is the lowest coord level.
|
||||
|
||||
// Find the distribcell instance number.
|
||||
if (c.material_.size() > 1 || c.sqrtkT_.size() > 1) {
|
||||
int offset = 0;
|
||||
for (int i = 0; i < p->n_coord; i++) {
|
||||
Cell& c_i {*cells[p->coord[i].cell]};
|
||||
if (c_i.type_ == FILL_UNIVERSE) {
|
||||
offset += c_i.offset_[c.distribcell_index_];
|
||||
} else if (c_i.type_ == FILL_LATTICE) {
|
||||
Lattice& lat {*lattices[p->coord[i+1].lattice-1]};
|
||||
int i_xyz[3] {p->coord[i+1].lattice_x,
|
||||
p->coord[i+1].lattice_y,
|
||||
p->coord[i+1].lattice_z};
|
||||
if (lat.are_valid_indices(i_xyz)) {
|
||||
offset += lat.offset(c.distribcell_index_, i_xyz);
|
||||
}
|
||||
}
|
||||
}
|
||||
p->cell_instance = offset;
|
||||
} else {
|
||||
p->cell_instance = 0;
|
||||
}
|
||||
|
||||
// Set the material and temperature.
|
||||
p->last_material = p->material;
|
||||
int32_t mat;
|
||||
if (c.material_.size() > 1) {
|
||||
mat = c.material_[p->cell_instance];
|
||||
} else {
|
||||
mat = c.material_[0];
|
||||
}
|
||||
if (mat == MATERIAL_VOID) {
|
||||
p->material = MATERIAL_VOID;
|
||||
} else {
|
||||
p->material = mat + 1;
|
||||
}
|
||||
p->last_sqrtkT = p->sqrtkT;
|
||||
if (c.sqrtkT_.size() > 1) {
|
||||
p->sqrtkT = c.sqrtkT_[p->cell_instance];
|
||||
} else {
|
||||
p->sqrtkT = c.sqrtkT_[0];
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else if (c.type_ == FILL_UNIVERSE) {
|
||||
//========================================================================
|
||||
//! Found a lower universe, update this coord level then search the next.
|
||||
|
||||
// Set the lower coordinate level universe.
|
||||
p->coord[p->n_coord].universe = c.fill_;
|
||||
|
||||
// Set the position and direction.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
p->coord[p->n_coord].xyz[i] = p->coord[p->n_coord-1].xyz[i];
|
||||
p->coord[p->n_coord].uvw[i] = p->coord[p->n_coord-1].uvw[i];
|
||||
}
|
||||
|
||||
// Apply translation.
|
||||
p->coord[p->n_coord].xyz[0] -= c.translation_.x;
|
||||
p->coord[p->n_coord].xyz[1] -= c.translation_.y;
|
||||
p->coord[p->n_coord].xyz[2] -= c.translation_.z;
|
||||
|
||||
// Apply rotation.
|
||||
if (!c.rotation_.empty()) {
|
||||
auto x = p->coord[p->n_coord].xyz[0];
|
||||
auto y = p->coord[p->n_coord].xyz[1];
|
||||
auto z = p->coord[p->n_coord].xyz[2];
|
||||
p->coord[p->n_coord].xyz[0] = x*c.rotation_[3] + y*c.rotation_[4]
|
||||
+ z*c.rotation_[5];
|
||||
p->coord[p->n_coord].xyz[1] = x*c.rotation_[6] + y*c.rotation_[7]
|
||||
+ z*c.rotation_[8];
|
||||
p->coord[p->n_coord].xyz[2] = x*c.rotation_[9] + y*c.rotation_[10]
|
||||
+ z*c.rotation_[11];
|
||||
auto u = p->coord[p->n_coord].uvw[0];
|
||||
auto v = p->coord[p->n_coord].uvw[1];
|
||||
auto w = p->coord[p->n_coord].uvw[2];
|
||||
p->coord[p->n_coord].uvw[0] = u*c.rotation_[3] + v*c.rotation_[4]
|
||||
+ w*c.rotation_[5];
|
||||
p->coord[p->n_coord].uvw[1] = u*c.rotation_[6] + v*c.rotation_[7]
|
||||
+ w*c.rotation_[8];
|
||||
p->coord[p->n_coord].uvw[2] = u*c.rotation_[9] + v*c.rotation_[10]
|
||||
+ w*c.rotation_[11];
|
||||
p->coord[p->n_coord].rotated = true;
|
||||
}
|
||||
|
||||
// Update the coordinate level and recurse.
|
||||
++p->n_coord;
|
||||
return find_cell(p, 0);
|
||||
|
||||
} else if (c.type_ == FILL_LATTICE) {
|
||||
//========================================================================
|
||||
//! Found a lower lattice, update this coord level then search the next.
|
||||
|
||||
Lattice& lat {*lattices[c.fill_]};
|
||||
|
||||
// Determine lattice indices.
|
||||
Position r {p->coord[p->n_coord-1].xyz};
|
||||
Direction u {p->coord[p->n_coord-1].uvw};
|
||||
r += TINY_BIT * u;
|
||||
auto i_xyz = lat.get_indices(r);
|
||||
|
||||
// Store lower level coordinates.
|
||||
r = lat.get_local_position(p->coord[p->n_coord-1].xyz, i_xyz);
|
||||
p->coord[p->n_coord].xyz[0] = r.x;
|
||||
p->coord[p->n_coord].xyz[1] = r.y;
|
||||
p->coord[p->n_coord].xyz[2] = r.z;
|
||||
p->coord[p->n_coord].uvw[0] = u.x;
|
||||
p->coord[p->n_coord].uvw[1] = u.y;
|
||||
p->coord[p->n_coord].uvw[2] = u.z;
|
||||
|
||||
// Set lattice indices.
|
||||
p->coord[p->n_coord].lattice = c.fill_ + 1;
|
||||
p->coord[p->n_coord].lattice_x = i_xyz[0];
|
||||
p->coord[p->n_coord].lattice_y = i_xyz[1];
|
||||
p->coord[p->n_coord].lattice_z = i_xyz[2];
|
||||
|
||||
// Set the lower coordinate level universe.
|
||||
if (lat.are_valid_indices(i_xyz)) {
|
||||
p->coord[p->n_coord].universe = lat[i_xyz];
|
||||
} else {
|
||||
if (lat.outer_ != NO_OUTER_UNIVERSE) {
|
||||
p->coord[p->n_coord].universe = lat.outer_;
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Particle " << p->id << " is outside lattice "
|
||||
<< lat.id_ << " but the lattice has no defined outer "
|
||||
"universe.";
|
||||
warning(err_msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the coordinate level and recurse.
|
||||
++p->n_coord;
|
||||
return find_cell(p, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
cross_lattice(Particle* p, int lattice_translation[3])
|
||||
{
|
||||
Lattice& lat {*lattices[p->coord[p->n_coord-1].lattice-1]};
|
||||
|
||||
if (openmc_verbosity >= 10 || openmc_trace) {
|
||||
std::stringstream msg;
|
||||
msg << " Crossing lattice " << lat.id_ << ". Current position ("
|
||||
<< p->coord[p->n_coord-1].lattice_x << ","
|
||||
<< p->coord[p->n_coord-1].lattice_y << ","
|
||||
<< p->coord[p->n_coord-1].lattice_z << ")";
|
||||
write_message(msg, 1);
|
||||
}
|
||||
|
||||
// Set the lattice indices.
|
||||
p->coord[p->n_coord-1].lattice_x += lattice_translation[0];
|
||||
p->coord[p->n_coord-1].lattice_y += lattice_translation[1];
|
||||
p->coord[p->n_coord-1].lattice_z += lattice_translation[2];
|
||||
std::array<int, 3> i_xyz {p->coord[p->n_coord-1].lattice_x,
|
||||
p->coord[p->n_coord-1].lattice_y,
|
||||
p->coord[p->n_coord-1].lattice_z};
|
||||
|
||||
// Set the new coordinate position.
|
||||
auto r = lat.get_local_position(p->coord[p->n_coord-2].xyz, i_xyz);
|
||||
p->coord[p->n_coord-1].xyz[0] = r.x;
|
||||
p->coord[p->n_coord-1].xyz[1] = r.y;
|
||||
p->coord[p->n_coord-1].xyz[2] = r.z;
|
||||
|
||||
if (!lat.are_valid_indices(i_xyz)) {
|
||||
// The particle is outside the lattice. Search for it from the base coords.
|
||||
p->n_coord = 1;
|
||||
bool found = find_cell(p, 0);
|
||||
if (!found && p->alive) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Could not locate particle " << p->id
|
||||
<< " after crossing a lattice boundary";
|
||||
p->mark_as_lost(err_msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Find cell in next lattice element.
|
||||
p->coord[p->n_coord-1].universe = lat[i_xyz];
|
||||
bool found = find_cell(p, 0);
|
||||
|
||||
if (!found) {
|
||||
// A particle crossing the corner of a lattice tile may not be found. In
|
||||
// this case, search for it from the base coords.
|
||||
p->n_coord = 1;
|
||||
bool found = find_cell(p, 0);
|
||||
if (!found && p->alive) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Could not locate particle " << p->id
|
||||
<< " after crossing a lattice boundary";
|
||||
p->mark_as_lost(err_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
distance_to_boundary(Particle* p, double* dist, int* surface_crossed,
|
||||
int lattice_translation[3], int* next_level)
|
||||
{
|
||||
*dist = INFINITY;
|
||||
double d_lat = INFINITY;
|
||||
double d_surf = INFINITY;
|
||||
lattice_translation[0] = 0;
|
||||
lattice_translation[1] = 0;
|
||||
lattice_translation[2] = 0;
|
||||
int32_t level_surf_cross;
|
||||
std::array<int, 3> level_lat_trans;
|
||||
|
||||
// Loop over each coordinate level.
|
||||
for (int i = 0; i < p->n_coord; i++) {
|
||||
Position r {p->coord[i].xyz};
|
||||
Direction u {p->coord[i].uvw};
|
||||
Cell& c {*cells[p->coord[i].cell]};
|
||||
|
||||
// Find the oncoming surface in this cell and the distance to it.
|
||||
auto surface_distance = c.distance(r, u, p->surface);
|
||||
d_surf = surface_distance.first;
|
||||
level_surf_cross = surface_distance.second;
|
||||
|
||||
// Find the distance to the next lattice tile crossing.
|
||||
if (p->coord[i].lattice != F90_NONE) {
|
||||
Lattice& lat {*lattices[p->coord[i].lattice-1]};
|
||||
std::array<int, 3> i_xyz {p->coord[i].lattice_x, p->coord[i].lattice_y,
|
||||
p->coord[i].lattice_z};
|
||||
//TODO: refactor so both lattice use the same position argument (which
|
||||
//also means the lat.type attribute can be removed)
|
||||
std::pair<double, std::array<int, 3>> lattice_distance;
|
||||
switch (lat.type_) {
|
||||
case LatticeType::rect:
|
||||
lattice_distance = lat.distance(r, u, i_xyz);
|
||||
break;
|
||||
case LatticeType::hex:
|
||||
Position r_hex {p->coord[i-1].xyz[0], p->coord[i-1].xyz[1],
|
||||
p->coord[i].xyz[2]};
|
||||
lattice_distance = lat.distance(r_hex, u, i_xyz);
|
||||
break;
|
||||
}
|
||||
d_lat = lattice_distance.first;
|
||||
level_lat_trans = lattice_distance.second;
|
||||
|
||||
if (d_lat < 0) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Particle " << p->id
|
||||
<< " had a negative distance to a lattice boundary";
|
||||
p->mark_as_lost(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// If the boundary on this coordinate level is coincident with a boundary on
|
||||
// a higher level then we need to make sure that the higher level boundary
|
||||
// is selected. This logic must consider floating point precision.
|
||||
if (d_surf < d_lat) {
|
||||
if (*dist == INFINITY || ((*dist) - d_surf)/(*dist) >= FP_REL_PRECISION) {
|
||||
*dist = d_surf;
|
||||
|
||||
// If the cell is not simple, it is possible that both the negative and
|
||||
// positive half-space were given in the region specification. Thus, we
|
||||
// have to explicitly check which half-space the particle would be
|
||||
// traveling into if the surface is crossed
|
||||
if (c.simple_) {
|
||||
*surface_crossed = level_surf_cross;
|
||||
} else {
|
||||
Position r_hit = r + d_surf * u;
|
||||
Surface& surf {*surfaces[std::abs(level_surf_cross)-1]};
|
||||
Direction norm = surf.normal(r_hit);
|
||||
if (u.dot(norm) > 0) {
|
||||
*surface_crossed = std::abs(level_surf_cross);
|
||||
} else {
|
||||
*surface_crossed = -std::abs(level_surf_cross);
|
||||
}
|
||||
}
|
||||
|
||||
lattice_translation[0] = 0;
|
||||
lattice_translation[1] = 0;
|
||||
lattice_translation[2] = 0;
|
||||
*next_level = i + 1;
|
||||
}
|
||||
} else {
|
||||
if (*dist == INFINITY || ((*dist) - d_lat)/(*dist) >= FP_REL_PRECISION) {
|
||||
*dist = d_lat;
|
||||
*surface_crossed = F90_NONE;
|
||||
lattice_translation[0] = level_lat_trans[0];
|
||||
lattice_translation[1] = level_lat_trans[1];
|
||||
lattice_translation[2] = level_lat_trans[2];
|
||||
*next_level = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -7,8 +7,11 @@
|
|||
#include "openmc/cell.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/geometry.h"
|
||||
#include "openmc/lattice.h"
|
||||
#include "openmc/material.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/surface.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -19,26 +22,26 @@ void
|
|||
adjust_indices()
|
||||
{
|
||||
// Adjust material/fill idices.
|
||||
for (Cell* c : global_cells) {
|
||||
if (c->fill != C_NONE) {
|
||||
int32_t id = c->fill;
|
||||
for (Cell* c : cells) {
|
||||
if (c->fill_ != C_NONE) {
|
||||
int32_t id = c->fill_;
|
||||
auto search_univ = universe_map.find(id);
|
||||
auto search_lat = lattice_map.find(id);
|
||||
if (search_univ != universe_map.end()) {
|
||||
c->type = FILL_UNIVERSE;
|
||||
c->fill = search_univ->second;
|
||||
c->type_ = FILL_UNIVERSE;
|
||||
c->fill_ = search_univ->second;
|
||||
} else if (search_lat != lattice_map.end()) {
|
||||
c->type = FILL_LATTICE;
|
||||
c->fill = search_lat->second;
|
||||
c->type_ = FILL_LATTICE;
|
||||
c->fill_ = search_lat->second;
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Specified fill " << id << " on cell " << c->id
|
||||
err_msg << "Specified fill " << id << " on cell " << c->id_
|
||||
<< " is neither a universe nor a lattice.";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
} else {
|
||||
c->type = FILL_MATERIAL;
|
||||
for (auto it = c->material.begin(); it != c->material.end(); it++) {
|
||||
c->type_ = FILL_MATERIAL;
|
||||
for (auto it = c->material_.begin(); it != c->material_.end(); it++) {
|
||||
int32_t mid = *it;
|
||||
if (mid != MATERIAL_VOID) {
|
||||
auto search = material_map.find(mid);
|
||||
|
|
@ -47,7 +50,7 @@ adjust_indices()
|
|||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Could not find material " << mid
|
||||
<< " specified on cell " << c->id;
|
||||
<< " specified on cell " << c->id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -56,51 +59,80 @@ adjust_indices()
|
|||
}
|
||||
|
||||
// Change cell.universe values from IDs to indices.
|
||||
for (Cell* c : global_cells) {
|
||||
auto search = universe_map.find(c->universe);
|
||||
for (Cell* c : cells) {
|
||||
auto search = universe_map.find(c->universe_);
|
||||
if (search != universe_map.end()) {
|
||||
//TODO: Remove this off-by-one indexing.
|
||||
c->universe = search->second + 1;
|
||||
c->universe_ = search->second;
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Could not find universe " << c->universe
|
||||
<< " specified on cell " << c->id;
|
||||
err_msg << "Could not find universe " << c->universe_
|
||||
<< " specified on cell " << c->id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Change all lattice universe values from IDs to indices.
|
||||
for (Lattice* l : lattices_c) {
|
||||
for (Lattice* l : lattices) {
|
||||
l->adjust_indices();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
assign_temperatures()
|
||||
{
|
||||
for (Cell* c : cells) {
|
||||
// Ignore non-material cells and cells with defined temperature.
|
||||
if (c->material_.size() == 0) continue;
|
||||
if (c->sqrtkT_.size() > 0) continue;
|
||||
|
||||
c->sqrtkT_.reserve(c->material_.size());
|
||||
for (auto i_mat : c->material_) {
|
||||
if (i_mat == MATERIAL_VOID) {
|
||||
// Set void region to 0K.
|
||||
c->sqrtkT_.push_back(0);
|
||||
|
||||
} else {
|
||||
if (materials[i_mat]->temperature_ >= 0) {
|
||||
// This material has a default temperature; use that value.
|
||||
auto T = materials[i_mat]->temperature_;
|
||||
c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T));
|
||||
} else {
|
||||
// Use the global default temperature.
|
||||
c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temperature_default));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
int32_t
|
||||
find_root_universe()
|
||||
{
|
||||
// Find all the universes listed as a cell fill.
|
||||
std::unordered_set<int32_t> fill_univ_ids;
|
||||
for (Cell* c : global_cells) {
|
||||
fill_univ_ids.insert(c->fill);
|
||||
for (Cell* c : cells) {
|
||||
fill_univ_ids.insert(c->fill_);
|
||||
}
|
||||
|
||||
// Find all the universes contained in a lattice.
|
||||
for (Lattice* lat : lattices_c) {
|
||||
for (Lattice* lat : lattices) {
|
||||
for (auto it = lat->begin(); it != lat->end(); ++it) {
|
||||
fill_univ_ids.insert(*it);
|
||||
}
|
||||
if (lat->outer != NO_OUTER_UNIVERSE) {
|
||||
fill_univ_ids.insert(lat->outer);
|
||||
if (lat->outer_ != NO_OUTER_UNIVERSE) {
|
||||
fill_univ_ids.insert(lat->outer_);
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out which universe is not in the set. This is the root universe.
|
||||
bool root_found {false};
|
||||
int32_t root_univ;
|
||||
for (int32_t i = 0; i < global_universes.size(); i++) {
|
||||
auto search = fill_univ_ids.find(global_universes[i]->id);
|
||||
for (int32_t i = 0; i < universes.size(); i++) {
|
||||
auto search = fill_univ_ids.find(universes[i]->id_);
|
||||
if (search == fill_univ_ids.end()) {
|
||||
if (root_found) {
|
||||
fatal_error("Two or more universes are not used as fill universes, so "
|
||||
|
|
@ -121,17 +153,116 @@ find_root_universe()
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
allocate_offset_tables(int n_maps)
|
||||
neighbor_lists()
|
||||
{
|
||||
for (Cell* c : global_cells) {
|
||||
if (c->type != FILL_MATERIAL) {
|
||||
c->offset.resize(n_maps, C_NONE);
|
||||
write_message("Building neighboring cells lists for each surface...", 6);
|
||||
|
||||
for (int i = 0; i < cells.size(); i++) {
|
||||
for (auto token : cells[i]->region_) {
|
||||
// Skip operator tokens.
|
||||
if (std::abs(token) >= OP_UNION) continue;
|
||||
|
||||
// This token is a surface index. Add the cell to the surface's list.
|
||||
if (token > 0) {
|
||||
surfaces[std::abs(token)-1]->neighbor_pos_.push_back(i);
|
||||
} else {
|
||||
surfaces[std::abs(token)-1]->neighbor_neg_.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Lattice* lat : lattices_c) {
|
||||
for (Surface* surf : surfaces) {
|
||||
surf->neighbor_pos_.shrink_to_fit();
|
||||
surf->neighbor_neg_.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
prepare_distribcell(int32_t* filter_cell_list, int n)
|
||||
{
|
||||
// Read the list of cells contained in distribcell filters from Fortran.
|
||||
std::unordered_set<int32_t> distribcells;
|
||||
for (int i = 0; i < n; i++) {
|
||||
distribcells.insert(filter_cell_list[i]);
|
||||
}
|
||||
|
||||
// Find all cells with distributed materials or temperatures. Make sure that
|
||||
// the number of materials/temperatures matches the number of cell instances.
|
||||
for (int i = 0; i < cells.size(); i++) {
|
||||
Cell& c {*cells[i]};
|
||||
|
||||
if (c.material_.size() > 1) {
|
||||
if (c.material_.size() != c.n_instances_) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cell " << c.id_ << " was specified with "
|
||||
<< c.material_.size() << " materials but has " << c.n_instances_
|
||||
<< " distributed instances. The number of materials must equal "
|
||||
"one or the number of instances.";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
distribcells.insert(i);
|
||||
}
|
||||
|
||||
if (c.sqrtkT_.size() > 1) {
|
||||
if (c.sqrtkT_.size() != c.n_instances_) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Cell " << c.id_ << " was specified with "
|
||||
<< c.sqrtkT_.size() << " temperatures but has " << c.n_instances_
|
||||
<< " distributed instances. The number of temperatures must equal "
|
||||
"one or the number of instances.";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
distribcells.insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Search through universes for distributed cells and assign each one a
|
||||
// unique distribcell array index.
|
||||
int distribcell_index = 0;
|
||||
std::vector<int32_t> target_univ_ids;
|
||||
for (Universe* u : universes) {
|
||||
for (auto cell_indx : u->cells_) {
|
||||
if (distribcells.find(cell_indx) != distribcells.end()) {
|
||||
cells[cell_indx]->distribcell_index_ = distribcell_index;
|
||||
target_univ_ids.push_back(u->id_);
|
||||
++distribcell_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the cell and lattice offset tables.
|
||||
int n_maps = target_univ_ids.size();
|
||||
for (Cell* c : cells) {
|
||||
if (c->type_ != FILL_MATERIAL) {
|
||||
c->offset_.resize(n_maps, C_NONE);
|
||||
}
|
||||
}
|
||||
for (Lattice* lat : lattices) {
|
||||
lat->allocate_offset_table(n_maps);
|
||||
}
|
||||
|
||||
// Fill the cell and lattice offset tables.
|
||||
for (int map = 0; map < target_univ_ids.size(); map++) {
|
||||
auto target_univ_id = target_univ_ids[map];
|
||||
for (Universe* univ : universes) {
|
||||
int32_t offset {0}; // TODO: is this a bug? It matches F90 implementation.
|
||||
for (int32_t cell_indx : univ->cells_) {
|
||||
Cell& c = *cells[cell_indx];
|
||||
|
||||
if (c.type_ == FILL_UNIVERSE) {
|
||||
c.offset_[map] = offset;
|
||||
int32_t search_univ = c.fill_;
|
||||
offset += count_universe_instances(search_univ, target_univ_id);
|
||||
|
||||
} else if (c.type_ == FILL_LATTICE) {
|
||||
Lattice& lat = *lattices[c.fill_];
|
||||
offset = lat.fill_offset_table(offset, target_univ_id, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -139,17 +270,17 @@ allocate_offset_tables(int n_maps)
|
|||
void
|
||||
count_cell_instances(int32_t univ_indx)
|
||||
{
|
||||
for (int32_t cell_indx : global_universes[univ_indx]->cells) {
|
||||
Cell& c = *global_cells[cell_indx];
|
||||
++c.n_instances;
|
||||
for (int32_t cell_indx : universes[univ_indx]->cells_) {
|
||||
Cell& c = *cells[cell_indx];
|
||||
++c.n_instances_;
|
||||
|
||||
if (c.type == FILL_UNIVERSE) {
|
||||
if (c.type_ == FILL_UNIVERSE) {
|
||||
// This cell contains another universe. Recurse into that universe.
|
||||
count_cell_instances(c.fill);
|
||||
count_cell_instances(c.fill_);
|
||||
|
||||
} else if (c.type == FILL_LATTICE) {
|
||||
} else if (c.type_ == FILL_LATTICE) {
|
||||
// This cell contains a lattice. Recurse into the lattice universes.
|
||||
Lattice& lat = *lattices_c[c.fill];
|
||||
Lattice& lat = *lattices[c.fill_];
|
||||
for (auto it = lat.begin(); it != lat.end(); ++it) {
|
||||
count_cell_instances(*it);
|
||||
}
|
||||
|
|
@ -163,20 +294,20 @@ int
|
|||
count_universe_instances(int32_t search_univ, int32_t target_univ_id)
|
||||
{
|
||||
// If this is the target, it can't contain itself.
|
||||
if (global_universes[search_univ]->id == target_univ_id) {
|
||||
if (universes[search_univ]->id_ == target_univ_id) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int count {0};
|
||||
for (int32_t cell_indx : global_universes[search_univ]->cells) {
|
||||
Cell& c = *global_cells[cell_indx];
|
||||
for (int32_t cell_indx : universes[search_univ]->cells_) {
|
||||
Cell& c = *cells[cell_indx];
|
||||
|
||||
if (c.type == FILL_UNIVERSE) {
|
||||
int32_t next_univ = c.fill;
|
||||
if (c.type_ == FILL_UNIVERSE) {
|
||||
int32_t next_univ = c.fill_;
|
||||
count += count_universe_instances(next_univ, target_univ_id);
|
||||
|
||||
} else if (c.type == FILL_LATTICE) {
|
||||
Lattice& lat = *lattices_c[c.fill];
|
||||
} else if (c.type_ == FILL_LATTICE) {
|
||||
Lattice& lat = *lattices[c.fill_];
|
||||
for (auto it = lat.begin(); it != lat.end(); ++it) {
|
||||
int32_t next_univ = *it;
|
||||
count += count_universe_instances(next_univ, target_univ_id);
|
||||
|
|
@ -189,43 +320,20 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id)
|
|||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
fill_offset_tables(int32_t target_univ_id, int map)
|
||||
{
|
||||
for (Universe* univ : global_universes) {
|
||||
int32_t offset {0}; // TODO: is this a bug? It matches F90 implementation.
|
||||
for (int32_t cell_indx : univ->cells) {
|
||||
Cell& c = *global_cells[cell_indx];
|
||||
|
||||
if (c.type == FILL_UNIVERSE) {
|
||||
c.offset[map] = offset;
|
||||
int32_t search_univ = c.fill;
|
||||
offset += count_universe_instances(search_univ, target_univ_id);
|
||||
|
||||
} else if (c.type == FILL_LATTICE) {
|
||||
Lattice& lat = *lattices_c[c.fill];
|
||||
offset = lat.fill_offset_table(offset, target_univ_id, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
std::string
|
||||
distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset,
|
||||
const Universe& search_univ, int32_t offset)
|
||||
{
|
||||
std::stringstream path;
|
||||
|
||||
path << "u" << search_univ.id << "->";
|
||||
path << "u" << search_univ.id_ << "->";
|
||||
|
||||
// Check to see if this universe directly contains the target cell. If so,
|
||||
// write to the path and return.
|
||||
for (int32_t cell_indx : search_univ.cells) {
|
||||
for (int32_t cell_indx : search_univ.cells_) {
|
||||
if ((cell_indx == target_cell) && (offset == target_offset)) {
|
||||
Cell& c = *global_cells[cell_indx];
|
||||
path << "c" << c.id;
|
||||
Cell& c = *cells[cell_indx];
|
||||
path << "c" << c.id_;
|
||||
return path.str();
|
||||
}
|
||||
}
|
||||
|
|
@ -234,19 +342,19 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset,
|
|||
// cell or lattice cell in this universe. Find which cell contains the
|
||||
// target.
|
||||
std::vector<std::int32_t>::const_reverse_iterator cell_it
|
||||
{search_univ.cells.crbegin()};
|
||||
for (; cell_it != search_univ.cells.crend(); ++cell_it) {
|
||||
Cell& c = *global_cells[*cell_it];
|
||||
{search_univ.cells_.crbegin()};
|
||||
for (; cell_it != search_univ.cells_.crend(); ++cell_it) {
|
||||
Cell& c = *cells[*cell_it];
|
||||
|
||||
// Material cells don't contain other cells so ignore them.
|
||||
if (c.type != FILL_MATERIAL) {
|
||||
if (c.type_ != FILL_MATERIAL) {
|
||||
int32_t temp_offset;
|
||||
if (c.type == FILL_UNIVERSE) {
|
||||
temp_offset = offset + c.offset[map];
|
||||
if (c.type_ == FILL_UNIVERSE) {
|
||||
temp_offset = offset + c.offset_[map];
|
||||
} else {
|
||||
Lattice& lat = *lattices_c[c.fill];
|
||||
int32_t indx = lat.universes.size()*map + lat.begin().indx;
|
||||
temp_offset = offset + lat.offsets[indx];
|
||||
Lattice& lat = *lattices[c.fill_];
|
||||
int32_t indx = lat.universes_.size()*map + lat.begin().indx_;
|
||||
temp_offset = offset + lat.offsets_[indx];
|
||||
}
|
||||
|
||||
// The desired cell is the first cell that gives an offset smaller or
|
||||
|
|
@ -256,27 +364,27 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset,
|
|||
}
|
||||
|
||||
// Add the cell to the path string.
|
||||
Cell& c = *global_cells[*cell_it];
|
||||
path << "c" << c.id << "->";
|
||||
Cell& c = *cells[*cell_it];
|
||||
path << "c" << c.id_ << "->";
|
||||
|
||||
if (c.type == FILL_UNIVERSE) {
|
||||
if (c.type_ == FILL_UNIVERSE) {
|
||||
// Recurse into the fill cell.
|
||||
offset += c.offset[map];
|
||||
offset += c.offset_[map];
|
||||
path << distribcell_path_inner(target_cell, map, target_offset,
|
||||
*global_universes[c.fill], offset);
|
||||
*universes[c.fill_], offset);
|
||||
return path.str();
|
||||
} else {
|
||||
// Recurse into the lattice cell.
|
||||
Lattice& lat = *lattices_c[c.fill];
|
||||
path << "l" << lat.id;
|
||||
Lattice& lat = *lattices[c.fill_];
|
||||
path << "l" << lat.id_;
|
||||
for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) {
|
||||
int32_t indx = lat.universes.size()*map + it.indx;
|
||||
int32_t temp_offset = offset + lat.offsets[indx];
|
||||
int32_t indx = lat.universes_.size()*map + it.indx_;
|
||||
int32_t temp_offset = offset + lat.offsets_[indx];
|
||||
if (temp_offset <= target_offset) {
|
||||
offset = temp_offset;
|
||||
path << "(" << lat.index_to_string(it.indx) << ")->";
|
||||
path << "(" << lat.index_to_string(it.indx_) << ")->";
|
||||
path << distribcell_path_inner(target_cell, map, target_offset,
|
||||
*global_universes[*it], offset);
|
||||
*universes[*it], offset);
|
||||
return path.str();
|
||||
}
|
||||
}
|
||||
|
|
@ -289,7 +397,7 @@ int
|
|||
distribcell_path_len(int32_t target_cell, int32_t map, int32_t target_offset,
|
||||
int32_t root_univ)
|
||||
{
|
||||
Universe& root = *global_universes[root_univ];
|
||||
Universe& root = *universes[root_univ];
|
||||
std::string path_ {distribcell_path_inner(target_cell, map, target_offset,
|
||||
root, 0)};
|
||||
return path_.size() + 1;
|
||||
|
|
@ -301,7 +409,7 @@ void
|
|||
distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset,
|
||||
int32_t root_univ, char* path)
|
||||
{
|
||||
Universe& root = *global_universes[root_univ];
|
||||
Universe& root = *universes[root_univ];
|
||||
std::string path_ {distribcell_path_inner(target_cell, map, target_offset,
|
||||
root, 0)};
|
||||
path_.copy(path, path_.size());
|
||||
|
|
@ -315,13 +423,13 @@ maximum_levels(int32_t univ)
|
|||
{
|
||||
int levels_below {0};
|
||||
|
||||
for (int32_t cell_indx : global_universes[univ]->cells) {
|
||||
Cell& c = *global_cells[cell_indx];
|
||||
if (c.type == FILL_UNIVERSE) {
|
||||
int32_t next_univ = c.fill;
|
||||
for (int32_t cell_indx : universes[univ]->cells_) {
|
||||
Cell& c = *cells[cell_indx];
|
||||
if (c.type_ == FILL_UNIVERSE) {
|
||||
int32_t next_univ = c.fill_;
|
||||
levels_below = std::max(levels_below, maximum_levels(next_univ));
|
||||
} else if (c.type == FILL_LATTICE) {
|
||||
Lattice& lat = *lattices_c[c.fill];
|
||||
} else if (c.type_ == FILL_LATTICE) {
|
||||
Lattice& lat = *lattices[c.fill_];
|
||||
for (auto it = lat.begin(); it != lat.end(); ++it) {
|
||||
int32_t next_univ = *it;
|
||||
levels_below = std::max(levels_below, maximum_levels(next_univ));
|
||||
|
|
@ -338,18 +446,20 @@ maximum_levels(int32_t univ)
|
|||
void
|
||||
free_memory_geometry_c()
|
||||
{
|
||||
for (Cell* c : global_cells) {delete c;}
|
||||
global_cells.clear();
|
||||
for (Cell* c : cells) {delete c;}
|
||||
cells.clear();
|
||||
cell_map.clear();
|
||||
n_cells = 0;
|
||||
|
||||
for (Universe* u : global_universes) {delete u;}
|
||||
global_universes.clear();
|
||||
for (Universe* u : universes) {delete u;}
|
||||
universes.clear();
|
||||
universe_map.clear();
|
||||
|
||||
for (Lattice* lat : lattices_c) {delete lat;}
|
||||
lattices_c.clear();
|
||||
for (Lattice* lat : lattices) {delete lat;}
|
||||
lattices.clear();
|
||||
lattice_map.clear();
|
||||
|
||||
overlap_check_count.clear();
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ module geometry_header
|
|||
implicit none
|
||||
|
||||
interface
|
||||
function universe_id(universe_ind) bind(C) result(id)
|
||||
import C_INT, C_INT32_T
|
||||
integer(C_INT), intent(in), value :: universe_ind
|
||||
integer(C_INT32_T) :: id
|
||||
end function universe_id
|
||||
|
||||
function cell_pointer(cell_ind) bind(C) result(ptr)
|
||||
import C_PTR, C_INT32_T
|
||||
integer(C_INT32_T), intent(in), value :: cell_ind
|
||||
|
|
@ -60,6 +66,13 @@ module geometry_header
|
|||
integer(C_INT32_T) :: n_instances
|
||||
end function cell_n_instances_c
|
||||
|
||||
function cell_distribcell_index_c(cell_ptr) &
|
||||
bind(C, name='cell_distribcell_index') result(distribcell_index)
|
||||
import C_PTR, C_INT
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
integer(C_INT) :: distribcell_index
|
||||
end function cell_distribcell_index_c
|
||||
|
||||
function cell_material_size_c(cell_ptr) bind(C, name='cell_material_size') &
|
||||
result(n)
|
||||
import C_PTR, C_INT
|
||||
|
|
@ -75,22 +88,20 @@ module geometry_header
|
|||
integer(C_INT32_T) :: mat
|
||||
end function cell_material_c
|
||||
|
||||
function cell_simple_c(cell_ptr) bind(C, name='cell_simple') result(simple)
|
||||
import C_PTR, C_BOOL
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
logical(C_BOOL) :: simple
|
||||
end function cell_simple_c
|
||||
function cell_sqrtkT_size_c(cell_ptr) bind(C, name='cell_sqrtkT_size') &
|
||||
result(n)
|
||||
import C_PTR, C_INT
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
integer(C_INT) :: n
|
||||
end function cell_sqrtkT_size_c
|
||||
|
||||
subroutine cell_distance_c(cell_ptr, xyz, uvw, on_surface, min_dist, &
|
||||
i_surf) bind(C, name="cell_distance")
|
||||
import C_PTR, C_INT32_T, C_DOUBLE
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
real(C_DOUBLE), intent(in) :: uvw(3)
|
||||
integer(C_INT32_T), intent(in), value :: on_surface
|
||||
real(C_DOUBLE), intent(out) :: min_dist
|
||||
integer(C_INT32_T), intent(out) :: i_surf
|
||||
end subroutine cell_distance_c
|
||||
function cell_sqrtkT_c(cell_ptr, i) bind(C, name='cell_sqrtkT') &
|
||||
result(sqrtkT)
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
integer(C_INT), intent(in), value :: i
|
||||
real(C_DOUBLE) :: sqrtkT
|
||||
end function cell_sqrtkT_c
|
||||
|
||||
function cell_offset_c(cell_ptr, map) bind(C, name="cell_offset") &
|
||||
result(offset)
|
||||
|
|
@ -100,12 +111,6 @@ module geometry_header
|
|||
integer(C_INT32_T) :: offset
|
||||
end function cell_offset_c
|
||||
|
||||
subroutine cell_to_hdf5_c(cell_ptr, group) bind(C, name='cell_to_hdf5')
|
||||
import HID_T, C_PTR
|
||||
type(C_PTR), intent(in), value :: cell_ptr
|
||||
integer(HID_T), intent(in), value :: group
|
||||
end subroutine cell_to_hdf5_c
|
||||
|
||||
function lattice_pointer(lat_ind) bind(C) result(ptr)
|
||||
import C_PTR, C_INT32_T
|
||||
integer(C_INT32_T), intent(in), value :: lat_ind
|
||||
|
|
@ -126,40 +131,6 @@ module geometry_header
|
|||
logical(C_BOOL) :: is_valid
|
||||
end function lattice_are_valid_indices_c
|
||||
|
||||
subroutine lattice_distance_c(lat_ptr, xyz, uvw, i_xyz, d, lattice_trans) &
|
||||
bind(C, name='lattice_distance')
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), intent(in), value :: lat_ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
real(C_DOUBLE), intent(in) :: uvw(3)
|
||||
integer(C_INT), intent(in) :: i_xyz(3)
|
||||
real(C_DOUBLE), intent(out) :: d
|
||||
integer(C_INT), intent(out) :: lattice_trans(3)
|
||||
end subroutine lattice_distance_c
|
||||
|
||||
subroutine lattice_get_indices_c(lat_ptr, xyz, i_xyz) &
|
||||
bind(C, name='lattice_get_indices')
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), intent(in), value :: lat_ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
integer(C_INT), intent(out) :: i_xyz(3)
|
||||
end subroutine lattice_get_indices_c
|
||||
|
||||
subroutine lattice_get_local_xyz_c(lat_ptr, global_xyz, i_xyz, local_xyz) &
|
||||
bind(C, name='lattice_get_local_xyz')
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), intent(in), value :: lat_ptr
|
||||
real(C_DOUBLE), intent(in) :: global_xyz(3)
|
||||
integer(C_INT), intent(in) :: i_xyz(3)
|
||||
real(C_DOUBLE), intent(out) :: local_xyz(3)
|
||||
end subroutine lattice_get_local_xyz_c
|
||||
|
||||
subroutine lattice_to_hdf5_c(lat_ptr, group) bind(C, name='lattice_to_hdf5')
|
||||
import HID_T, C_PTR
|
||||
type(C_PTR), intent(in), value :: lat_ptr
|
||||
integer(HID_T), intent(in), value :: group
|
||||
end subroutine lattice_to_hdf5_c
|
||||
|
||||
function lattice_offset_c(lat_ptr, map, i_xyz) &
|
||||
bind(C, name='lattice_offset') result(offset)
|
||||
import C_PTR, C_INT, C_INT32_T
|
||||
|
|
@ -169,79 +140,24 @@ module geometry_header
|
|||
integer(C_INT32_T) :: offset
|
||||
end function lattice_offset_c
|
||||
|
||||
function lattice_outer_c(lat_ptr) bind(C, name='lattice_outer') &
|
||||
result(outer)
|
||||
import C_PTR, C_INT32_T
|
||||
type(C_PTR), intent(in), value :: lat_ptr
|
||||
integer(C_INT32_T) :: outer
|
||||
end function lattice_outer_c
|
||||
|
||||
function lattice_universe_c(lat_ptr, i_xyz) &
|
||||
bind(C, name='lattice_universe') result(univ)
|
||||
import C_PTR, C_INT32_t, C_INT
|
||||
type(C_PTR), intent(in), value :: lat_ptr
|
||||
integer(C_INT), intent(in) :: i_xyz(3)
|
||||
integer(C_INT32_T) :: univ
|
||||
end function lattice_universe_c
|
||||
|
||||
subroutine extend_cells_c(n) bind(C)
|
||||
import C_INT32_t
|
||||
integer(C_INT32_T), intent(in), value :: n
|
||||
end subroutine extend_cells_c
|
||||
end interface
|
||||
|
||||
!===============================================================================
|
||||
! UNIVERSE defines a geometry that fills all phase space
|
||||
!===============================================================================
|
||||
|
||||
type Universe
|
||||
integer :: id ! Unique ID
|
||||
integer, allocatable :: cells(:) ! List of cells within
|
||||
real(8) :: x0 ! Translation in x-coordinate
|
||||
real(8) :: y0 ! Translation in y-coordinate
|
||||
real(8) :: z0 ! Translation in z-coordinate
|
||||
end type Universe
|
||||
|
||||
!===============================================================================
|
||||
! LATTICE abstract type for ordered array of universes.
|
||||
!===============================================================================
|
||||
|
||||
type, abstract :: Lattice
|
||||
type :: Lattice
|
||||
type(C_PTR) :: ptr
|
||||
contains
|
||||
procedure :: id => lattice_id
|
||||
procedure :: are_valid_indices => lattice_are_valid_indices
|
||||
procedure :: distance => lattice_distance
|
||||
procedure :: get => lattice_get
|
||||
procedure :: get_indices => lattice_get_indices
|
||||
procedure :: get_local_xyz => lattice_get_local_xyz
|
||||
procedure :: offset => lattice_offset
|
||||
procedure :: outer => lattice_outer
|
||||
procedure :: to_hdf5 => lattice_to_hdf5
|
||||
end type Lattice
|
||||
|
||||
!===============================================================================
|
||||
! RECTLATTICE extends LATTICE for rectilinear arrays.
|
||||
!===============================================================================
|
||||
|
||||
type, extends(Lattice) :: RectLattice
|
||||
end type RectLattice
|
||||
|
||||
!===============================================================================
|
||||
! HEXLATTICE extends LATTICE for hexagonal (sometimes called triangular) arrays.
|
||||
!===============================================================================
|
||||
|
||||
type, extends(Lattice) :: HexLattice
|
||||
end type HexLattice
|
||||
|
||||
!===============================================================================
|
||||
! LATTICECONTAINER pointer array for storing lattices
|
||||
!===============================================================================
|
||||
|
||||
type LatticeContainer
|
||||
class(Lattice), allocatable :: obj
|
||||
end type LatticeContainer
|
||||
|
||||
!===============================================================================
|
||||
! CELL defines a closed volume by its bounding surfaces
|
||||
!===============================================================================
|
||||
|
|
@ -249,16 +165,7 @@ module geometry_header
|
|||
type Cell
|
||||
type(C_PTR) :: ptr
|
||||
|
||||
integer, allocatable :: region(:) ! Definition of spatial region as
|
||||
! Boolean expression of half-spaces
|
||||
integer :: distribcell_index ! Index corresponding to this cell in
|
||||
! distribcell arrays
|
||||
real(8), allocatable :: sqrtkT(:) ! Square root of k_Boltzmann *
|
||||
! temperature in eV. Multiple for
|
||||
! distribcell
|
||||
|
||||
! Rotation matrix and translation vector
|
||||
real(8), allocatable :: translation(:)
|
||||
real(8), allocatable :: rotation(:)
|
||||
real(8), allocatable :: rotation_matrix(:,:)
|
||||
|
||||
|
|
@ -270,12 +177,12 @@ module geometry_header
|
|||
procedure :: universe => cell_universe
|
||||
procedure :: fill => cell_fill
|
||||
procedure :: n_instances => cell_n_instances
|
||||
procedure :: distribcell_index => cell_distribcell_index
|
||||
procedure :: material_size => cell_material_size
|
||||
procedure :: material => cell_material
|
||||
procedure :: simple => cell_simple
|
||||
procedure :: distance => cell_distance
|
||||
procedure :: sqrtkT_size => cell_sqrtkT_size
|
||||
procedure :: sqrtkT => cell_sqrtkT
|
||||
procedure :: offset => cell_offset
|
||||
procedure :: to_hdf5 => cell_to_hdf5
|
||||
|
||||
end type Cell
|
||||
|
||||
|
|
@ -286,8 +193,7 @@ module geometry_header
|
|||
integer(C_INT32_T), bind(C) :: n_universes ! # of universes
|
||||
|
||||
type(Cell), allocatable, target :: cells(:)
|
||||
type(Universe), allocatable, target :: universes(:)
|
||||
type(LatticeContainer), allocatable, target :: lattices(:)
|
||||
type(Lattice), allocatable, target :: lattices(:)
|
||||
|
||||
! Dictionaries which map user IDs to indices in the global arrays
|
||||
type(DictIntInt) :: cell_dict
|
||||
|
|
@ -309,39 +215,6 @@ contains
|
|||
is_valid = lattice_are_valid_indices_c(this % ptr, i_xyz)
|
||||
end function lattice_are_valid_indices
|
||||
|
||||
subroutine lattice_distance(this, xyz, uvw, i_xyz, d, lattice_trans)
|
||||
class(Lattice), intent(in) :: this
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
real(C_DOUBLE), intent(in) :: uvw(3)
|
||||
integer(C_INT), intent(in) :: i_xyz(3)
|
||||
real(C_DOUBLE), intent(out) :: d
|
||||
integer(C_INT), intent(out) :: lattice_trans(3)
|
||||
call lattice_distance_c(this % ptr, xyz, uvw, i_xyz, d, lattice_trans)
|
||||
end subroutine lattice_distance
|
||||
|
||||
function lattice_get(this, i_xyz) result(univ)
|
||||
class(Lattice), intent(in) :: this
|
||||
integer(C_INT), intent(in) :: i_xyz(3)
|
||||
integer(C_INT32_T) :: univ
|
||||
univ = lattice_universe_c(this % ptr, i_xyz)
|
||||
end function lattice_get
|
||||
|
||||
function lattice_get_indices(this, xyz) result(i_xyz)
|
||||
class(Lattice), intent(in) :: this
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
integer(C_INT) :: i_xyz(3)
|
||||
call lattice_get_indices_c(this % ptr, xyz, i_xyz)
|
||||
end function lattice_get_indices
|
||||
|
||||
function lattice_get_local_xyz(this, global_xyz, i_xyz) &
|
||||
result(local_xyz)
|
||||
class(Lattice), intent(in) :: this
|
||||
real(C_DOUBLE), intent(in) :: global_xyz(3)
|
||||
integer(C_INT), intent(in) :: i_xyz(3)
|
||||
real(C_DOUBLE) :: local_xyz(3)
|
||||
call lattice_get_local_xyz_c(this % ptr, global_xyz, i_xyz, local_xyz)
|
||||
end function lattice_get_local_xyz
|
||||
|
||||
function lattice_offset(this, map, i_xyz) result(offset)
|
||||
class(Lattice), intent(in) :: this
|
||||
integer(C_INT), intent(in) :: map
|
||||
|
|
@ -350,18 +223,6 @@ contains
|
|||
offset = lattice_offset_c(this % ptr, map, i_xyz)
|
||||
end function lattice_offset
|
||||
|
||||
function lattice_outer(this) result(outer)
|
||||
class(Lattice), intent(in) :: this
|
||||
integer(C_INT32_T) :: outer
|
||||
outer = lattice_outer_c(this % ptr)
|
||||
end function lattice_outer
|
||||
|
||||
subroutine lattice_to_hdf5(this, group)
|
||||
class(Lattice), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: group
|
||||
call lattice_to_hdf5_c(this % ptr, group)
|
||||
end subroutine lattice_to_hdf5
|
||||
|
||||
!===============================================================================
|
||||
|
||||
function cell_id(this) result(id)
|
||||
|
|
@ -400,6 +261,12 @@ contains
|
|||
n_instances = cell_n_instances_c(this % ptr)
|
||||
end function cell_n_instances
|
||||
|
||||
function cell_distribcell_index(this) result(distribcell_index)
|
||||
class(Cell), intent(in) :: this
|
||||
integer(C_INT) :: distribcell_index
|
||||
distribcell_index = cell_distribcell_index_c(this % ptr)
|
||||
end function cell_distribcell_index
|
||||
|
||||
function cell_material_size(this) result(n)
|
||||
class(Cell), intent(in) :: this
|
||||
integer(C_INT) :: n
|
||||
|
|
@ -413,21 +280,18 @@ contains
|
|||
mat = cell_material_c(this % ptr, i)
|
||||
end function cell_material
|
||||
|
||||
function cell_simple(this) result(simple)
|
||||
function cell_sqrtkT_size(this) result(n)
|
||||
class(Cell), intent(in) :: this
|
||||
logical(C_BOOL) :: simple
|
||||
simple = cell_simple_c(this % ptr)
|
||||
end function cell_simple
|
||||
integer :: n
|
||||
n = cell_sqrtkT_size_c(this % ptr)
|
||||
end function cell_sqrtkT_size
|
||||
|
||||
subroutine cell_distance(this, xyz, uvw, on_surface, min_dist, i_surf)
|
||||
class(Cell), intent(in) :: this
|
||||
real(C_DOUBLE), intent(in) :: xyz(3)
|
||||
real(C_DOUBLE), intent(in) :: uvw(3)
|
||||
integer(C_INT32_T), intent(in) :: on_surface
|
||||
real(C_DOUBLE), intent(out) :: min_dist
|
||||
integer(C_INT32_T), intent(out) :: i_surf
|
||||
call cell_distance_c(this % ptr, xyz, uvw, on_surface, min_dist, i_surf)
|
||||
end subroutine cell_distance
|
||||
function cell_sqrtkT(this, i) result(sqrtkT)
|
||||
class(Cell), intent(in) :: this
|
||||
integer, intent(in) :: i
|
||||
real(C_DOUBLE) :: sqrtkT
|
||||
sqrtkT = cell_sqrtkT_c(this % ptr, i)
|
||||
end function cell_sqrtkT
|
||||
|
||||
function cell_offset(this, map) result(offset)
|
||||
class(Cell), intent(in) :: this
|
||||
|
|
@ -436,12 +300,6 @@ contains
|
|||
offset = cell_offset_c(this % ptr, map)
|
||||
end function cell_offset
|
||||
|
||||
subroutine cell_to_hdf5(this, group)
|
||||
class(Cell), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: group
|
||||
call cell_to_hdf5_c(this % ptr, group)
|
||||
end subroutine cell_to_hdf5
|
||||
|
||||
!===============================================================================
|
||||
! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table
|
||||
! appears at in the model. Later, this list is used to determine the actual
|
||||
|
|
@ -470,10 +328,10 @@ contains
|
|||
if (cells(i) % material(j) == MATERIAL_VOID) cycle
|
||||
|
||||
! Get temperature of cell (rounding to nearest integer)
|
||||
if (size(cells(i) % sqrtkT) > 1) then
|
||||
temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN
|
||||
if (cells(i) % sqrtkT_size() > 1) then
|
||||
temperature = cells(i) % sqrtkT(j-1)**2 / K_BOLTZMANN
|
||||
else
|
||||
temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN
|
||||
temperature = cells(i) % sqrtkT(0)**2 / K_BOLTZMANN
|
||||
end if
|
||||
|
||||
i_material = cells(i) % material(j)
|
||||
|
|
@ -522,7 +380,6 @@ contains
|
|||
n_universes = 0
|
||||
|
||||
if (allocated(cells)) deallocate(cells)
|
||||
if (allocated(universes)) deallocate(universes)
|
||||
if (allocated(lattices)) deallocate(lattices)
|
||||
|
||||
call cell_dict % clear()
|
||||
|
|
@ -626,105 +483,4 @@ contains
|
|||
end if
|
||||
end function openmc_cell_set_id
|
||||
|
||||
|
||||
function openmc_cell_set_temperature(index, T, instance) result(err) bind(C)
|
||||
! Set the temperature of a cell
|
||||
integer(C_INT32_T), value, intent(in) :: index ! index in cells
|
||||
real(C_DOUBLE), value, intent(in) :: T ! temperature
|
||||
integer(C_INT32_T), optional, intent(in) :: instance ! cell instance
|
||||
|
||||
integer(C_INT) :: err ! error code
|
||||
integer :: j ! looping variable
|
||||
integer :: n ! number of cell instances
|
||||
integer :: material_index ! material index in materials array
|
||||
integer :: num_nuclides ! num nuclides in material
|
||||
integer :: nuclide_index ! index of nuclide in nuclides array
|
||||
real(8) :: min_temp ! min common-denominator avail temp
|
||||
real(8) :: max_temp ! max common-denominator avail temp
|
||||
real(8) :: temp ! actual temp we'll assign
|
||||
logical :: outside_low ! lower than available data
|
||||
logical :: outside_high ! higher than available data
|
||||
|
||||
outside_low = .false.
|
||||
outside_high = .false.
|
||||
|
||||
err = E_UNASSIGNED
|
||||
|
||||
if (index >= 1 .and. index <= size(cells)) then
|
||||
|
||||
! error if the cell is filled with another universe
|
||||
if (cells(index) % fill() /= C_NONE) then
|
||||
err = E_GEOMETRY
|
||||
call set_errmsg("Cannot set temperature on a cell filled &
|
||||
&with a universe.")
|
||||
else
|
||||
! find which material is associated with this cell (material_index
|
||||
! is the index into the materials array)
|
||||
if (present(instance)) then
|
||||
material_index = cells(index) % material(instance + 1)
|
||||
else
|
||||
material_index = cells(index) % material(1)
|
||||
end if
|
||||
|
||||
! number of nuclides associated with this material
|
||||
num_nuclides = size(materials(material_index) % nuclide)
|
||||
|
||||
min_temp = ZERO
|
||||
max_temp = INFINITY
|
||||
|
||||
do j = 1, num_nuclides
|
||||
nuclide_index = materials(material_index) % nuclide(j)
|
||||
min_temp = max(min_temp, minval(nuclides(nuclide_index) % kTs))
|
||||
max_temp = min(max_temp, maxval(nuclides(nuclide_index) % kTs))
|
||||
end do
|
||||
|
||||
! adjust the temperature to be within bounds if necessary
|
||||
if (K_BOLTZMANN * T < min_temp) then
|
||||
outside_low = .true.
|
||||
temp = min_temp / K_BOLTZMANN
|
||||
else if (K_BOLTZMANN * T > max_temp) then
|
||||
outside_high = .true.
|
||||
temp = max_temp / K_BOLTZMANN
|
||||
else
|
||||
temp = T
|
||||
end if
|
||||
|
||||
associate (c => cells(index))
|
||||
if (allocated(c % sqrtkT)) then
|
||||
n = size(c % sqrtkT)
|
||||
if (present(instance) .and. n > 1) then
|
||||
if (instance >= 0 .and. instance < n) then
|
||||
c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * temp)
|
||||
err = 0
|
||||
end if
|
||||
else
|
||||
c % sqrtkT(:) = sqrt(K_BOLTZMANN * temp)
|
||||
err = 0
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
|
||||
! Assign error codes for outside of temperature bounds provided the
|
||||
! temperature was changed correctly. This needs to be done after
|
||||
! changing the temperature based on the logical structure above.
|
||||
if (err == 0) then
|
||||
if (outside_low) then
|
||||
err = E_WARNING
|
||||
call set_errmsg("Nuclear data has not been loaded beyond lower &
|
||||
&bound of T=" // trim(to_str(T)) // " K.")
|
||||
else if (outside_high) then
|
||||
err = E_WARNING
|
||||
call set_errmsg("Nuclear data has not been loaded beyond upper &
|
||||
&bound of T=" // trim(to_str(T)) // " K.")
|
||||
end if
|
||||
end if
|
||||
|
||||
end if
|
||||
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in cells array is out of bounds.")
|
||||
end if
|
||||
end function openmc_cell_set_temperature
|
||||
|
||||
end module geometry_header
|
||||
|
|
|
|||
|
|
@ -910,6 +910,8 @@ using_mpio_device(hid_t obj_id)
|
|||
template<>
|
||||
const hid_t H5TypeMap<int>::type_id = H5T_NATIVE_INT;
|
||||
template<>
|
||||
const hid_t H5TypeMap<unsigned long>::type_id = H5T_NATIVE_ULONG;
|
||||
template<>
|
||||
const hid_t H5TypeMap<int64_t>::type_id = H5T_NATIVE_INT64;
|
||||
template<>
|
||||
const hid_t H5TypeMap<double>::type_id = H5T_NATIVE_DOUBLE;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ module input_xml
|
|||
use cmfd_header, only: cmfd_mesh
|
||||
use constants
|
||||
use dict_header, only: DictIntInt, DictCharInt, DictEntryCI
|
||||
use distribution_multivariate
|
||||
use distribution_univariate
|
||||
use endf, only: reaction_name
|
||||
use error, only: fatal_error, warning, write_message, openmc_err_msg
|
||||
use geometry, only: neighbor_lists
|
||||
|
|
@ -28,10 +26,9 @@ module input_xml
|
|||
use surface_header
|
||||
use set_header, only: SetChar
|
||||
use settings
|
||||
use source_header
|
||||
use stl_vector, only: VectorInt, VectorReal, VectorChar
|
||||
use string, only: to_lower, to_str, str_to_int, str_to_real, &
|
||||
starts_with, ends_with, tokenize, split_string, &
|
||||
starts_with, ends_with, split_string, &
|
||||
zero_padded, to_c_string
|
||||
use summary, only: write_summary
|
||||
use tally
|
||||
|
|
@ -51,22 +48,21 @@ module input_xml
|
|||
subroutine adjust_indices() bind(C)
|
||||
end subroutine adjust_indices
|
||||
|
||||
subroutine allocate_offset_tables(n_maps) bind(C)
|
||||
import C_INT
|
||||
integer(C_INT), intent(in), value :: n_maps
|
||||
end subroutine allocate_offset_tables
|
||||
|
||||
subroutine fill_offset_tables(target_univ_id, map) bind(C)
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT32_T), intent(in), value :: target_univ_id
|
||||
integer(C_INT), intent(in), value :: map
|
||||
end subroutine fill_offset_tables
|
||||
subroutine assign_temperatures() bind(C)
|
||||
end subroutine assign_temperatures
|
||||
|
||||
subroutine count_cell_instances(univ_indx) bind(C)
|
||||
import C_INT32_T
|
||||
integer(C_INT32_T), intent(in), value :: univ_indx
|
||||
end subroutine count_cell_instances
|
||||
|
||||
subroutine prepare_distribcell_c(cell_list, n) &
|
||||
bind(C, name="prepare_distribcell")
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT), intent(in), value :: n
|
||||
integer(C_INT32_T), intent(in) :: cell_list(n)
|
||||
end subroutine prepare_distribcell_c
|
||||
|
||||
subroutine read_surfaces(node_ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: node_ptr
|
||||
|
|
@ -102,6 +98,13 @@ module input_xml
|
|||
integer(C_INT32_T), intent(in), value :: univ
|
||||
integer(C_INT) :: n
|
||||
end function maximum_levels
|
||||
|
||||
subroutine set_particle_energy_bounds(particle, E_min, E_max) bind(C)
|
||||
import C_INT, C_DOUBLE
|
||||
integer(C_INT), value :: particle
|
||||
real(C_DOUBLE), value :: E_min
|
||||
real(C_DOUBLE), value :: E_max
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
|
@ -171,14 +174,14 @@ contains
|
|||
|
||||
! Perform some final operations to set up the geometry
|
||||
call adjust_indices()
|
||||
call count_cell_instances(root_universe-1)
|
||||
call count_cell_instances(root_universe)
|
||||
|
||||
! 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(material_temps)
|
||||
call assign_temperatures()
|
||||
|
||||
! Determine desired txemperatures for each nuclide and S(a,b) table
|
||||
call get_temperatures(nuc_temps, sab_temps)
|
||||
|
|
@ -186,7 +189,7 @@ contains
|
|||
! Check to make sure there are not too many nested coordinate levels in the
|
||||
! geometry since the coordinate list is statically allocated for performance
|
||||
! reasons
|
||||
if (maximum_levels(root_universe - 1) > MAX_COORD) then
|
||||
if (maximum_levels(root_universe) > MAX_COORD) then
|
||||
call fatal_error("Too many nested coordinate levels in the geometry. &
|
||||
&Try increasing the maximum number of coordinate levels by &
|
||||
&providing the CMake -Dmaxcoord= option.")
|
||||
|
|
@ -212,7 +215,6 @@ contains
|
|||
integer, allocatable :: temp_int_array(:)
|
||||
integer :: n_tracks
|
||||
logical :: file_exists
|
||||
character(MAX_WORD_LEN) :: type
|
||||
character(MAX_LINE_LEN) :: filename
|
||||
type(XMLDocument) :: doc
|
||||
type(XMLNode) :: root
|
||||
|
|
@ -227,7 +229,6 @@ contains
|
|||
type(XMLNode) :: node_vol
|
||||
type(XMLNode) :: node_tab_leg
|
||||
type(XMLNode), allocatable :: node_mesh_list(:)
|
||||
type(XMLNode), allocatable :: node_source_list(:)
|
||||
type(XMLNode), allocatable :: node_vol_list(:)
|
||||
|
||||
! Check if settings.xml exists
|
||||
|
|
@ -456,46 +457,13 @@ contains
|
|||
! ==========================================================================
|
||||
! EXTERNAL SOURCE
|
||||
|
||||
! Get point to list of <source> 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
|
||||
! Handled on C++ side
|
||||
|
||||
! 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)
|
||||
|
|
@ -1003,17 +971,14 @@ contains
|
|||
|
||||
subroutine read_geometry_xml()
|
||||
|
||||
integer :: i, j, k
|
||||
integer :: n, n_mats, n_rlats, n_hlats
|
||||
integer :: id
|
||||
integer :: i
|
||||
integer :: n, n_rlats, n_hlats
|
||||
integer :: univ_id
|
||||
integer :: n_cells_in_univ
|
||||
real(8) :: phi, theta, psi
|
||||
logical :: file_exists
|
||||
logical :: boundary_exists
|
||||
character(MAX_LINE_LEN) :: filename
|
||||
character(MAX_WORD_LEN), allocatable :: sarray(:)
|
||||
character(:), allocatable :: region_spec
|
||||
type(Cell), pointer :: c
|
||||
class(Lattice), pointer :: lat
|
||||
type(XMLDocument) :: doc
|
||||
|
|
@ -1023,7 +988,6 @@ contains
|
|||
type(XMLNode), allocatable :: node_cell_list(:)
|
||||
type(XMLNode), allocatable :: node_rlat_list(:)
|
||||
type(XMLNode), allocatable :: node_hlat_list(:)
|
||||
type(VectorInt) :: tokens
|
||||
type(VectorInt) :: univ_ids ! List of all universe IDs
|
||||
type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each
|
||||
! universe contains
|
||||
|
|
@ -1091,20 +1055,12 @@ contains
|
|||
! Allocate cells array
|
||||
allocate(cells(n_cells))
|
||||
|
||||
if (check_overlaps) then
|
||||
allocate(overlap_check_cnt(n_cells))
|
||||
overlap_check_cnt = 0
|
||||
end if
|
||||
|
||||
n_universes = 0
|
||||
do i = 1, n_cells
|
||||
c => cells(i)
|
||||
|
||||
c % ptr = cell_pointer(i - 1)
|
||||
|
||||
! Initialize distribcell instances and distribcell index
|
||||
c % distribcell_index = NONE
|
||||
|
||||
! Get pointer to i-th cell node
|
||||
node_cell = node_cell_list(i)
|
||||
|
||||
|
|
@ -1114,43 +1070,6 @@ contains
|
|||
// to_str(c % id()))
|
||||
end if
|
||||
|
||||
! Check for region specification (also under deprecated name surfaces)
|
||||
if (check_for_node(node_cell, "surfaces")) then
|
||||
call warning("The use of 'surfaces' is deprecated and will be &
|
||||
&disallowed in a future release. Use 'region' instead. The &
|
||||
&openmc-update-inputs utility can be used to automatically &
|
||||
&update geometry.xml files.")
|
||||
region_spec = node_value_string(node_cell, "surfaces")
|
||||
call get_node_value(node_cell, "surfaces", region_spec)
|
||||
elseif (check_for_node(node_cell, "region")) then
|
||||
region_spec = node_value_string(node_cell, "region")
|
||||
else
|
||||
region_spec = ''
|
||||
end if
|
||||
|
||||
if (len_trim(region_spec) > 0) then
|
||||
! Create surfaces array from string
|
||||
call tokenize(region_spec, tokens)
|
||||
|
||||
! Convert user IDs to surface indices
|
||||
do j = 1, tokens % size()
|
||||
id = tokens % data(j)
|
||||
if (id < OP_UNION) then
|
||||
if (surface_dict % has(abs(id))) then
|
||||
k = surface_dict % get(abs(id))
|
||||
tokens % data(j) = sign(k, id)
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
|
||||
! Copy region spec and RPN form to cell arrays
|
||||
allocate(c % region(tokens%size()))
|
||||
c % region(:) = tokens%data(1:tokens%size())
|
||||
|
||||
call tokens%clear()
|
||||
end if
|
||||
if (.not. allocated(c%region)) allocate(c%region(0))
|
||||
|
||||
! Rotation matrix
|
||||
if (check_for_node(node_cell, "rotation")) then
|
||||
! Rotations can only be applied to cells that are being filled with
|
||||
|
|
@ -1186,62 +1105,6 @@ contains
|
|||
cos(phi)*cos(theta) /), (/ 3,3 /))
|
||||
end if
|
||||
|
||||
! Translation vector
|
||||
if (check_for_node(node_cell, "translation")) then
|
||||
! Translations can only be applied to cells that are being filled with
|
||||
! another universe
|
||||
if (c % fill() == C_NONE) then
|
||||
call fatal_error("Cannot apply a translation to cell " &
|
||||
// trim(to_str(c % id())) // " because it is not filled with &
|
||||
&another universe")
|
||||
end if
|
||||
|
||||
! Read number of translation parameters
|
||||
n = node_word_count(node_cell, "translation")
|
||||
if (n /= 3) then
|
||||
call fatal_error("Incorrect number of translation parameters on &
|
||||
&cell " // to_str(c % id()))
|
||||
end if
|
||||
|
||||
! Copy translation vector
|
||||
allocate(c % translation(3))
|
||||
call get_node_array(node_cell, "translation", c % translation)
|
||||
end if
|
||||
|
||||
! Read cell temperatures. If the temperature is not specified, set it to
|
||||
! a negative number for now. During initialization we'll replace
|
||||
! negatives with the temperature from the material data.
|
||||
if (check_for_node(node_cell, "temperature")) then
|
||||
n = node_word_count(node_cell, "temperature")
|
||||
if (n > 0) then
|
||||
! Make sure this is a "normal" cell.
|
||||
if (c % fill() /= C_NONE) call fatal_error("Cell " &
|
||||
// trim(to_str(c % id())) // " was specified with a temperature &
|
||||
&but no material. Temperature specification is only valid for &
|
||||
&cells filled with a material.")
|
||||
|
||||
! Copy in temperatures
|
||||
allocate(c % sqrtkT(n))
|
||||
call get_node_array(node_cell, "temperature", c % sqrtkT)
|
||||
|
||||
! Make sure all temperatues are positive
|
||||
do j = 1, size(c % sqrtkT)
|
||||
if (c % sqrtkT(j) < ZERO) call fatal_error("Cell " &
|
||||
// trim(to_str(c % id())) // " was specified with a negative &
|
||||
&temperature. All cell temperatures must be non-negative.")
|
||||
end do
|
||||
|
||||
! Convert to sqrt(kT)
|
||||
c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:))
|
||||
else
|
||||
allocate(c % sqrtkT(1))
|
||||
c % sqrtkT(1) = -1.0
|
||||
end if
|
||||
else
|
||||
allocate(c % sqrtkT(1))
|
||||
c % sqrtkT = -1.0
|
||||
end if
|
||||
|
||||
! Add cell to dictionary
|
||||
call cell_dict % set(c % id(), i)
|
||||
|
||||
|
|
@ -1252,7 +1115,7 @@ contains
|
|||
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 universe_dict % set(univ_id, n_universes - 1)
|
||||
call univ_ids % push_back(univ_id)
|
||||
else
|
||||
n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id)
|
||||
|
|
@ -1276,11 +1139,8 @@ contains
|
|||
allocate(lattices(n_rlats + n_hlats))
|
||||
|
||||
RECT_LATTICES: do i = 1, n_rlats
|
||||
allocate(RectLattice::lattices(i) % obj)
|
||||
lat => lattices(i) % obj
|
||||
lat => lattices(i)
|
||||
lat % ptr = lattice_pointer(i - 1)
|
||||
select type(lat)
|
||||
type is (RectLattice)
|
||||
|
||||
! Get pointer to i-th lattice
|
||||
node_lat = node_rlat_list(i)
|
||||
|
|
@ -1288,15 +1148,11 @@ contains
|
|||
! Add lattice to dictionary
|
||||
call lattice_dict % set(lat % id(), i)
|
||||
|
||||
end select
|
||||
end do RECT_LATTICES
|
||||
|
||||
HEX_LATTICES: do i = 1, n_hlats
|
||||
allocate(HexLattice::lattices(n_rlats + i) % obj)
|
||||
lat => lattices(n_rlats + i) % obj
|
||||
lat => lattices(n_rlats + i)
|
||||
lat % ptr = lattice_pointer(n_rlats + i - 1)
|
||||
select type (lat)
|
||||
type is (HexLattice)
|
||||
|
||||
! Get pointer to i-th lattice
|
||||
node_lat = node_hlat_list(i)
|
||||
|
|
@ -1304,36 +1160,13 @@ contains
|
|||
! Add lattice to dictionary
|
||||
call lattice_dict % set(lat % id(), n_rlats + i)
|
||||
|
||||
end select
|
||||
end do HEX_LATTICES
|
||||
|
||||
! ==========================================================================
|
||||
! 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 = find_root_universe() + 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
|
||||
root_universe = find_root_universe()
|
||||
|
||||
! Clear dictionary
|
||||
call cells_in_univ_dict%clear()
|
||||
|
|
@ -1473,7 +1306,6 @@ contains
|
|||
character(3) :: element ! name of element, e.g. Zr
|
||||
character(MAX_WORD_LEN) :: units ! units on density
|
||||
character(MAX_LINE_LEN) :: filename ! absolute path to materials.xml
|
||||
character(MAX_LINE_LEN) :: temp_str ! temporary string when reading
|
||||
character(MAX_WORD_LEN), allocatable :: sarray(:)
|
||||
real(8) :: val ! value entered for density
|
||||
real(8) :: temp_dble ! temporary double prec. real
|
||||
|
|
@ -3479,6 +3311,8 @@ contains
|
|||
! Get the minimum and maximum energies
|
||||
energy_min(NEUTRON) = energy_bins(num_energy_groups + 1)
|
||||
energy_max(NEUTRON) = energy_bins(1)
|
||||
call set_particle_energy_bounds(NEUTRON, energy_min(NEUTRON), &
|
||||
energy_max(NEUTRON))
|
||||
|
||||
! Get the datasets present in the library
|
||||
call get_groups(file_id, names)
|
||||
|
|
@ -3639,6 +3473,8 @@ contains
|
|||
nuclides(i_nuclide) % grid(1) % energy(1))
|
||||
energy_max(NEUTRON) = min(energy_max(NEUTRON), nuclides(i_nuclide) % &
|
||||
grid(1) % energy(size(nuclides(i_nuclide) % grid(1) % energy)))
|
||||
call set_particle_energy_bounds(NEUTRON, energy_min(NEUTRON), &
|
||||
energy_max(NEUTRON))
|
||||
end if
|
||||
|
||||
! Add name and alias to dictionary
|
||||
|
|
@ -3672,6 +3508,8 @@ contains
|
|||
energy_max(PHOTON) = min(energy_max(PHOTON), &
|
||||
exp(elements(i_element) % energy(size(elements(i_element) &
|
||||
% energy))))
|
||||
call set_particle_energy_bounds(PHOTON, energy_min(PHOTON), &
|
||||
energy_max(PHOTON))
|
||||
end if
|
||||
|
||||
! Add element to set
|
||||
|
|
@ -3713,6 +3551,8 @@ contains
|
|||
if (size(ttb_e_grid) >= 1) then
|
||||
energy_min(PHOTON) = max(energy_min(PHOTON), ttb_e_grid(1))
|
||||
energy_max(PHOTON) = min(energy_max(PHOTON), ttb_e_grid(size(ttb_e_grid)))
|
||||
call set_particle_energy_bounds(PHOTON, energy_min(PHOTON), &
|
||||
energy_max(PHOTON))
|
||||
end if
|
||||
|
||||
! Take logarithm of energies since they are log-log interpolated
|
||||
|
|
@ -3793,46 +3633,6 @@ contains
|
|||
|
||||
end subroutine read_ce_cross_sections
|
||||
|
||||
!===============================================================================
|
||||
! ASSIGN_TEMPERATURES If any cells have undefined temperatures, try to find
|
||||
! their temperatures from material or global default temperatures
|
||||
!===============================================================================
|
||||
|
||||
subroutine assign_temperatures(material_temps)
|
||||
real(8), intent(in) :: material_temps(:)
|
||||
|
||||
integer :: i, j
|
||||
integer :: i_material
|
||||
|
||||
do i = 1, n_cells
|
||||
! Ignore non-normal cells and cells with defined temperature.
|
||||
if (cells(i) % fill() /= C_NONE) cycle
|
||||
if (cells(i) % sqrtkT(1) >= ZERO) cycle
|
||||
|
||||
! Set the number of temperatures equal to the number of materials.
|
||||
deallocate(cells(i) % sqrtkT)
|
||||
allocate(cells(i) % sqrtkT(cells(i) % material_size()))
|
||||
|
||||
! Check each of the cell materials for temperature data.
|
||||
do j = 1, cells(i) % material_size()
|
||||
! Arbitrarily set void regions to 0K.
|
||||
if (cells(i) % material(j) == MATERIAL_VOID) then
|
||||
cells(i) % sqrtkT(j) = ZERO
|
||||
cycle
|
||||
end if
|
||||
|
||||
! Use material default or global default temperature
|
||||
i_material = cells(i) % material(j)
|
||||
if (material_temps(i_material) >= ZERO) then
|
||||
cells(i) % sqrtkT(j) = sqrt(K_BOLTZMANN * &
|
||||
material_temps(i_material))
|
||||
else
|
||||
cells(i) % sqrtkT(j) = sqrt(K_BOLTZMANN * temperature_default)
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end subroutine assign_temperatures
|
||||
|
||||
!===============================================================================
|
||||
! READ_MULTIPOLE_DATA checks for the existence of a multipole library in the
|
||||
! directory and loads it using multipole_read
|
||||
|
|
@ -3889,9 +3689,9 @@ contains
|
|||
|
||||
subroutine prepare_distribcell()
|
||||
|
||||
integer :: i, j, k
|
||||
integer :: i, j
|
||||
type(SetInt) :: cell_list ! distribcells to track
|
||||
type(ListInt) :: univ_list ! universes containing distribcells
|
||||
integer(C_INT32_T), allocatable :: cell_list_c(:)
|
||||
|
||||
! Find all cells listed in a distribcell filter.
|
||||
do i = 1, n_tallies
|
||||
|
|
@ -3903,56 +3703,11 @@ contains
|
|||
end do
|
||||
end do
|
||||
|
||||
! Find all cells with multiple (distributed) materials or temperatures.
|
||||
do i = 1, n_cells
|
||||
if (cells(i) % material_size() > 1 .or. size(cells(i) % sqrtkT) > 1) then
|
||||
call cell_list % add(i)
|
||||
end if
|
||||
end do
|
||||
|
||||
! Make sure the number of distributed materials and temperatures matches the
|
||||
! number of respective cell instances.
|
||||
do i = 1, n_cells
|
||||
associate (c => cells(i))
|
||||
if (c % material_size() > 1) then
|
||||
if (c % material_size() /= c % n_instances()) then
|
||||
call fatal_error("Cell " // trim(to_str(c % id())) // " was &
|
||||
&specified with " // trim(to_str(c % material_size())) &
|
||||
// " materials but has " // trim(to_str(c % n_instances())) &
|
||||
// " distributed instances. The number of materials must &
|
||||
&equal one or the number of instances.")
|
||||
end if
|
||||
end if
|
||||
if (size(c % sqrtkT) > 1) then
|
||||
if (size(c % sqrtkT) /= c % n_instances()) then
|
||||
call fatal_error("Cell " // trim(to_str(c % id())) // " was &
|
||||
&specified with " // trim(to_str(size(c % sqrtkT))) &
|
||||
// " temperatures but has " // trim(to_str(c % n_instances()))&
|
||||
// " distributed instances. The number of temperatures must &
|
||||
&equal one or the number of instances.")
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
end do
|
||||
|
||||
! Search through universes for distributed cells and assign each one a
|
||||
! unique distribcell array index.
|
||||
k = 1
|
||||
do i = 1, n_universes
|
||||
do j = 1, size(universes(i) % cells)
|
||||
if (cell_list % contains(universes(i) % cells(j))) then
|
||||
cells(universes(i) % cells(j)) % distribcell_index = k
|
||||
call univ_list % append(universes(i) % id)
|
||||
k = k + 1
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
! Allocate and fill cell and lattice offset tables.
|
||||
call allocate_offset_tables(univ_list % size())
|
||||
do i = 1, univ_list % size()
|
||||
call fill_offset_tables(univ_list % get_item(i), i-1)
|
||||
allocate(cell_list_c(cell_list % size()))
|
||||
do i = 1, cell_list % size()
|
||||
cell_list_c(i) = cell_list % get_item(i) - 1
|
||||
end do
|
||||
call prepare_distribcell_c(cell_list_c, cell_list % size())
|
||||
|
||||
end subroutine prepare_distribcell
|
||||
|
||||
|
|
|
|||
406
src/lattice.cpp
406
src/lattice.cpp
|
|
@ -18,7 +18,7 @@ namespace openmc {
|
|||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<Lattice*> lattices_c;
|
||||
std::vector<Lattice*> lattices;
|
||||
|
||||
std::unordered_map<int32_t, int32_t> lattice_map;
|
||||
|
||||
|
|
@ -29,17 +29,17 @@ std::unordered_map<int32_t, int32_t> lattice_map;
|
|||
Lattice::Lattice(pugi::xml_node lat_node)
|
||||
{
|
||||
if (check_for_node(lat_node, "id")) {
|
||||
id = std::stoi(get_node_value(lat_node, "id"));
|
||||
id_ = std::stoi(get_node_value(lat_node, "id"));
|
||||
} else {
|
||||
fatal_error("Must specify id of lattice in geometry XML file.");
|
||||
}
|
||||
|
||||
if (check_for_node(lat_node, "name")) {
|
||||
name = get_node_value(lat_node, "name");
|
||||
name_ = get_node_value(lat_node, "name");
|
||||
}
|
||||
|
||||
if (check_for_node(lat_node, "outer")) {
|
||||
outer = std::stoi(get_node_value(lat_node, "outer"));
|
||||
outer_ = std::stoi(get_node_value(lat_node, "outer"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,10 +49,10 @@ LatticeIter Lattice::begin()
|
|||
{return LatticeIter(*this, 0);}
|
||||
|
||||
LatticeIter Lattice::end()
|
||||
{return LatticeIter(*this, universes.size());}
|
||||
{return LatticeIter(*this, universes_.size());}
|
||||
|
||||
ReverseLatticeIter Lattice::rbegin()
|
||||
{return ReverseLatticeIter(*this, universes.size()-1);}
|
||||
{return ReverseLatticeIter(*this, universes_.size()-1);}
|
||||
|
||||
ReverseLatticeIter Lattice::rend()
|
||||
{return ReverseLatticeIter(*this, -1);}
|
||||
|
|
@ -71,20 +71,20 @@ Lattice::adjust_indices()
|
|||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Invalid universe number " << uid << " specified on "
|
||||
"lattice " << id;
|
||||
"lattice " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the index for the outer universe.
|
||||
if (outer != NO_OUTER_UNIVERSE) {
|
||||
auto search = universe_map.find(outer);
|
||||
if (outer_ != NO_OUTER_UNIVERSE) {
|
||||
auto search = universe_map.find(outer_);
|
||||
if (search != universe_map.end()) {
|
||||
outer = search->second;
|
||||
outer_ = search->second;
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Invalid universe number " << outer << " specified on "
|
||||
"lattice " << id;
|
||||
err_msg << "Invalid universe number " << outer_ << " specified on "
|
||||
"lattice " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ int32_t
|
|||
Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map)
|
||||
{
|
||||
for (LatticeIter it = begin(); it != end(); ++it) {
|
||||
offsets[map * universes.size() + it.indx] = offset;
|
||||
offsets_[map * universes_.size() + it.indx_] = offset;
|
||||
offset += count_universe_instances(*it, target_univ_id);
|
||||
}
|
||||
return offset;
|
||||
|
|
@ -109,19 +109,19 @@ Lattice::to_hdf5(hid_t lattices_group) const
|
|||
{
|
||||
// Make a group for the lattice.
|
||||
std::string group_name {"lattice "};
|
||||
group_name += std::to_string(id);
|
||||
group_name += std::to_string(id_);
|
||||
hid_t lat_group = create_group(lattices_group, group_name);
|
||||
|
||||
// Write the name and outer universe.
|
||||
if (!name.empty()) {
|
||||
write_string(lat_group, "name", name, false);
|
||||
if (!name_.empty()) {
|
||||
write_string(lat_group, "name", name_, false);
|
||||
}
|
||||
|
||||
if (outer != NO_OUTER_UNIVERSE) {
|
||||
int32_t outer_id = global_universes[outer]->id;
|
||||
if (outer_ != NO_OUTER_UNIVERSE) {
|
||||
int32_t outer_id = universes[outer_]->id_;
|
||||
write_dataset(lat_group, "outer", outer_id);
|
||||
} else {
|
||||
write_dataset(lat_group, "outer", outer);
|
||||
write_dataset(lat_group, "outer", outer_);
|
||||
}
|
||||
|
||||
// Call subclass-overriden function to fill in other details.
|
||||
|
|
@ -137,19 +137,21 @@ Lattice::to_hdf5(hid_t lattices_group) const
|
|||
RectLattice::RectLattice(pugi::xml_node lat_node)
|
||||
: Lattice {lat_node}
|
||||
{
|
||||
type_ = LatticeType::rect;
|
||||
|
||||
// Read the number of lattice cells in each dimension.
|
||||
std::string dimension_str {get_node_value(lat_node, "dimension")};
|
||||
std::vector<std::string> dimension_words {split(dimension_str)};
|
||||
if (dimension_words.size() == 2) {
|
||||
n_cells[0] = std::stoi(dimension_words[0]);
|
||||
n_cells[1] = std::stoi(dimension_words[1]);
|
||||
n_cells[2] = 1;
|
||||
is_3d = false;
|
||||
n_cells_[0] = std::stoi(dimension_words[0]);
|
||||
n_cells_[1] = std::stoi(dimension_words[1]);
|
||||
n_cells_[2] = 1;
|
||||
is_3d_ = false;
|
||||
} else if (dimension_words.size() == 3) {
|
||||
n_cells[0] = std::stoi(dimension_words[0]);
|
||||
n_cells[1] = std::stoi(dimension_words[1]);
|
||||
n_cells[2] = std::stoi(dimension_words[2]);
|
||||
is_3d = true;
|
||||
n_cells_[0] = std::stoi(dimension_words[0]);
|
||||
n_cells_[1] = std::stoi(dimension_words[1]);
|
||||
n_cells_[2] = std::stoi(dimension_words[2]);
|
||||
is_3d_ = true;
|
||||
} else {
|
||||
fatal_error("Rectangular lattice must be two or three dimensions.");
|
||||
}
|
||||
|
|
@ -161,9 +163,9 @@ RectLattice::RectLattice(pugi::xml_node lat_node)
|
|||
fatal_error("Number of entries on <lower_left> must be the same as the "
|
||||
"number of entries on <dimension>.");
|
||||
}
|
||||
lower_left[0] = stod(ll_words[0]);
|
||||
lower_left[1] = stod(ll_words[1]);
|
||||
if (is_3d) {lower_left[2] = stod(ll_words[2]);}
|
||||
lower_left_[0] = stod(ll_words[0]);
|
||||
lower_left_[1] = stod(ll_words[1]);
|
||||
if (is_3d_) {lower_left_[2] = stod(ll_words[2]);}
|
||||
|
||||
// Read the lattice pitches.
|
||||
std::string pitch_str {get_node_value(lat_node, "pitch")};
|
||||
|
|
@ -172,9 +174,9 @@ RectLattice::RectLattice(pugi::xml_node lat_node)
|
|||
fatal_error("Number of entries on <pitch> must be the same as the "
|
||||
"number of entries on <dimension>.");
|
||||
}
|
||||
pitch[0] = stod(pitch_words[0]);
|
||||
pitch[1] = stod(pitch_words[1]);
|
||||
if (is_3d) {pitch[2] = stod(pitch_words[2]);}
|
||||
pitch_[0] = stod(pitch_words[0]);
|
||||
pitch_[1] = stod(pitch_words[1]);
|
||||
if (is_3d_) {pitch_[2] = stod(pitch_words[2]);}
|
||||
|
||||
// Read the universes and make sure the correct number was specified.
|
||||
std::string univ_str {get_node_value(lat_node, "universes")};
|
||||
|
|
@ -189,13 +191,13 @@ RectLattice::RectLattice(pugi::xml_node lat_node)
|
|||
}
|
||||
|
||||
// Parse the universes.
|
||||
universes.resize(nx*ny*nz, C_NONE);
|
||||
universes_.resize(nx*ny*nz, C_NONE);
|
||||
for (int iz = 0; iz < nz; iz++) {
|
||||
for (int iy = ny-1; iy > -1; iy--) {
|
||||
for (int ix = 0; ix < nx; ix++) {
|
||||
int indx1 = nx*ny*iz + nx*(ny-iy-1) + ix;
|
||||
int indx2 = nx*ny*iz + nx*iy + ix;
|
||||
universes[indx1] = std::stoi(univ_words[indx2]);
|
||||
universes_[indx1] = std::stoi(univ_words[indx2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -204,10 +206,10 @@ RectLattice::RectLattice(pugi::xml_node lat_node)
|
|||
//==============================================================================
|
||||
|
||||
int32_t&
|
||||
RectLattice::operator[](const int i_xyz[3])
|
||||
RectLattice::operator[](std::array<int, 3> i_xyz)
|
||||
{
|
||||
int indx = nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0];
|
||||
return universes[indx];
|
||||
return universes_[indx];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -215,15 +217,16 @@ RectLattice::operator[](const int i_xyz[3])
|
|||
bool
|
||||
RectLattice::are_valid_indices(const int i_xyz[3]) const
|
||||
{
|
||||
return ( (i_xyz[0] >= 0) && (i_xyz[0] < n_cells[0])
|
||||
&& (i_xyz[1] >= 0) && (i_xyz[1] < n_cells[1])
|
||||
&& (i_xyz[2] >= 0) && (i_xyz[2] < n_cells[2]));
|
||||
return ( (i_xyz[0] >= 0) && (i_xyz[0] < n_cells_[0])
|
||||
&& (i_xyz[1] >= 0) && (i_xyz[1] < n_cells_[1])
|
||||
&& (i_xyz[2] >= 0) && (i_xyz[2] < n_cells_[2]));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
||||
RectLattice::distance(Position r, Direction u, const std::array<int, 3>& i_xyz)
|
||||
const
|
||||
{
|
||||
// Get short aliases to the coordinates.
|
||||
double x = r.x;
|
||||
|
|
@ -231,8 +234,8 @@ RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
double z = r.z;
|
||||
|
||||
// Determine the oncoming edge.
|
||||
double x0 {copysign(0.5 * pitch[0], u.x)};
|
||||
double y0 {copysign(0.5 * pitch[1], u.y)};
|
||||
double x0 {copysign(0.5 * pitch_[0], u.x)};
|
||||
double y0 {copysign(0.5 * pitch_[1], u.y)};
|
||||
|
||||
// Left and right sides
|
||||
double d {INFTY};
|
||||
|
|
@ -260,8 +263,8 @@ RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
}
|
||||
|
||||
// Top and bottom sides
|
||||
if (is_3d) {
|
||||
double z0 {copysign(0.5 * pitch[2], u.z)};
|
||||
if (is_3d_) {
|
||||
double z0 {copysign(0.5 * pitch_[2], u.z)};
|
||||
if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) {
|
||||
double this_d = (z0 - z) / u.z;
|
||||
if (this_d < d) {
|
||||
|
|
@ -283,11 +286,11 @@ RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
std::array<int, 3>
|
||||
RectLattice::get_indices(Position r) const
|
||||
{
|
||||
int ix {static_cast<int>(std::ceil((r.x - lower_left.x) / pitch.x))-1};
|
||||
int iy {static_cast<int>(std::ceil((r.y - lower_left.y) / pitch.y))-1};
|
||||
int ix {static_cast<int>(std::ceil((r.x - lower_left_.x) / pitch_.x))-1};
|
||||
int iy {static_cast<int>(std::ceil((r.y - lower_left_.y) / pitch_.y))-1};
|
||||
int iz;
|
||||
if (is_3d) {
|
||||
iz = static_cast<int>(std::ceil((r.z - lower_left.z) / pitch.z))-1;
|
||||
if (is_3d_) {
|
||||
iz = static_cast<int>(std::ceil((r.z - lower_left_.z) / pitch_.z))-1;
|
||||
} else {
|
||||
iz = 0;
|
||||
}
|
||||
|
|
@ -297,12 +300,13 @@ RectLattice::get_indices(Position r) const
|
|||
//==============================================================================
|
||||
|
||||
Position
|
||||
RectLattice::get_local_position(Position r, const int i_xyz[3]) const
|
||||
RectLattice::get_local_position(Position r, const std::array<int, 3> i_xyz)
|
||||
const
|
||||
{
|
||||
r.x -= (lower_left.x + (i_xyz[0] + 0.5)*pitch.x);
|
||||
r.y -= (lower_left.y + (i_xyz[1] + 0.5)*pitch.y);
|
||||
if (is_3d) {
|
||||
r.z -= (lower_left.z + (i_xyz[2] + 0.5)*pitch.z);
|
||||
r.x -= (lower_left_.x + (i_xyz[0] + 0.5)*pitch_.x);
|
||||
r.y -= (lower_left_.y + (i_xyz[1] + 0.5)*pitch_.y);
|
||||
if (is_3d_) {
|
||||
r.z -= (lower_left_.z + (i_xyz[2] + 0.5)*pitch_.z);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
@ -312,7 +316,7 @@ RectLattice::get_local_position(Position r, const int i_xyz[3]) const
|
|||
int32_t&
|
||||
RectLattice::offset(int map, const int i_xyz[3])
|
||||
{
|
||||
return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]];
|
||||
return offsets_[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -326,7 +330,7 @@ RectLattice::index_to_string(int indx) const
|
|||
std::string out {std::to_string(ix)};
|
||||
out += ',';
|
||||
out += std::to_string(iy);
|
||||
if (is_3d) {
|
||||
if (is_3d_) {
|
||||
out += ',';
|
||||
out += std::to_string(iz);
|
||||
}
|
||||
|
|
@ -340,25 +344,25 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const
|
|||
{
|
||||
// Write basic lattice information.
|
||||
write_string(lat_group, "type", "rectangular", false);
|
||||
if (is_3d) {
|
||||
write_dataset(lat_group, "pitch", pitch);
|
||||
write_dataset(lat_group, "lower_left", lower_left);
|
||||
write_dataset(lat_group, "dimension", n_cells);
|
||||
if (is_3d_) {
|
||||
write_dataset(lat_group, "pitch", pitch_);
|
||||
write_dataset(lat_group, "lower_left", lower_left_);
|
||||
write_dataset(lat_group, "dimension", n_cells_);
|
||||
} else {
|
||||
std::array<double, 2> pitch_short {{pitch[0], pitch[1]}};
|
||||
std::array<double, 2> pitch_short {{pitch_[0], pitch_[1]}};
|
||||
write_dataset(lat_group, "pitch", pitch_short);
|
||||
std::array<double, 2> ll_short {{lower_left[0], lower_left[1]}};
|
||||
std::array<double, 2> ll_short {{lower_left_[0], lower_left_[1]}};
|
||||
write_dataset(lat_group, "lower_left", ll_short);
|
||||
std::array<int, 2> nc_short {{n_cells[0], n_cells[1]}};
|
||||
std::array<int, 2> nc_short {{n_cells_[0], n_cells_[1]}};
|
||||
write_dataset(lat_group, "dimension", nc_short);
|
||||
}
|
||||
|
||||
// Write the universe ids. The convention here is to switch the ordering on
|
||||
// the y-axis to match the way universes are input in a text file.
|
||||
if (is_3d) {
|
||||
hsize_t nx {static_cast<hsize_t>(n_cells[0])};
|
||||
hsize_t ny {static_cast<hsize_t>(n_cells[1])};
|
||||
hsize_t nz {static_cast<hsize_t>(n_cells[2])};
|
||||
if (is_3d_) {
|
||||
hsize_t nx {static_cast<hsize_t>(n_cells_[0])};
|
||||
hsize_t ny {static_cast<hsize_t>(n_cells_[1])};
|
||||
hsize_t nz {static_cast<hsize_t>(n_cells_[2])};
|
||||
int out[nx*ny*nz];
|
||||
|
||||
for (int m = 0; m < nz; m++) {
|
||||
|
|
@ -366,7 +370,7 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const
|
|||
for (int j = 0; j < nx; j++) {
|
||||
int indx1 = nx*ny*m + nx*k + j;
|
||||
int indx2 = nx*ny*m + nx*(ny-k-1) + j;
|
||||
out[indx2] = global_universes[universes[indx1]]->id;
|
||||
out[indx2] = universes[universes_[indx1]]->id_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -375,15 +379,15 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const
|
|||
write_int(lat_group, 3, dims, "universes", out, false);
|
||||
|
||||
} else {
|
||||
hsize_t nx {static_cast<hsize_t>(n_cells[0])};
|
||||
hsize_t ny {static_cast<hsize_t>(n_cells[1])};
|
||||
hsize_t nx {static_cast<hsize_t>(n_cells_[0])};
|
||||
hsize_t ny {static_cast<hsize_t>(n_cells_[1])};
|
||||
int out[nx*ny];
|
||||
|
||||
for (int k = 0; k < ny; k++) {
|
||||
for (int j = 0; j < nx; j++) {
|
||||
int indx1 = nx*k + j;
|
||||
int indx2 = nx*(ny-k-1) + j;
|
||||
out[indx2] = global_universes[universes[indx1]]->id;
|
||||
out[indx2] = universes[universes_[indx1]]->id_;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,52 +403,54 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const
|
|||
HexLattice::HexLattice(pugi::xml_node lat_node)
|
||||
: Lattice {lat_node}
|
||||
{
|
||||
type_ = LatticeType::hex;
|
||||
|
||||
// Read the number of lattice cells in each dimension.
|
||||
n_rings = std::stoi(get_node_value(lat_node, "n_rings"));
|
||||
n_rings_ = std::stoi(get_node_value(lat_node, "n_rings"));
|
||||
if (check_for_node(lat_node, "n_axial")) {
|
||||
n_axial = std::stoi(get_node_value(lat_node, "n_axial"));
|
||||
is_3d = true;
|
||||
n_axial_ = std::stoi(get_node_value(lat_node, "n_axial"));
|
||||
is_3d_ = true;
|
||||
} else {
|
||||
n_axial = 1;
|
||||
is_3d = false;
|
||||
n_axial_ = 1;
|
||||
is_3d_ = false;
|
||||
}
|
||||
|
||||
// Read the lattice center.
|
||||
std::string center_str {get_node_value(lat_node, "center")};
|
||||
std::vector<std::string> center_words {split(center_str)};
|
||||
if (is_3d && (center_words.size() != 3)) {
|
||||
if (is_3d_ && (center_words.size() != 3)) {
|
||||
fatal_error("A hexagonal lattice with <n_axial> must have <center> "
|
||||
"specified by 3 numbers.");
|
||||
} else if (!is_3d && center_words.size() != 2) {
|
||||
} else if (!is_3d_ && center_words.size() != 2) {
|
||||
fatal_error("A hexagonal lattice without <n_axial> must have <center> "
|
||||
"specified by 2 numbers.");
|
||||
}
|
||||
center[0] = stod(center_words[0]);
|
||||
center[1] = stod(center_words[1]);
|
||||
if (is_3d) {center[2] = stod(center_words[2]);}
|
||||
center_[0] = stod(center_words[0]);
|
||||
center_[1] = stod(center_words[1]);
|
||||
if (is_3d_) {center_[2] = stod(center_words[2]);}
|
||||
|
||||
// Read the lattice pitches.
|
||||
std::string pitch_str {get_node_value(lat_node, "pitch")};
|
||||
std::vector<std::string> pitch_words {split(pitch_str)};
|
||||
if (is_3d && (pitch_words.size() != 2)) {
|
||||
if (is_3d_ && (pitch_words.size() != 2)) {
|
||||
fatal_error("A hexagonal lattice with <n_axial> must have <pitch> "
|
||||
"specified by 2 numbers.");
|
||||
} else if (!is_3d && (pitch_words.size() != 1)) {
|
||||
} else if (!is_3d_ && (pitch_words.size() != 1)) {
|
||||
fatal_error("A hexagonal lattice without <n_axial> must have <pitch> "
|
||||
"specified by 1 number.");
|
||||
}
|
||||
pitch[0] = stod(pitch_words[0]);
|
||||
if (is_3d) {pitch[1] = stod(pitch_words[1]);}
|
||||
pitch_[0] = stod(pitch_words[0]);
|
||||
if (is_3d_) {pitch_[1] = stod(pitch_words[1]);}
|
||||
|
||||
// Read the universes and make sure the correct number was specified.
|
||||
int n_univ = (3*n_rings*n_rings - 3*n_rings + 1) * n_axial;
|
||||
int n_univ = (3*n_rings_*n_rings_ - 3*n_rings_ + 1) * n_axial_;
|
||||
std::string univ_str {get_node_value(lat_node, "universes")};
|
||||
std::vector<std::string> univ_words {split(univ_str)};
|
||||
if (univ_words.size() != n_univ) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Expected " << n_univ
|
||||
<< " universes for a hexagonal lattice with " << n_rings
|
||||
<< " rings and " << n_axial << " axial levels" << " but "
|
||||
<< " universes for a hexagonal lattice with " << n_rings_
|
||||
<< " rings and " << n_axial_ << " axial levels" << " but "
|
||||
<< univ_words.size() << " were specified.";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
|
@ -458,25 +464,25 @@ HexLattice::HexLattice(pugi::xml_node lat_node)
|
|||
// in a manner that matches the input order. Note that i_x = 0, i_a = 0
|
||||
// corresponds to the center of the hexagonal lattice.
|
||||
|
||||
universes.resize((2*n_rings-1) * (2*n_rings-1) * n_axial, C_NONE);
|
||||
universes_.resize((2*n_rings_-1) * (2*n_rings_-1) * n_axial_, C_NONE);
|
||||
int input_index = 0;
|
||||
for (int m = 0; m < n_axial; m++) {
|
||||
for (int m = 0; m < n_axial_; m++) {
|
||||
// Initialize lattice indecies.
|
||||
int i_x = 1;
|
||||
int i_a = n_rings - 1;
|
||||
int i_a = n_rings_ - 1;
|
||||
|
||||
// Map upper triangular region of hexagonal lattice which is found in the
|
||||
// first n_rings-1 rows of the input.
|
||||
for (int k = 0; k < n_rings-1; k++) {
|
||||
for (int k = 0; k < n_rings_-1; k++) {
|
||||
// Walk the index to lower-left neighbor of last row start.
|
||||
i_x -= 1;
|
||||
|
||||
// Iterate over the input columns.
|
||||
for (int j = 0; j < k+1; j++) {
|
||||
int indx = (2*n_rings-1)*(2*n_rings-1) * m
|
||||
+ (2*n_rings-1) * (i_a+n_rings-1)
|
||||
+ (i_x+n_rings-1);
|
||||
universes[indx] = std::stoi(univ_words[input_index]);
|
||||
int indx = (2*n_rings_-1)*(2*n_rings_-1) * m
|
||||
+ (2*n_rings_-1) * (i_a+n_rings_-1)
|
||||
+ (i_x+n_rings_-1);
|
||||
universes_[indx] = std::stoi(univ_words[input_index]);
|
||||
input_index++;
|
||||
// Walk the index to the right neighbor (which is not adjacent).
|
||||
i_x += 2;
|
||||
|
|
@ -490,7 +496,7 @@ HexLattice::HexLattice(pugi::xml_node lat_node)
|
|||
|
||||
// Map the middle square region of the hexagonal lattice which is found in
|
||||
// the next 2*n_rings-1 rows of the input.
|
||||
for (int k = 0; k < 2*n_rings-1; k++) {
|
||||
for (int k = 0; k < 2*n_rings_-1; k++) {
|
||||
if ((k % 2) == 0) {
|
||||
// Walk the index to the lower-left neighbor of the last row start.
|
||||
i_x -= 1;
|
||||
|
|
@ -501,11 +507,11 @@ HexLattice::HexLattice(pugi::xml_node lat_node)
|
|||
}
|
||||
|
||||
// Iterate over the input columns.
|
||||
for (int j = 0; j < n_rings - (k % 2); j++) {
|
||||
int indx = (2*n_rings-1)*(2*n_rings-1) * m
|
||||
+ (2*n_rings-1) * (i_a+n_rings-1)
|
||||
+ (i_x+n_rings-1);
|
||||
universes[indx] = std::stoi(univ_words[input_index]);
|
||||
for (int j = 0; j < n_rings_ - (k % 2); j++) {
|
||||
int indx = (2*n_rings_-1)*(2*n_rings_-1) * m
|
||||
+ (2*n_rings_-1) * (i_a+n_rings_-1)
|
||||
+ (i_x+n_rings_-1);
|
||||
universes_[indx] = std::stoi(univ_words[input_index]);
|
||||
input_index++;
|
||||
// Walk the index to the right neighbor (which is not adjacent).
|
||||
i_x += 2;
|
||||
|
|
@ -513,22 +519,22 @@ HexLattice::HexLattice(pugi::xml_node lat_node)
|
|||
}
|
||||
|
||||
// Return the lattice index to the start of the current row.
|
||||
i_x -= 2*(n_rings - (k % 2));
|
||||
i_a += n_rings - (k % 2);
|
||||
i_x -= 2*(n_rings_ - (k % 2));
|
||||
i_a += n_rings_ - (k % 2);
|
||||
}
|
||||
|
||||
// Map the lower triangular region of the hexagonal lattice.
|
||||
for (int k = 0; k < n_rings-1; k++) {
|
||||
for (int k = 0; k < n_rings_-1; k++) {
|
||||
// Walk the index to the lower-right neighbor of the last row start.
|
||||
i_x += 1;
|
||||
i_a -= 1;
|
||||
|
||||
// Iterate over the input columns.
|
||||
for (int j = 0; j < n_rings-k-1; j++) {
|
||||
int indx = (2*n_rings-1)*(2*n_rings-1) * m
|
||||
+ (2*n_rings-1) * (i_a+n_rings-1)
|
||||
+ (i_x+n_rings-1);
|
||||
universes[indx] = std::stoi(univ_words[input_index]);
|
||||
for (int j = 0; j < n_rings_-k-1; j++) {
|
||||
int indx = (2*n_rings_-1)*(2*n_rings_-1) * m
|
||||
+ (2*n_rings_-1) * (i_a+n_rings_-1)
|
||||
+ (i_x+n_rings_-1);
|
||||
universes_[indx] = std::stoi(univ_words[input_index]);
|
||||
input_index++;
|
||||
// Walk the index to the right neighbor (which is not adjacent).
|
||||
i_x += 2;
|
||||
|
|
@ -536,8 +542,8 @@ HexLattice::HexLattice(pugi::xml_node lat_node)
|
|||
}
|
||||
|
||||
// Return lattice index to start of current row.
|
||||
i_x -= 2*(n_rings - k - 1);
|
||||
i_a += n_rings - k - 1;
|
||||
i_x -= 2*(n_rings_ - k - 1);
|
||||
i_a += n_rings_ - k - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -545,21 +551,21 @@ HexLattice::HexLattice(pugi::xml_node lat_node)
|
|||
//==============================================================================
|
||||
|
||||
int32_t&
|
||||
HexLattice::operator[](const int i_xyz[3])
|
||||
HexLattice::operator[](std::array<int, 3> i_xyz)
|
||||
{
|
||||
int indx = (2*n_rings-1)*(2*n_rings-1) * i_xyz[2]
|
||||
+ (2*n_rings-1) * i_xyz[1]
|
||||
int indx = (2*n_rings_-1)*(2*n_rings_-1) * i_xyz[2]
|
||||
+ (2*n_rings_-1) * i_xyz[1]
|
||||
+ i_xyz[0];
|
||||
return universes[indx];
|
||||
return universes_[indx];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
LatticeIter HexLattice::begin()
|
||||
{return LatticeIter(*this, n_rings-1);}
|
||||
{return LatticeIter(*this, n_rings_-1);}
|
||||
|
||||
ReverseLatticeIter HexLattice::rbegin()
|
||||
{return ReverseLatticeIter(*this, universes.size()-n_rings);}
|
||||
{return ReverseLatticeIter(*this, universes_.size()-n_rings_);}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
|
|
@ -567,16 +573,17 @@ bool
|
|||
HexLattice::are_valid_indices(const int i_xyz[3]) const
|
||||
{
|
||||
return ((i_xyz[0] >= 0) && (i_xyz[1] >= 0) && (i_xyz[2] >= 0)
|
||||
&& (i_xyz[0] < 2*n_rings-1) && (i_xyz[1] < 2*n_rings-1)
|
||||
&& (i_xyz[0] + i_xyz[1] > n_rings-2)
|
||||
&& (i_xyz[0] + i_xyz[1] < 3*n_rings-2)
|
||||
&& (i_xyz[2] < n_axial));
|
||||
&& (i_xyz[0] < 2*n_rings_-1) && (i_xyz[1] < 2*n_rings_-1)
|
||||
&& (i_xyz[0] + i_xyz[1] > n_rings_-2)
|
||||
&& (i_xyz[0] + i_xyz[1] < 3*n_rings_-2)
|
||||
&& (i_xyz[2] < n_axial_));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
||||
HexLattice::distance(Position r, Direction u, const std::array<int, 3>& i_xyz)
|
||||
const
|
||||
{
|
||||
// Compute the direction on the hexagonal basis.
|
||||
double beta_dir = u.x * std::sqrt(3.0) / 2.0 + u.y / 2.0;
|
||||
|
|
@ -591,13 +598,13 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
// Upper-right and lower-left sides.
|
||||
double d {INFTY};
|
||||
std::array<int, 3> lattice_trans;
|
||||
double edge = -copysign(0.5*pitch[0], beta_dir); // Oncoming edge
|
||||
double edge = -copysign(0.5*pitch_[0], beta_dir); // Oncoming edge
|
||||
Position r_t;
|
||||
if (beta_dir > 0) {
|
||||
const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1], i_xyz[2]};
|
||||
const std::array<int, 3> i_xyz_t {i_xyz[0]+1, i_xyz[1], i_xyz[2]};
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
} else {
|
||||
const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1], i_xyz[2]};
|
||||
const std::array<int, 3> i_xyz_t {i_xyz[0]-1, i_xyz[1], i_xyz[2]};
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
}
|
||||
double beta = r_t.x * std::sqrt(3.0) / 2.0 + r_t.y / 2.0;
|
||||
|
|
@ -611,12 +618,12 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
}
|
||||
|
||||
// Lower-right and upper-left sides.
|
||||
edge = -copysign(0.5*pitch[0], gamma_dir);
|
||||
edge = -copysign(0.5*pitch_[0], gamma_dir);
|
||||
if (gamma_dir > 0) {
|
||||
const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1]-1, i_xyz[2]};
|
||||
const std::array<int, 3> i_xyz_t {i_xyz[0]+1, i_xyz[1]-1, i_xyz[2]};
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
} else {
|
||||
const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1]+1, i_xyz[2]};
|
||||
const std::array<int, 3> i_xyz_t {i_xyz[0]-1, i_xyz[1]+1, i_xyz[2]};
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
}
|
||||
double gamma = r_t.x * std::sqrt(3.0) / 2.0 - r_t.y / 2.0;
|
||||
|
|
@ -633,12 +640,12 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
}
|
||||
|
||||
// Upper and lower sides.
|
||||
edge = -copysign(0.5*pitch[0], u.y);
|
||||
edge = -copysign(0.5*pitch_[0], u.y);
|
||||
if (u.y > 0) {
|
||||
const int i_xyz_t[3] {i_xyz[0], i_xyz[1]+1, i_xyz[2]};
|
||||
const std::array<int, 3> i_xyz_t {i_xyz[0], i_xyz[1]+1, i_xyz[2]};
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
} else {
|
||||
const int i_xyz_t[3] {i_xyz[0], i_xyz[1]-1, i_xyz[2]};
|
||||
const std::array<int, 3> i_xyz_t {i_xyz[0], i_xyz[1]-1, i_xyz[2]};
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
}
|
||||
if ((std::abs(r_t.y - edge) > FP_PRECISION) && u.y != 0) {
|
||||
|
|
@ -654,9 +661,9 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
|||
}
|
||||
|
||||
// Top and bottom sides
|
||||
if (is_3d) {
|
||||
if (is_3d_) {
|
||||
double z = r.z;
|
||||
double z0 {copysign(0.5 * pitch[1], u.z)};
|
||||
double z0 {copysign(0.5 * pitch_[1], u.z)};
|
||||
if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) {
|
||||
double this_d = (z0 - z) / u.z;
|
||||
if (this_d < d) {
|
||||
|
|
@ -680,13 +687,13 @@ std::array<int, 3>
|
|||
HexLattice::get_indices(Position r) const
|
||||
{
|
||||
// Offset the xyz by the lattice center.
|
||||
Position r_o {r.x - center.x, r.y - center.y, r.z};
|
||||
if (is_3d) {r_o.z -= center.z;}
|
||||
Position r_o {r.x - center_.x, r.y - center_.y, r.z};
|
||||
if (is_3d_) {r_o.z -= center_.z;}
|
||||
|
||||
// Index the z direction.
|
||||
std::array<int, 3> out;
|
||||
if (is_3d) {
|
||||
out[2] = static_cast<int>(std::ceil(r_o.z / pitch[1] + 0.5 * n_axial))-1;
|
||||
if (is_3d_) {
|
||||
out[2] = static_cast<int>(std::ceil(r_o.z / pitch_[1] + 0.5 * n_axial_))-1;
|
||||
} else {
|
||||
out[2] = 0;
|
||||
}
|
||||
|
|
@ -695,13 +702,13 @@ HexLattice::get_indices(Position r) const
|
|||
// find the index of the global coordinates to within 4 cells.
|
||||
double alpha = r_o.y - r_o.x / std::sqrt(3.0);
|
||||
out[0] = static_cast<int>(std::floor(r_o.x
|
||||
/ (0.5*std::sqrt(3.0) * pitch[0])));
|
||||
out[1] = static_cast<int>(std::floor(alpha / pitch[0]));
|
||||
/ (0.5*std::sqrt(3.0) * pitch_[0])));
|
||||
out[1] = static_cast<int>(std::floor(alpha / pitch_[0]));
|
||||
|
||||
// Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but
|
||||
// the array is offset so that the indices never go below 0).
|
||||
out[0] += n_rings-1;
|
||||
out[1] += n_rings-1;
|
||||
out[0] += n_rings_-1;
|
||||
out[1] += n_rings_-1;
|
||||
|
||||
// Calculate the (squared) distance between the particle and the centers of
|
||||
// the four possible cells. Regular hexagonal tiles form a Voronoi
|
||||
|
|
@ -715,7 +722,7 @@ HexLattice::get_indices(Position r) const
|
|||
double d_min {INFTY};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int i_xyz[3] {out[0] + j, out[1] + i, 0};
|
||||
const std::array<int, 3> i_xyz {out[0] + j, out[1] + i, 0};
|
||||
Position r_t = get_local_position(r, i_xyz);
|
||||
double d = r_t.x*r_t.x + r_t.y*r_t.y;
|
||||
if (d < d_min) {
|
||||
|
|
@ -743,15 +750,16 @@ HexLattice::get_indices(Position r) const
|
|||
//==============================================================================
|
||||
|
||||
Position
|
||||
HexLattice::get_local_position(Position r, const int i_xyz[3]) const
|
||||
HexLattice::get_local_position(Position r, const std::array<int, 3> i_xyz)
|
||||
const
|
||||
{
|
||||
// x_l = x_g - (center + pitch_x*cos(30)*index_x)
|
||||
r.x -= (center.x + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings + 1) * pitch[0]);
|
||||
r.x -= center_.x + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings_ + 1) * pitch_[0];
|
||||
// y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y)
|
||||
r.y -= (center.y + (i_xyz[1] - n_rings + 1) * pitch[0]
|
||||
+ (i_xyz[0] - n_rings + 1) * pitch[0] / 2.0);
|
||||
if (is_3d) {
|
||||
r.z -= center.z - (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1];
|
||||
r.y -= (center_.y + (i_xyz[1] - n_rings_ + 1) * pitch_[0]
|
||||
+ (i_xyz[0] - n_rings_ + 1) * pitch_[0] / 2.0);
|
||||
if (is_3d_) {
|
||||
r.z -= center_.z - (0.5 * n_axial_ - i_xyz[2] - 0.5) * pitch_[1];
|
||||
}
|
||||
|
||||
return r;
|
||||
|
|
@ -762,9 +770,9 @@ HexLattice::get_local_position(Position r, const int i_xyz[3]) const
|
|||
bool
|
||||
HexLattice::is_valid_index(int indx) const
|
||||
{
|
||||
int nx {2*n_rings - 1};
|
||||
int ny {2*n_rings - 1};
|
||||
int nz {n_axial};
|
||||
int nx {2*n_rings_ - 1};
|
||||
int ny {2*n_rings_ - 1};
|
||||
int nz {n_axial_};
|
||||
int iz = indx / (nx * ny);
|
||||
int iy = (indx - nx*ny*iz) / nx;
|
||||
int ix = indx - nx*ny*iz - nx*iy;
|
||||
|
|
@ -777,10 +785,10 @@ HexLattice::is_valid_index(int indx) const
|
|||
int32_t&
|
||||
HexLattice::offset(int map, const int i_xyz[3])
|
||||
{
|
||||
int nx {2*n_rings - 1};
|
||||
int ny {2*n_rings - 1};
|
||||
int nz {n_axial};
|
||||
return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]];
|
||||
int nx {2*n_rings_ - 1};
|
||||
int ny {2*n_rings_ - 1};
|
||||
int nz {n_axial_};
|
||||
return offsets_[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -788,15 +796,15 @@ HexLattice::offset(int map, const int i_xyz[3])
|
|||
std::string
|
||||
HexLattice::index_to_string(int indx) const
|
||||
{
|
||||
int nx {2*n_rings - 1};
|
||||
int ny {2*n_rings - 1};
|
||||
int nx {2*n_rings_ - 1};
|
||||
int ny {2*n_rings_ - 1};
|
||||
int iz {indx / (nx * ny)};
|
||||
int iy {(indx - nx * ny * iz) / nx};
|
||||
int ix {indx - nx * ny * iz - nx * iy};
|
||||
std::string out {std::to_string(ix - n_rings + 1)};
|
||||
std::string out {std::to_string(ix - n_rings_ + 1)};
|
||||
out += ',';
|
||||
out += std::to_string(iy - n_rings + 1);
|
||||
if (is_3d) {
|
||||
out += std::to_string(iy - n_rings_ + 1);
|
||||
if (is_3d_) {
|
||||
out += ',';
|
||||
out += std::to_string(iz);
|
||||
}
|
||||
|
|
@ -810,36 +818,36 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const
|
|||
{
|
||||
// Write basic lattice information.
|
||||
write_string(lat_group, "type", "hexagonal", false);
|
||||
write_dataset(lat_group, "n_rings", n_rings);
|
||||
write_dataset(lat_group, "n_axial", n_axial);
|
||||
if (is_3d) {
|
||||
write_dataset(lat_group, "pitch", pitch);
|
||||
write_dataset(lat_group, "center", center);
|
||||
write_dataset(lat_group, "n_rings", n_rings_);
|
||||
write_dataset(lat_group, "n_axial", n_axial_);
|
||||
if (is_3d_) {
|
||||
write_dataset(lat_group, "pitch", pitch_);
|
||||
write_dataset(lat_group, "center", center_);
|
||||
} else {
|
||||
std::array<double, 1> pitch_short {{pitch[0]}};
|
||||
std::array<double, 1> pitch_short {{pitch_[0]}};
|
||||
write_dataset(lat_group, "pitch", pitch_short);
|
||||
std::array<double, 2> center_short {{center[0], center[1]}};
|
||||
std::array<double, 2> center_short {{center_[0], center_[1]}};
|
||||
write_dataset(lat_group, "center", center_short);
|
||||
}
|
||||
|
||||
// Write the universe ids.
|
||||
hsize_t nx {static_cast<hsize_t>(2*n_rings - 1)};
|
||||
hsize_t ny {static_cast<hsize_t>(2*n_rings - 1)};
|
||||
hsize_t nz {static_cast<hsize_t>(n_axial)};
|
||||
hsize_t nx {static_cast<hsize_t>(2*n_rings_ - 1)};
|
||||
hsize_t ny {static_cast<hsize_t>(2*n_rings_ - 1)};
|
||||
hsize_t nz {static_cast<hsize_t>(n_axial_)};
|
||||
int out[nx*ny*nz];
|
||||
|
||||
for (int m = 0; m < nz; m++) {
|
||||
for (int k = 0; k < ny; k++) {
|
||||
for (int j = 0; j < nx; j++) {
|
||||
int indx = nx*ny*m + nx*k + j;
|
||||
if (j + k < n_rings - 1) {
|
||||
if (j + k < n_rings_ - 1) {
|
||||
// This array position is never used; put a -1 to indicate this.
|
||||
out[indx] = -1;
|
||||
} else if (j + k > 3*n_rings - 3) {
|
||||
} else if (j + k > 3*n_rings_ - 3) {
|
||||
// This array position is never used; put a -1 to indicate this.
|
||||
out[indx] = -1;
|
||||
} else {
|
||||
out[indx] = global_universes[universes[indx]]->id;
|
||||
out[indx] = universes[universes_[indx]]->id_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -857,15 +865,15 @@ extern "C" void
|
|||
read_lattices(pugi::xml_node *node)
|
||||
{
|
||||
for (pugi::xml_node lat_node : node->children("lattice")) {
|
||||
lattices_c.push_back(new RectLattice(lat_node));
|
||||
lattices.push_back(new RectLattice(lat_node));
|
||||
}
|
||||
for (pugi::xml_node lat_node : node->children("hex_lattice")) {
|
||||
lattices_c.push_back(new HexLattice(lat_node));
|
||||
lattices.push_back(new HexLattice(lat_node));
|
||||
}
|
||||
|
||||
// Fill the lattice map.
|
||||
for (int i_lat = 0; i_lat < lattices_c.size(); i_lat++) {
|
||||
int id = lattices_c[i_lat]->id;
|
||||
for (int i_lat = 0; i_lat < lattices.size(); i_lat++) {
|
||||
int id = lattices[i_lat]->id_;
|
||||
auto in_map = lattice_map.find(id);
|
||||
if (in_map == lattice_map.end()) {
|
||||
lattice_map[id] = i_lat;
|
||||
|
|
@ -882,53 +890,15 @@ read_lattices(pugi::xml_node *node)
|
|||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
Lattice* lattice_pointer(int lat_ind) {return lattices_c[lat_ind];}
|
||||
Lattice* lattice_pointer(int lat_ind) {return lattices[lat_ind];}
|
||||
|
||||
int32_t lattice_id(Lattice *lat) {return lat->id;}
|
||||
int32_t lattice_id(Lattice *lat) {return lat->id_;}
|
||||
|
||||
bool lattice_are_valid_indices(Lattice *lat, const int i_xyz[3])
|
||||
{return lat->are_valid_indices(i_xyz);}
|
||||
|
||||
void lattice_distance(Lattice *lat, const double xyz[3], const double uvw[3],
|
||||
const int i_xyz[3], double *d, int lattice_trans[3])
|
||||
{
|
||||
Position r {xyz};
|
||||
Direction u {uvw};
|
||||
std::pair<double, std::array<int, 3>> ld {lat->distance(r, u, i_xyz)};
|
||||
*d = ld.first;
|
||||
lattice_trans[0] = ld.second[0];
|
||||
lattice_trans[1] = ld.second[1];
|
||||
lattice_trans[2] = ld.second[2];
|
||||
}
|
||||
|
||||
void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3])
|
||||
{
|
||||
Position r {xyz};
|
||||
std::array<int, 3> inds = lat->get_indices(r);
|
||||
i_xyz[0] = inds[0];
|
||||
i_xyz[1] = inds[1];
|
||||
i_xyz[2] = inds[2];
|
||||
}
|
||||
|
||||
void lattice_get_local_xyz(Lattice *lat, const double global_xyz[3],
|
||||
const int i_xyz[3], double local_xyz[3])
|
||||
{
|
||||
Position global {global_xyz};
|
||||
Position local = lat->get_local_position(global, i_xyz);
|
||||
local_xyz[0] = local.x;
|
||||
local_xyz[1] = local.y;
|
||||
local_xyz[2] = local.z;
|
||||
}
|
||||
|
||||
int32_t lattice_offset(Lattice *lat, int map, const int i_xyz[3])
|
||||
{return lat->offset(map, i_xyz);}
|
||||
|
||||
int32_t lattice_outer(Lattice *lat) {return lat->outer;}
|
||||
|
||||
void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);}
|
||||
|
||||
int32_t lattice_universe(Lattice *lat, const int i_xyz[3])
|
||||
{return (*lat)[i_xyz];}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace openmc {
|
|||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<Material*> global_materials;
|
||||
std::vector<Material*> materials;
|
||||
std::unordered_map<int32_t, int32_t> material_map;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -28,6 +28,10 @@ Material::Material(pugi::xml_node node)
|
|||
fatal_error("Must specify id of material in materials XML file.");
|
||||
}
|
||||
|
||||
if (check_for_node(node, "temperature")) {
|
||||
temperature_ = std::stod(get_node_value(node, "temperature"));
|
||||
}
|
||||
|
||||
if (check_for_node(node, "volume")) {
|
||||
volume_ = std::stod(get_node_value(node, "volume"));
|
||||
}
|
||||
|
|
@ -42,13 +46,13 @@ read_materials(pugi::xml_node* node)
|
|||
{
|
||||
// Loop over XML material elements and populate the array.
|
||||
for (pugi::xml_node material_node : node->children("material")) {
|
||||
global_materials.push_back(new Material(material_node));
|
||||
materials.push_back(new Material(material_node));
|
||||
}
|
||||
global_materials.shrink_to_fit();
|
||||
materials.shrink_to_fit();
|
||||
|
||||
// Populate the material map.
|
||||
for (int i = 0; i < global_materials.size(); i++) {
|
||||
int32_t mid = global_materials[i]->id;
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
int32_t mid = materials[i]->id;
|
||||
auto search = material_map.find(mid);
|
||||
if (search == material_map.end()) {
|
||||
material_map[mid] = i;
|
||||
|
|
@ -67,8 +71,8 @@ read_materials(pugi::xml_node* node)
|
|||
extern "C" int
|
||||
openmc_material_get_volume(int32_t index, double* volume)
|
||||
{
|
||||
if (index >= 1 && index <= global_materials.size()) {
|
||||
Material* m = global_materials[index - 1];
|
||||
if (index >= 1 && index <= materials.size()) {
|
||||
Material* m = materials[index - 1];
|
||||
if (m->volume_ >= 0.0) {
|
||||
*volume = m->volume_;
|
||||
return 0;
|
||||
|
|
@ -87,8 +91,8 @@ openmc_material_get_volume(int32_t index, double* volume)
|
|||
extern "C" int
|
||||
openmc_material_set_volume(int32_t index, double volume)
|
||||
{
|
||||
if (index >= 1 && index <= global_materials.size()) {
|
||||
Material* m = global_materials[index - 1];
|
||||
if (index >= 1 && index <= materials.size()) {
|
||||
Material* m = materials[index - 1];
|
||||
if (volume >= 0.0) {
|
||||
m->volume_ = volume;
|
||||
return 0;
|
||||
|
|
@ -107,7 +111,7 @@ openmc_material_set_volume(int32_t index, double volume)
|
|||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
Material* material_pointer(int32_t indx) {return global_materials[indx];}
|
||||
Material* material_pointer(int32_t indx) {return materials[indx];}
|
||||
|
||||
int32_t material_id(Material* mat) {return mat->id;}
|
||||
|
||||
|
|
@ -120,16 +124,16 @@ extern "C" {
|
|||
|
||||
void extend_materials_c(int32_t n)
|
||||
{
|
||||
global_materials.reserve(global_materials.size() + n);
|
||||
materials.reserve(materials.size() + n);
|
||||
for (int32_t i = 0; i < n; i++) {
|
||||
global_materials.push_back(new Material());
|
||||
materials.push_back(new Material());
|
||||
}
|
||||
}
|
||||
|
||||
void free_memory_material_c()
|
||||
{
|
||||
for (Material *mat : global_materials) {delete mat;}
|
||||
global_materials.clear();
|
||||
for (Material *mat : materials) {delete mat;}
|
||||
materials.clear();
|
||||
material_map.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -678,6 +678,22 @@ contains
|
|||
end function openmc_material_get_id
|
||||
|
||||
|
||||
function openmc_material_get_fissionable(index, fissionable) result(err) bind(C)
|
||||
! returns whether a material is fissionable
|
||||
integer(C_INT32_T), value :: index
|
||||
logical(C_BOOL), intent(out) :: fissionable
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= size(materials)) then
|
||||
fissionable = materials(index) % fissionable
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
end function openmc_material_get_fissionable
|
||||
|
||||
|
||||
function openmc_material_set_id(index, id) result(err) bind(C)
|
||||
! Set the ID of a material
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
|
|
|
|||
|
|
@ -160,10 +160,10 @@ contains
|
|||
if (cells(i) % material(j) == MATERIAL_VOID) cycle
|
||||
|
||||
! Get temperature of cell (rounding to nearest integer)
|
||||
if (size(cells(i) % sqrtkT) > 1) then
|
||||
kT = cells(i) % sqrtkT(j)**2
|
||||
if (cells(i) % sqrtkT_size() > 1) then
|
||||
kT = cells(i) % sqrtkT(j-1)**2
|
||||
else
|
||||
kT = cells(i) % sqrtkT(1)**2
|
||||
kT = cells(i) % sqrtkT(0)**2
|
||||
end if
|
||||
|
||||
i_material = cells(i) % material(j)
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ module mgxs_interface
|
|||
end interface
|
||||
|
||||
! Number of energy groups
|
||||
integer(C_INT) :: num_energy_groups
|
||||
integer(C_INT), bind(C) :: num_energy_groups
|
||||
|
||||
! Number of delayed groups
|
||||
integer(C_INT) :: num_delayed_groups
|
||||
|
|
@ -159,6 +159,13 @@ module mgxs_interface
|
|||
real(8), allocatable :: energy_bin_avg(:)
|
||||
|
||||
! Energy group structure with increasing energy
|
||||
real(8), allocatable :: rev_energy_bins(:)
|
||||
real(C_DOUBLE), allocatable, target :: rev_energy_bins(:)
|
||||
|
||||
end module mgxs_interface
|
||||
contains
|
||||
|
||||
function rev_energy_bins_ptr() result(ptr) bind(C)
|
||||
type(C_PTR) :: ptr
|
||||
ptr = C_LOC(rev_energy_bins(1))
|
||||
end function
|
||||
|
||||
end module mgxs_interface
|
||||
|
|
|
|||
23
src/nuclide.cpp
Normal file
23
src/nuclide.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include "openmc/nuclide.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::array<double, 2> energy_min {0.0, 0.0};
|
||||
std::array<double, 2> energy_max {INFTY, INFTY};
|
||||
|
||||
//==============================================================================
|
||||
// Fortran compatibility functions
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
set_particle_energy_bounds(int particle, double E_min, double E_max)
|
||||
{
|
||||
energy_min[particle - 1] = E_min;
|
||||
energy_max[particle - 1] = E_max;
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -211,7 +211,6 @@ contains
|
|||
|
||||
integer :: i ! index for coordinate levels
|
||||
type(Cell), pointer :: c
|
||||
type(Universe), pointer :: u
|
||||
class(Lattice), pointer :: l
|
||||
|
||||
! display type of particle
|
||||
|
|
@ -232,20 +231,20 @@ contains
|
|||
write(ou,*) ' Level ' // trim(to_str(i - 1))
|
||||
|
||||
! Print cell for this level
|
||||
if (p % coord(i) % cell /= NONE) then
|
||||
c => cells(p % coord(i) % cell)
|
||||
if (p % coord(i) % cell /= C_NONE) then
|
||||
c => cells(p % coord(i) % cell + 1)
|
||||
write(ou,*) ' Cell = ' // trim(to_str(c % id()))
|
||||
end if
|
||||
|
||||
! Print universe for this level
|
||||
if (p % coord(i) % universe /= NONE) then
|
||||
u => universes(p % coord(i) % universe)
|
||||
write(ou,*) ' Universe = ' // trim(to_str(u % id))
|
||||
write(ou,*) ' Universe = ' &
|
||||
// trim(to_str(universe_id(p % coord(i) % universe)))
|
||||
end if
|
||||
|
||||
! Print information on lattice
|
||||
if (p % coord(i) % lattice /= NONE) then
|
||||
l => lattices(p % coord(i) % lattice) % obj
|
||||
l => lattices(p % coord(i) % lattice)
|
||||
write(ou,*) ' Lattice = ' // trim(to_str(l % id()))
|
||||
write(ou,*) ' Lattice position = (' // trim(to_str(&
|
||||
p % coord(i) % lattice_x)) // ',' // trim(to_str(&
|
||||
|
|
@ -622,42 +621,6 @@ contains
|
|||
|
||||
end subroutine print_results
|
||||
|
||||
!===============================================================================
|
||||
! PRINT_OVERLAP_DEBUG displays information regarding overlap checking results
|
||||
!===============================================================================
|
||||
|
||||
subroutine print_overlap_check
|
||||
|
||||
integer :: i, j
|
||||
integer :: num_sparse = 0
|
||||
|
||||
! display header block for geometry debugging section
|
||||
call header("Cell Overlap Check Summary", 1)
|
||||
|
||||
write(ou,100) 'Cell ID','No. Overlap Checks'
|
||||
|
||||
do i = 1, n_cells
|
||||
write(ou,101) cells(i) % id(), overlap_check_cnt(i)
|
||||
if (overlap_check_cnt(i) < 10) num_sparse = num_sparse + 1
|
||||
end do
|
||||
write(ou,*)
|
||||
write(ou,'(1X,A)') 'There were ' // trim(to_str(num_sparse)) // &
|
||||
' cells with less than 10 overlap checks'
|
||||
j = 0
|
||||
do i = 1, n_cells
|
||||
if (overlap_check_cnt(i) < 10) then
|
||||
j = j + 1
|
||||
write(ou,'(1X,A8)', advance='no') trim(to_str(cells(i) % id()))
|
||||
if (modulo(j,8) == 0) write(ou,*)
|
||||
end if
|
||||
end do
|
||||
write(ou,*)
|
||||
|
||||
100 format (1X,A,T15,A)
|
||||
101 format (1X,I8,T15,I12)
|
||||
|
||||
end subroutine print_overlap_check
|
||||
|
||||
!===============================================================================
|
||||
! WRITE_TALLIES creates an output file and writes out the mean values of all
|
||||
! tallies and their standard deviations
|
||||
|
|
|
|||
75
src/output.cpp
Normal file
75
src/output.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#include "openmc/output.h"
|
||||
|
||||
#include <algorithm> // for std::transform
|
||||
#include <cstring> // for strlen
|
||||
#include <iomanip> // for setw
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "openmc/cell.h"
|
||||
#include "openmc/geometry.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/settings.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
void
|
||||
header(const char* msg, int level) {
|
||||
// Determine how many times to repeat the '=' character.
|
||||
int n_prefix = (63 - strlen(msg)) / 2;
|
||||
int n_suffix = n_prefix;
|
||||
if ((strlen(msg) % 2) == 0) ++n_suffix;
|
||||
|
||||
// Convert to uppercase.
|
||||
std::string upper(msg);
|
||||
std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
|
||||
|
||||
// Add ===> <=== markers.
|
||||
std::stringstream out;
|
||||
out << ' ';
|
||||
for (int i = 0; i < n_prefix; i++) out << '=';
|
||||
out << "> " << upper << " <";
|
||||
for (int i = 0; i < n_suffix; i++) out << '=';
|
||||
|
||||
// Print header based on verbosity level.
|
||||
if (openmc_verbosity >= level) {
|
||||
std::cout << out.str() << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
print_overlap_check() {
|
||||
#ifdef OPENMC_MPI
|
||||
std::vector<int64_t> temp(overlap_check_count);
|
||||
int err = MPI_Reduce(temp.data(), overlap_check_count.data(),
|
||||
overlap_check_count.size(), MPI_INT64_T, MPI_SUM, 0,
|
||||
mpi::intracomm);
|
||||
#endif
|
||||
|
||||
if (openmc_master) {
|
||||
header("cell overlap check summary", 1);
|
||||
std::cout << " Cell ID No. Overlap Checks\n";
|
||||
|
||||
std::vector<int32_t> sparse_cell_ids;
|
||||
for (int i = 0; i < n_cells; i++) {
|
||||
std::cout << " " << std::setw(8) << cells[i]->id_ << std::setw(17)
|
||||
<< overlap_check_count[i] << "\n";
|
||||
if (overlap_check_count[i] < 10) {
|
||||
sparse_cell_ids.push_back(cells[i]->id_);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n There were " << sparse_cell_ids.size()
|
||||
<< " cells with less than 10 overlap checks\n";
|
||||
for (auto id : sparse_cell_ids) {
|
||||
std::cout << " " << id;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -19,8 +19,8 @@ namespace openmc {
|
|||
void
|
||||
LocalCoord::reset()
|
||||
{
|
||||
cell = 0;
|
||||
universe = 0;
|
||||
cell = C_NONE;
|
||||
universe = C_NONE;
|
||||
lattice = 0;
|
||||
lattice_x = 0;
|
||||
lattice_y = 0;
|
||||
|
|
@ -67,7 +67,7 @@ Particle::initialize()
|
|||
|
||||
// clear attributes
|
||||
surface = 0;
|
||||
cell_born = 0;
|
||||
cell_born = C_NONE;
|
||||
material = 0;
|
||||
last_material = 0;
|
||||
last_sqrtkT = 0;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ contains
|
|||
else
|
||||
if (pl % color_by == PLOT_COLOR_MATS) then
|
||||
! Assign color based on material
|
||||
associate (c => cells(p % coord(j) % cell))
|
||||
associate (c => cells(p % coord(j) % cell + 1))
|
||||
if (c % type() == FILL_UNIVERSE) then
|
||||
! If we stopped on a middle universe level, treat as if not found
|
||||
rgb = pl % not_found % rgb
|
||||
|
|
@ -100,8 +100,8 @@ contains
|
|||
end associate
|
||||
else if (pl % color_by == PLOT_COLOR_CELLS) then
|
||||
! Assign color based on cell
|
||||
rgb = pl % colors(p % coord(j) % cell) % rgb
|
||||
id = cells(p % coord(j) % cell) % id()
|
||||
rgb = pl % colors(p % coord(j) % cell + 1) % rgb
|
||||
id = cells(p % coord(j) % cell + 1) % id()
|
||||
else
|
||||
rgb = 0
|
||||
id = -1
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module settings
|
|||
|
||||
! ============================================================================
|
||||
! ENERGY TREATMENT RELATED VARIABLES
|
||||
logical(C_BOOL) :: run_CE = .true. ! Run in CE mode?
|
||||
logical(C_BOOL), bind(C, name='openmc_run_CE') :: run_CE = .true. ! Run in CE mode?
|
||||
|
||||
! ============================================================================
|
||||
! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES
|
||||
|
|
@ -21,12 +21,12 @@ module settings
|
|||
integer(C_INT) :: temperature_method = TEMPERATURE_NEAREST
|
||||
logical :: temperature_multipole = .false.
|
||||
real(C_DOUBLE) :: temperature_tolerance = 10.0_8
|
||||
real(8) :: temperature_default = 293.6_8
|
||||
real(C_DOUBLE) :: temperature_default = 293.6_8
|
||||
real(8) :: temperature_range(2) = [ZERO, ZERO]
|
||||
|
||||
integer :: n_log_bins ! number of bins for logarithmic grid
|
||||
|
||||
logical :: photon_transport = .false.
|
||||
logical(C_BOOL), bind(C, name='openmc_photon_transport') :: photon_transport = .false.
|
||||
integer :: electron_treatment = ELECTRON_TTB
|
||||
|
||||
! ============================================================================
|
||||
|
|
@ -104,7 +104,8 @@ module settings
|
|||
particle_restart_run = .false.
|
||||
|
||||
! Write out initial source
|
||||
logical :: write_initial_source = .false.
|
||||
logical(C_BOOL), bind(C, name='openmc_write_initial_source') :: &
|
||||
write_initial_source = .false.
|
||||
|
||||
! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE
|
||||
logical :: create_fission_neutrons = .true.
|
||||
|
|
@ -120,7 +121,6 @@ module settings
|
|||
character(MAX_FILE_LEN) :: path_input ! Path to input file
|
||||
character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml
|
||||
character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library
|
||||
character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source
|
||||
character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point
|
||||
character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point
|
||||
character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/distribution.h"
|
||||
#include "openmc/distribution_multi.h"
|
||||
#include "openmc/distribution_spatial.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/string_utils.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
|
|
@ -98,6 +102,24 @@ void read_settings(pugi::xml_node* root)
|
|||
temperature_range[0] = range[0];
|
||||
temperature_range[1] = range[1];
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// EXTERNAL SOURCE
|
||||
|
||||
// Get point to list of <source> elements and make sure there is at least one
|
||||
for (pugi::xml_node node : root->children("source")) {
|
||||
external_sources.emplace_back(node);
|
||||
}
|
||||
|
||||
// If no source specified, default to isotropic point source at origin with Watt spectrum
|
||||
if (external_sources.empty()) {
|
||||
SourceDistribution source {
|
||||
UPtrSpace{new SpatialPoint({0.0, 0.0, 0.0})},
|
||||
UPtrAngle{new Isotropic()},
|
||||
UPtrDist{new Watt(0.988, 2.249e-6)}
|
||||
};
|
||||
external_sources.push_back(std::move(source));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -24,13 +24,12 @@ module simulation
|
|||
use nuclide_header, only: micro_xs, n_nuclides
|
||||
use output, only: header, print_columns, &
|
||||
print_batch_keff, print_generation, print_runtime, &
|
||||
print_results, print_overlap_check, write_tallies
|
||||
print_results, write_tallies
|
||||
use particle_header
|
||||
use photon_header, only: micro_photon_xs, n_elements
|
||||
use random_lcg, only: set_particle_seed
|
||||
use settings
|
||||
use simulation_header
|
||||
use source, only: initialize_source, sample_external_source
|
||||
use state_point, only: openmc_statepoint_write, write_source_point, load_state_point
|
||||
use string, only: to_str
|
||||
use tally, only: accumulate_tallies, setup_active_tallies, &
|
||||
|
|
@ -52,6 +51,19 @@ module simulation
|
|||
integer(C_INT), parameter :: STATUS_EXIT_MAX_BATCH = 1
|
||||
integer(C_INT), parameter :: STATUS_EXIT_ON_TRIGGER = 2
|
||||
|
||||
interface
|
||||
subroutine openmc_simulation_init_c() bind(C)
|
||||
end subroutine
|
||||
|
||||
subroutine initialize_source() bind(C)
|
||||
end subroutine
|
||||
|
||||
function sample_external_source() result(site) bind(C)
|
||||
import Bank
|
||||
type(Bank) :: site
|
||||
end function
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -241,7 +253,10 @@ contains
|
|||
|
||||
subroutine finalize_generation()
|
||||
|
||||
integer(8) :: i
|
||||
interface
|
||||
subroutine fill_source_bank_fixedsource() bind(C)
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
! Update global tallies with the omp private accumulation variables
|
||||
!$omp parallel
|
||||
|
|
@ -294,13 +309,7 @@ contains
|
|||
|
||||
elseif (run_mode == MODE_FIXEDSOURCE) then
|
||||
! For fixed-source mode, we need to sample the external source
|
||||
if (path_source == '') then
|
||||
do i = 1, work
|
||||
call set_particle_seed((total_gen + overall_generation()) * &
|
||||
n_particles + work_index(rank) + i)
|
||||
call sample_external_source(source_bank(i))
|
||||
end do
|
||||
end if
|
||||
call fill_source_bank_fixedsource()
|
||||
end if
|
||||
|
||||
end subroutine finalize_generation
|
||||
|
|
@ -425,6 +434,9 @@ contains
|
|||
! Skip if simulation has already been initialized
|
||||
if (simulation_initialized) return
|
||||
|
||||
! Call initialization on C++ side
|
||||
call openmc_simulation_init_c()
|
||||
|
||||
! Set up tally procedure pointers
|
||||
call init_tally_routines()
|
||||
|
||||
|
|
@ -511,7 +523,6 @@ contains
|
|||
integer :: n ! size of arrays
|
||||
integer :: mpi_err ! MPI error code
|
||||
integer :: count_per_filter ! number of result values for one filter bin
|
||||
integer(8) :: temp
|
||||
real(8) :: tempr(3) ! temporary array for communication
|
||||
#ifdef OPENMC_MPIF08
|
||||
type(MPI_Datatype) :: result_block
|
||||
|
|
@ -520,6 +531,11 @@ contains
|
|||
#endif
|
||||
#endif
|
||||
|
||||
interface
|
||||
subroutine print_overlap_check() bind(C)
|
||||
end subroutine print_overlap_check
|
||||
end interface
|
||||
|
||||
err = 0
|
||||
|
||||
! Skip if simulation was never run
|
||||
|
|
@ -572,12 +588,6 @@ contains
|
|||
k_col_abs = tempr(1)
|
||||
k_col_tra = tempr(2)
|
||||
k_abs_tra = tempr(3)
|
||||
|
||||
if (check_overlaps) then
|
||||
call MPI_REDUCE(overlap_check_cnt, temp, n_cells, MPI_INTEGER8, &
|
||||
MPI_SUM, 0, mpi_intracomm, mpi_err)
|
||||
overlap_check_cnt = temp
|
||||
end if
|
||||
#endif
|
||||
|
||||
! Write tally results to tallies.out
|
||||
|
|
@ -596,8 +606,8 @@ contains
|
|||
if (master) then
|
||||
if (verbosity >= 6) call print_runtime()
|
||||
if (verbosity >= 4) call print_results()
|
||||
if (check_overlaps) call print_overlap_check()
|
||||
end if
|
||||
if (check_overlaps) call print_overlap_check()
|
||||
|
||||
! Reset flags
|
||||
need_depletion_rx = .false.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
#include "openmc/simulation.h"
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/message_passing.h"
|
||||
|
||||
// OPENMC_RUN encompasses all the main logic where iterations are performed
|
||||
// over the batches, generations, and histories in a fixed source or k-eigenvalue
|
||||
|
|
@ -16,3 +19,47 @@ int openmc_run() {
|
|||
openmc_simulation_finalize();
|
||||
return err;
|
||||
}
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<int64_t> work_index;
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
//==============================================================================
|
||||
|
||||
void openmc_simulation_init_c()
|
||||
{
|
||||
// Determine how much work each process should do
|
||||
calculate_work();
|
||||
}
|
||||
|
||||
void calculate_work()
|
||||
{
|
||||
// Determine minimum amount of particles to simulate on each processor
|
||||
int64_t min_work = n_particles/mpi::n_procs;
|
||||
|
||||
// Determine number of processors that have one extra particle
|
||||
int64_t remainder = n_particles % mpi::n_procs;
|
||||
|
||||
int64_t i_bank = 0;
|
||||
work_index.reserve(mpi::n_procs);
|
||||
work_index.push_back(0);
|
||||
for (int i = 0; i < mpi::n_procs; ++i) {
|
||||
// Number of particles for rank i
|
||||
int64_t work_i = i < remainder ? min_work + 1 : min_work;
|
||||
|
||||
// Set number of particles
|
||||
if (mpi::rank == i) openmc_work = work_i;
|
||||
|
||||
// Set index into source bank for rank i
|
||||
i_bank += work_i;
|
||||
work_index.push_back(i_bank);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module simulation_header
|
|||
|
||||
integer(C_INT), bind(C, name='openmc_current_batch') :: current_batch ! current batch
|
||||
integer(C_INT), bind(C, name='openmc_current_gen') :: current_gen ! current generation within a batch
|
||||
integer :: total_gen = 0 ! total number of generations simulated
|
||||
integer(C_INT), bind(C, name='openmc_total_gen') :: total_gen = 0 ! total number of generations simulated
|
||||
logical(C_BOOL), bind(C, name='openmc_simulation_initialized') :: &
|
||||
simulation_initialized = .false.
|
||||
logical :: need_depletion_rx ! need to calculate depletion reaction rx?
|
||||
|
|
@ -67,10 +67,7 @@ module simulation_header
|
|||
|
||||
integer :: restart_batch
|
||||
|
||||
! Flag for enabling cell overlap checking during transport
|
||||
integer(8), allocatable :: overlap_check_cnt(:)
|
||||
|
||||
logical :: trace
|
||||
logical(C_BOOL), bind(C, name='openmc_trace') :: trace
|
||||
|
||||
!$omp threadprivate(trace, thread_id, current_work)
|
||||
|
||||
|
|
@ -80,8 +77,8 @@ contains
|
|||
! OVERALL_GENERATION determines the overall generation number
|
||||
!===============================================================================
|
||||
|
||||
pure function overall_generation() result(gen)
|
||||
integer :: gen
|
||||
pure function overall_generation() result(gen) bind(C)
|
||||
integer(C_INT) :: gen
|
||||
gen = gen_per_batch*(current_batch - 1) + current_gen
|
||||
end function overall_generation
|
||||
|
||||
|
|
@ -90,7 +87,6 @@ contains
|
|||
!===============================================================================
|
||||
|
||||
subroutine free_memory_simulation()
|
||||
if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt)
|
||||
if (allocated(entropy_p)) deallocate(entropy_p)
|
||||
if (allocated(source_frac)) deallocate(source_frac)
|
||||
if (allocated(work_index)) deallocate(work_index)
|
||||
|
|
|
|||
141
src/source.F90
141
src/source.F90
|
|
@ -1,141 +0,0 @@
|
|||
module source
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
use algorithm, only: binary_search
|
||||
use bank_header, only: Bank, source_bank
|
||||
use constants
|
||||
use distribution_univariate, only: Discrete
|
||||
use distribution_multivariate, only: SpatialBox
|
||||
use error, only: fatal_error
|
||||
use geometry, only: find_cell
|
||||
use hdf5_interface
|
||||
use math
|
||||
use message_passing, only: rank
|
||||
use mgxs_interface, only: rev_energy_bins, num_energy_groups
|
||||
use output, only: write_message
|
||||
use particle_header, only: Particle
|
||||
use random_lcg, only: prn, set_particle_seed, prn_set_stream
|
||||
use settings
|
||||
use simulation_header
|
||||
use source_header, only: external_source
|
||||
use string, only: to_str
|
||||
use state_point, only: read_source_bank, write_source_bank
|
||||
|
||||
implicit none
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! INITIALIZE_SOURCE initializes particles in the source bank
|
||||
!===============================================================================
|
||||
|
||||
subroutine initialize_source()
|
||||
|
||||
integer(8) :: i ! loop index over bank sites
|
||||
integer(8) :: id ! particle id
|
||||
integer(HID_T) :: file_id
|
||||
character(MAX_WORD_LEN) :: filetype
|
||||
character(MAX_FILE_LEN) :: filename
|
||||
type(Bank), pointer :: src ! source bank site
|
||||
|
||||
call write_message("Initializing source particles...", 5)
|
||||
|
||||
if (path_source /= '') then
|
||||
! Read the source from a binary file instead of sampling from some
|
||||
! assumed source distribution
|
||||
|
||||
call write_message('Reading source file from ' // trim(path_source) &
|
||||
&// '...', 6)
|
||||
|
||||
! Open the binary file
|
||||
file_id = file_open(path_source, 'r', parallel=.true.)
|
||||
|
||||
! Read the file type
|
||||
call read_attribute(filetype, file_id, "filetype")
|
||||
|
||||
! Check to make sure this is a source file
|
||||
if (filetype /= 'source' .and. filetype /= 'statepoint') then
|
||||
call fatal_error("Specified starting source file not a source file &
|
||||
&type.")
|
||||
end if
|
||||
|
||||
! Read in the source bank
|
||||
call read_source_bank(file_id, work_index, source_bank)
|
||||
|
||||
! Close file
|
||||
call file_close(file_id)
|
||||
|
||||
else
|
||||
! Generation source sites from specified distribution in user input
|
||||
do i = 1, work
|
||||
! Get pointer to source bank site
|
||||
src => source_bank(i)
|
||||
|
||||
! initialize random number seed
|
||||
id = total_gen*n_particles + work_index(rank) + i
|
||||
call set_particle_seed(id)
|
||||
|
||||
! sample external source distribution
|
||||
call sample_external_source(src)
|
||||
end do
|
||||
end if
|
||||
|
||||
! Write out initial source
|
||||
if (write_initial_source) then
|
||||
call write_message('Writing out initial source...', 5)
|
||||
filename = trim(path_output) // 'initial_source.h5'
|
||||
file_id = file_open(filename, 'w', parallel=.true.)
|
||||
call write_source_bank(file_id, work_index, source_bank)
|
||||
call file_close(file_id)
|
||||
end if
|
||||
|
||||
end subroutine initialize_source
|
||||
|
||||
!===============================================================================
|
||||
! SAMPLE_EXTERNAL_SOURCE samples the user-specified external source and stores
|
||||
! the position, angle, and energy in a Bank type.
|
||||
!===============================================================================
|
||||
|
||||
subroutine sample_external_source(site)
|
||||
type(Bank), intent(inout) :: site ! source site
|
||||
|
||||
integer :: i ! dummy loop index
|
||||
integer :: n_source ! number of source distributions
|
||||
real(8) :: c ! cumulative frequency
|
||||
real(8) :: xi
|
||||
|
||||
! Set the random number generator to the source stream.
|
||||
call prn_set_stream(STREAM_SOURCE)
|
||||
|
||||
! Sample from among multiple source distributions
|
||||
n_source = size(external_source)
|
||||
if (n_source > 1) then
|
||||
xi = prn()*sum(external_source(:) % strength)
|
||||
c = ZERO
|
||||
do i = 1, n_source
|
||||
c = c + external_source(i) % strength
|
||||
if (xi < c) exit
|
||||
end do
|
||||
else
|
||||
i = 1
|
||||
end if
|
||||
|
||||
! Sample source site from i-th source distribution
|
||||
site = external_source(i) % sample()
|
||||
|
||||
! If running in MG, convert site % E to group
|
||||
if (.not. run_CE) then
|
||||
site % E = real(binary_search(rev_energy_bins, num_energy_groups + 1, &
|
||||
site % E), 8)
|
||||
site % E = num_energy_groups + 1 - site % E
|
||||
end if
|
||||
|
||||
! Set the random number generator back to the tracking stream.
|
||||
call prn_set_stream(STREAM_TRACKING)
|
||||
|
||||
end subroutine sample_external_source
|
||||
|
||||
end module source
|
||||
378
src/source.cpp
Normal file
378
src/source.cpp
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
#include "openmc/source.h"
|
||||
|
||||
#include <algorithm> // for move
|
||||
#include <sstream> // for stringstream
|
||||
|
||||
#include "xtensor/xadapt.hpp"
|
||||
|
||||
#include "openmc/cell.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/file_utils.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/material.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/mgxs_interface.h"
|
||||
#include "openmc/nuclide.h"
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/search.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/simulation.h"
|
||||
#include "openmc/state_point.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<SourceDistribution> external_sources;
|
||||
|
||||
//==============================================================================
|
||||
// SourceDistribution implementation
|
||||
//==============================================================================
|
||||
|
||||
SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
|
||||
: space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { }
|
||||
|
||||
SourceDistribution::SourceDistribution(pugi::xml_node node)
|
||||
{
|
||||
// Check for particle type
|
||||
if (check_for_node(node, "particle")) {
|
||||
auto temp_str = get_node_value(node, "particle", true, true);
|
||||
if (temp_str == "neutron") {
|
||||
particle_ = ParticleType::neutron;
|
||||
} else if (temp_str == "photon") {
|
||||
particle_ = ParticleType::photon;
|
||||
openmc_photon_transport = true;
|
||||
} else {
|
||||
fatal_error(std::string("Unknown source particle type: ") + temp_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for source strength
|
||||
if (check_for_node(node, "strength")) {
|
||||
strength_ = std::stod(get_node_value(node, "strength"));
|
||||
}
|
||||
|
||||
// Check for external source file
|
||||
if (check_for_node(node, "file")) {
|
||||
// Copy path of source file
|
||||
path_source = get_node_value(node, "file", false, true);
|
||||
|
||||
// Check if source file exists
|
||||
if (!file_exists(path_source)) {
|
||||
std::stringstream msg;
|
||||
msg << "Source file '" << path_source << "' does not exist.";
|
||||
fatal_error(msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Spatial distribution for external source
|
||||
if (check_for_node(node, "space")) {
|
||||
// Get pointer to spatial distribution
|
||||
pugi::xml_node node_space = node.child("space");
|
||||
|
||||
// Check for type of spatial distribution and read
|
||||
std::string type;
|
||||
if (check_for_node(node_space, "type"))
|
||||
type = get_node_value(node_space, "type", true, true);
|
||||
if (type == "cartesian") {
|
||||
space_ = UPtrSpace{new CartesianIndependent(node_space)};
|
||||
} else if (type == "box") {
|
||||
space_ = UPtrSpace{new SpatialBox(node_space)};
|
||||
} else if (type == "fission") {
|
||||
space_ = UPtrSpace{new SpatialBox(node_space, true)};
|
||||
} else if (type == "point") {
|
||||
space_ = UPtrSpace{new SpatialPoint(node_space)};
|
||||
} else {
|
||||
std::stringstream msg;
|
||||
msg << "Invalid spatial distribution for external source: " << type;
|
||||
fatal_error(msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
// If no spatial distribution specified, make it a point source
|
||||
space_ = UPtrSpace{new SpatialPoint()};
|
||||
}
|
||||
|
||||
// Determine external source angular distribution
|
||||
if (check_for_node(node, "angle")) {
|
||||
// Get pointer to angular distribution
|
||||
pugi::xml_node node_angle = node.child("angle");
|
||||
|
||||
// Check for type of angular distribution
|
||||
std::string type;
|
||||
if (check_for_node(node_angle, "type"))
|
||||
type = get_node_value(node_angle, "type", true, true);
|
||||
if (type == "isotropic") {
|
||||
angle_ = UPtrAngle{new Isotropic()};
|
||||
} else if (type == "monodirectional") {
|
||||
angle_ = UPtrAngle{new Monodirectional(node_angle)};
|
||||
} else if (type == "mu-phi") {
|
||||
angle_ = UPtrAngle{new PolarAzimuthal(node_angle)};
|
||||
} else {
|
||||
std::stringstream msg;
|
||||
msg << "Invalid angular distribution for external source: " << type;
|
||||
fatal_error(msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
angle_ = UPtrAngle{new Isotropic()};
|
||||
}
|
||||
|
||||
// Determine external source energy distribution
|
||||
if (check_for_node(node, "energy")) {
|
||||
pugi::xml_node node_dist = node.child("energy");
|
||||
energy_ = distribution_from_xml(node_dist);
|
||||
} else {
|
||||
// Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
|
||||
energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bank SourceDistribution::sample() const
|
||||
{
|
||||
Bank site;
|
||||
|
||||
// Set weight to one by default
|
||||
site.wgt = 1.0;
|
||||
|
||||
// Repeat sampling source location until a good site has been found
|
||||
bool found = false;
|
||||
int n_reject = 0;
|
||||
static int n_accept = 0;
|
||||
while (!found) {
|
||||
// Set particle type
|
||||
site.particle = static_cast<int>(particle_);
|
||||
|
||||
// Sample spatial distribution
|
||||
Position r = space_->sample();
|
||||
site.xyz[0] = r.x;
|
||||
site.xyz[1] = r.y;
|
||||
site.xyz[2] = r.z;
|
||||
|
||||
// Now search to see if location exists in geometry
|
||||
int32_t cell_index, instance;
|
||||
int err = openmc_find_cell(site.xyz, &cell_index, &instance);
|
||||
found = (err != OPENMC_E_GEOMETRY);
|
||||
|
||||
// Check if spatial site is in fissionable material
|
||||
if (found) {
|
||||
auto space_box = dynamic_cast<SpatialBox*>(space_.get());
|
||||
if (space_box) {
|
||||
if (space_box->only_fissionable()) {
|
||||
// Determine material
|
||||
auto c = cells[cell_index - 1];
|
||||
int32_t mat_index = c->material_[instance];
|
||||
auto m = materials[mat_index];
|
||||
|
||||
if (mat_index == MATERIAL_VOID) {
|
||||
found = false;
|
||||
} else {
|
||||
bool fissionable;
|
||||
openmc_material_get_fissionable(mat_index + 1, &fissionable);
|
||||
if (!fissionable) found = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for rejection
|
||||
if (!found) {
|
||||
++n_reject;
|
||||
if (n_reject >= EXTSRC_REJECT_THRESHOLD &&
|
||||
static_cast<double>(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) {
|
||||
fatal_error("More than 95% of external source sites sampled were "
|
||||
"rejected. Please check your external source definition.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Increment number of accepted samples
|
||||
++n_accept;
|
||||
|
||||
// Sample angle
|
||||
Direction u = angle_->sample();
|
||||
site.uvw[0] = u.x;
|
||||
site.uvw[1] = u.y;
|
||||
site.uvw[2] = u.z;
|
||||
|
||||
// Check for monoenergetic source above maximum particle energy
|
||||
auto p = static_cast<int>(particle_);
|
||||
auto energy_ptr = dynamic_cast<Discrete*>(energy_.get());
|
||||
if (energy_ptr) {
|
||||
auto energies = xt::adapt(energy_ptr->x());
|
||||
if (xt::any(energies > energy_max[p-1])) {
|
||||
fatal_error("Source energy above range of energies of at least "
|
||||
"one cross section table");
|
||||
} else if (xt::any(energies < energy_min[p-1])) {
|
||||
fatal_error("Source energy below range of energies of at least "
|
||||
"one cross section table");
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// Sample energy spectrum
|
||||
site.E = energy_->sample();
|
||||
|
||||
// Resample if energy falls outside minimum or maximum particle energy
|
||||
if (site.E < energy_max[p-1] && site.E > energy_min[p-1]) break;
|
||||
}
|
||||
|
||||
// Set delayed group
|
||||
site.delayed_group = 0;
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
void initialize_source()
|
||||
{
|
||||
write_message("Initializing source particles...", 5);
|
||||
|
||||
// Get pointer to source bank
|
||||
Bank* source_bank;
|
||||
int64_t n;
|
||||
openmc_source_bank(&source_bank, &n);
|
||||
|
||||
if (path_source != "") {
|
||||
// Read the source from a binary file instead of sampling from some
|
||||
// assumed source distribution
|
||||
|
||||
std::stringstream msg;
|
||||
msg << "Reading source file from " << path_source << "...";
|
||||
write_message(msg, 6);
|
||||
|
||||
// Open the binary file
|
||||
hid_t file_id = file_open(path_source, 'r', true);
|
||||
|
||||
// Read the file type
|
||||
std::string filetype;
|
||||
read_attribute(file_id, "filetype", filetype);
|
||||
|
||||
// Check to make sure this is a source file
|
||||
if (filetype != "source" && filetype != "statepoint") {
|
||||
fatal_error("Specified starting source file not a source file type.");
|
||||
}
|
||||
|
||||
// Read in the source bank
|
||||
read_source_bank(file_id, work_index.data(), source_bank);
|
||||
|
||||
// Close file
|
||||
file_close(file_id);
|
||||
|
||||
} else {
|
||||
// Generation source sites from specified distribution in user input
|
||||
for (int64_t i = 0; i < openmc_work; ++i) {
|
||||
// initialize random number seed
|
||||
int64_t id = openmc_total_gen*n_particles + work_index[openmc::mpi::rank] + i + 1;
|
||||
set_particle_seed(id);
|
||||
|
||||
// sample external source distribution
|
||||
source_bank[i] = sample_external_source();
|
||||
}
|
||||
}
|
||||
|
||||
// Write out initial source
|
||||
if (openmc_write_initial_source) {
|
||||
write_message("Writing out initial source...", 5);
|
||||
std::string filename = path_output + "initial_source.h5";
|
||||
hid_t file_id = file_open(filename, 'w', true);
|
||||
write_source_bank(file_id, work_index.data(), source_bank);
|
||||
file_close(file_id);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" double* rev_energy_bins_ptr();
|
||||
|
||||
Bank sample_external_source()
|
||||
{
|
||||
// Set the random number generator to the source stream.
|
||||
prn_set_stream(STREAM_SOURCE);
|
||||
|
||||
// Determine total source strength
|
||||
double total_strength = 0.0;
|
||||
for (auto& s : external_sources)
|
||||
total_strength += s.strength();
|
||||
|
||||
// Sample from among multiple source distributions
|
||||
int i = 0;
|
||||
if (external_sources.size() > 1) {
|
||||
double xi = prn()*total_strength;
|
||||
double c = 0.0;
|
||||
for (; i < external_sources.size(); ++i) {
|
||||
c += external_sources[i].strength();
|
||||
if (xi < c) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sample source site from i-th source distribution
|
||||
Bank site {external_sources[i].sample()};
|
||||
|
||||
// If running in MG, convert site % E to group
|
||||
if (!openmc_run_CE) {
|
||||
// Get pointer to rev_energy_bins array on Fortran side
|
||||
double* rev_energy_bins = rev_energy_bins_ptr();
|
||||
|
||||
int n = num_energy_groups + 1;
|
||||
site.E = lower_bound_index(rev_energy_bins, rev_energy_bins + n, site.E);
|
||||
site.E = num_energy_groups - site.E;
|
||||
}
|
||||
|
||||
// Set the random number generator back to the tracking stream.
|
||||
prn_set_stream(STREAM_TRACKING);
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Fortran compatibility functions
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void free_memory_source()
|
||||
{
|
||||
external_sources.clear();
|
||||
}
|
||||
|
||||
extern "C" double total_source_strength()
|
||||
{
|
||||
double strength = 0.0;
|
||||
for (const auto& s : external_sources) {
|
||||
strength += s.strength();
|
||||
}
|
||||
return strength;
|
||||
}
|
||||
|
||||
// Needed in fill_source_bank_fixedsource
|
||||
extern "C" int overall_generation();
|
||||
|
||||
//! Fill source bank at end of generation for fixed source simulations
|
||||
extern "C" void fill_source_bank_fixedsource()
|
||||
{
|
||||
if (path_source.empty()) {
|
||||
// Get pointer to source bank
|
||||
Bank* source_bank;
|
||||
int64_t n;
|
||||
openmc_source_bank(&source_bank, &n);
|
||||
|
||||
for (int64_t i = 0; i < openmc_work; ++i) {
|
||||
// initialize random number seed
|
||||
int64_t id = (openmc_total_gen + overall_generation())*n_particles +
|
||||
work_index[openmc::mpi::rank] + i + 1;
|
||||
set_particle_seed(id);
|
||||
|
||||
// sample external source distribution
|
||||
source_bank[i] = sample_external_source();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -1,388 +0,0 @@
|
|||
module source_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use bank_header, only: Bank
|
||||
use constants
|
||||
use distribution_univariate
|
||||
use distribution_multivariate
|
||||
use error
|
||||
use geometry, only: find_cell
|
||||
use material_header, only: materials
|
||||
use nuclide_header, only: energy_min, energy_max
|
||||
use particle_header
|
||||
use settings, only: photon_transport
|
||||
use string, only: to_lower
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
private
|
||||
public :: free_memory_source
|
||||
public :: openmc_extend_sources
|
||||
public :: openmc_source_set_strength
|
||||
|
||||
integer :: n_accept = 0 ! Number of samples accepted
|
||||
integer :: n_reject = 0 ! Number of samples rejected
|
||||
|
||||
!===============================================================================
|
||||
! SOURCEDISTRIBUTION describes an external source of particles for a
|
||||
! fixed-source problem or for the starting source in a k eigenvalue problem
|
||||
!===============================================================================
|
||||
|
||||
type, public :: SourceDistribution
|
||||
integer :: particle ! particle type
|
||||
real(8) :: strength = ONE ! source strength
|
||||
class(SpatialDistribution), allocatable :: space ! spatial distribution
|
||||
class(UnitSphereDistribution), allocatable :: angle ! angle distribution
|
||||
class(Distribution), allocatable :: energy ! energy distribution
|
||||
contains
|
||||
procedure :: from_xml
|
||||
procedure :: sample
|
||||
end type SourceDistribution
|
||||
|
||||
! Number of external source distributions
|
||||
integer(C_INT32_T), public, bind(C) :: n_sources = 0
|
||||
|
||||
! External source distributions
|
||||
type(SourceDistribution), public, allocatable :: external_source(:)
|
||||
|
||||
contains
|
||||
|
||||
subroutine from_xml(this, node, path_source)
|
||||
class(SourceDistribution), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
character(MAX_FILE_LEN), intent(out) :: path_source
|
||||
|
||||
integer :: n
|
||||
logical :: file_exists
|
||||
character(MAX_WORD_LEN) :: type, temp_str
|
||||
type(XMLNode) :: node_space
|
||||
type(XMLNode) :: node_angle
|
||||
type(XMLNode) :: node_dist
|
||||
|
||||
! Check for particle type
|
||||
if (check_for_node(node, "particle")) then
|
||||
call get_node_value(node, "particle", temp_str)
|
||||
select case (to_lower(temp_str))
|
||||
case ('neutron')
|
||||
this % particle = NEUTRON
|
||||
case ('photon')
|
||||
this % particle = PHOTON
|
||||
photon_transport = .true.
|
||||
case default
|
||||
call fatal_error('Unknown source particle type: ' // trim(temp_str))
|
||||
end select
|
||||
else
|
||||
this % particle = NEUTRON
|
||||
end if
|
||||
|
||||
! Check for source strength
|
||||
if (check_for_node(node, "strength")) then
|
||||
call get_node_value(node, "strength", this % strength)
|
||||
end if
|
||||
|
||||
! Check for external source file
|
||||
if (check_for_node(node, "file")) then
|
||||
! Copy path of source file
|
||||
call get_node_value(node, "file", path_source)
|
||||
|
||||
! Check if source file exists
|
||||
inquire(FILE=path_source, EXIST=file_exists)
|
||||
if (.not. file_exists) then
|
||||
call fatal_error("Source file '" // trim(path_source) &
|
||||
// "' does not exist!")
|
||||
end if
|
||||
|
||||
else
|
||||
|
||||
! Spatial distribution for external source
|
||||
if (check_for_node(node, "space")) then
|
||||
|
||||
! Get pointer to spatial distribution
|
||||
node_space = node % child("space")
|
||||
|
||||
! Check for type of spatial distribution
|
||||
type = ''
|
||||
if (check_for_node(node_space, "type")) &
|
||||
call get_node_value(node_space, "type", type)
|
||||
select case (to_lower(type))
|
||||
case ('cartesian')
|
||||
allocate(CartesianIndependent :: this % space)
|
||||
|
||||
case ('box')
|
||||
allocate(SpatialBox :: this % space)
|
||||
|
||||
case ('fission')
|
||||
allocate(SpatialBox :: this % space)
|
||||
select type(space => this % space)
|
||||
type is (SpatialBox)
|
||||
space % only_fissionable = .true.
|
||||
end select
|
||||
|
||||
case ('point')
|
||||
allocate(SpatialPoint :: this % space)
|
||||
|
||||
case default
|
||||
call fatal_error("Invalid spatial distribution for external source: "&
|
||||
// trim(type))
|
||||
end select
|
||||
|
||||
! Read spatial distribution from XML
|
||||
call this % space % from_xml(node_space)
|
||||
|
||||
else
|
||||
! If no spatial distribution specified, make it a point source
|
||||
allocate(SpatialPoint :: this % space)
|
||||
select type (space => this % space)
|
||||
type is (SpatialPoint)
|
||||
space % xyz(:) = [ZERO, ZERO, ZERO]
|
||||
end select
|
||||
end if
|
||||
|
||||
! Determine external source angular distribution
|
||||
if (check_for_node(node, "angle")) then
|
||||
|
||||
! Get pointer to angular distribution
|
||||
node_angle = node % child("angle")
|
||||
|
||||
! Check for type of angular distribution
|
||||
type = ''
|
||||
if (check_for_node(node_angle, "type")) &
|
||||
call get_node_value(node_angle, "type", type)
|
||||
select case (to_lower(type))
|
||||
case ('isotropic')
|
||||
allocate(Isotropic :: this % angle)
|
||||
|
||||
case ('monodirectional')
|
||||
allocate(Monodirectional :: this % angle)
|
||||
|
||||
case ('mu-phi')
|
||||
allocate(PolarAzimuthal :: this % angle)
|
||||
|
||||
case default
|
||||
call fatal_error("Invalid angular distribution for external source: "&
|
||||
// trim(type))
|
||||
end select
|
||||
|
||||
! Read reference directional unit vector
|
||||
if (check_for_node(node_angle, "reference_uvw")) then
|
||||
n = node_word_count(node_angle, "reference_uvw")
|
||||
if (n /= 3) then
|
||||
call fatal_error('Angular distribution reference direction must have &
|
||||
&three parameters specified.')
|
||||
end if
|
||||
call get_node_array(node_angle, "reference_uvw", &
|
||||
this % angle % reference_uvw)
|
||||
else
|
||||
! By default, set reference unit vector to be positive z-direction
|
||||
this % angle % reference_uvw(:) = [ZERO, ZERO, ONE]
|
||||
end if
|
||||
|
||||
! Read parameters for angle distribution
|
||||
select type (angle => this % angle)
|
||||
type is (Monodirectional)
|
||||
call get_node_array(node_angle, "reference_uvw", &
|
||||
this % angle % reference_uvw)
|
||||
|
||||
type is (PolarAzimuthal)
|
||||
if (check_for_node(node_angle, "mu")) then
|
||||
node_dist = node_angle % child("mu")
|
||||
call distribution_from_xml(angle % mu, node_dist)
|
||||
else
|
||||
allocate(Uniform :: angle%mu)
|
||||
select type (mu => angle%mu)
|
||||
type is (Uniform)
|
||||
mu % a = -ONE
|
||||
mu % b = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
if (check_for_node(node_angle, "phi")) then
|
||||
node_dist = node_angle % child("phi")
|
||||
call distribution_from_xml(angle % phi, node_dist)
|
||||
else
|
||||
allocate(Uniform :: angle%phi)
|
||||
select type (phi => angle%phi)
|
||||
type is (Uniform)
|
||||
phi % a = ZERO
|
||||
phi % b = TWO*PI
|
||||
end select
|
||||
end if
|
||||
end select
|
||||
|
||||
else
|
||||
! Set default angular distribution isotropic
|
||||
allocate(Isotropic :: this % angle)
|
||||
this % angle % reference_uvw(:) = [ZERO, ZERO, ONE]
|
||||
end if
|
||||
|
||||
! Determine external source energy distribution
|
||||
if (check_for_node(node, "energy")) then
|
||||
node_dist = node % child("energy")
|
||||
call distribution_from_xml(this % energy, node_dist)
|
||||
else
|
||||
! Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
|
||||
allocate(Watt :: this % energy)
|
||||
select type(energy => this % energy)
|
||||
type is (Watt)
|
||||
energy % a = 0.988e6_8
|
||||
energy % b = 2.249e-6_8
|
||||
end select
|
||||
end if
|
||||
end if
|
||||
|
||||
end subroutine from_xml
|
||||
|
||||
function sample(this) result(site)
|
||||
class(SourceDistribution), intent(in) :: this
|
||||
type(Bank) :: site
|
||||
|
||||
logical :: found ! Does the source particle exist within geometry?
|
||||
type(Particle) :: p ! Temporary particle for using find_cell
|
||||
|
||||
! Set weight to one by default
|
||||
site % wgt = ONE
|
||||
|
||||
! Repeat sampling source location until a good site has been found
|
||||
found = .false.
|
||||
do while (.not. found)
|
||||
! Set particle defaults
|
||||
call particle_initialize(p)
|
||||
|
||||
! Set particle type
|
||||
site % particle = this % particle
|
||||
|
||||
! Sample spatial distribution
|
||||
site % xyz(:) = this % space % sample()
|
||||
|
||||
! Fill p with needed data
|
||||
p % coord(1) % xyz(:) = site % xyz
|
||||
p % coord(1) % uvw(:) = [ ONE, ZERO, ZERO ]
|
||||
|
||||
! Now search to see if location exists in geometry
|
||||
call find_cell(p, found)
|
||||
|
||||
! Check if spatial site is in fissionable material
|
||||
if (found) then
|
||||
select type (space => this % space)
|
||||
type is (SpatialBox)
|
||||
if (space % only_fissionable) then
|
||||
if (p % material == MATERIAL_VOID) then
|
||||
found = .false.
|
||||
elseif (.not. materials(p % material) % fissionable) then
|
||||
found = .false.
|
||||
end if
|
||||
end if
|
||||
end select
|
||||
end if
|
||||
|
||||
! Check for rejection
|
||||
if (.not. found) then
|
||||
n_reject = n_reject + 1
|
||||
if (n_reject >= EXTSRC_REJECT_THRESHOLD .and. &
|
||||
real(n_accept, 8)/n_reject <= EXTSRC_REJECT_FRACTION) then
|
||||
call fatal_error("More than 95% of external source sites sampled &
|
||||
&were rejected. Please check your external source definition.")
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
|
||||
! Increment number of accepted samples
|
||||
n_accept = n_accept + 1
|
||||
|
||||
call particle_clear(p)
|
||||
|
||||
! Sample angle
|
||||
site % uvw(:) = this % angle % sample()
|
||||
|
||||
! Check for monoenergetic source above maximum particle energy
|
||||
select type (energy => this % energy)
|
||||
type is (Discrete)
|
||||
if (any(energy % x > energy_max(this % particle))) then
|
||||
call fatal_error("Source energy above range of energies of at least &
|
||||
&one cross section table")
|
||||
else if (any(energy % x < energy_min(this % particle))) then
|
||||
call fatal_error("Source energy below range of energies of at least &
|
||||
&one cross section table")
|
||||
end if
|
||||
end select
|
||||
|
||||
do
|
||||
! Sample energy spectrum
|
||||
site % E = this % energy % sample()
|
||||
|
||||
! Resample if energy falls outside minimum or maximum particle energy
|
||||
if (site % E < energy_max(this % particle) .and. &
|
||||
site % E > energy_min(this % particle)) exit
|
||||
end do
|
||||
|
||||
! Set delayed group
|
||||
site % delayed_group = 0
|
||||
|
||||
end function sample
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_SOURCE deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_source()
|
||||
n_sources = 0
|
||||
if (allocated(external_source)) deallocate(external_source)
|
||||
end subroutine free_memory_source
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_extend_sources(n, index_start, index_end) result(err) bind(C)
|
||||
! Extend the external_source array by n elements
|
||||
integer(C_INT32_T), value, intent(in) :: n
|
||||
integer(C_INT32_T), optional, intent(out) :: index_start
|
||||
integer(C_INT32_T), optional, intent(out) :: index_end
|
||||
integer(C_INT) :: err
|
||||
|
||||
type(SourceDistribution), allocatable :: temp(:) ! temporary array
|
||||
|
||||
if (n_sources == 0) then
|
||||
! Allocate external_source array
|
||||
allocate(external_source(n))
|
||||
else
|
||||
! Allocate external_source array with increased size
|
||||
allocate(temp(n_sources + n))
|
||||
|
||||
! Copy original source array to temporary array
|
||||
temp(1:n_sources) = external_source
|
||||
|
||||
! Move allocation from temporary array
|
||||
call move_alloc(FROM=temp, TO=external_source)
|
||||
end if
|
||||
|
||||
! Return indices in external_source array
|
||||
if (present(index_start)) index_start = n_sources + 1
|
||||
if (present(index_end)) index_end = n_sources + n
|
||||
n_sources = n_sources + n
|
||||
|
||||
err = 0
|
||||
end function openmc_extend_sources
|
||||
|
||||
|
||||
function openmc_source_set_strength(index, strength) result(err) bind(C)
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
real(C_DOUBLE), value, intent(in) :: strength
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= n_sources) then
|
||||
if (strength > ZERO) then
|
||||
external_source(index) % strength = strength
|
||||
err = 0
|
||||
else
|
||||
err = E_INVALID_ARGUMENT
|
||||
call set_errmsg("Source strength must be positive.")
|
||||
end if
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in external source array is out of bounds.")
|
||||
end if
|
||||
end function openmc_source_set_strength
|
||||
|
||||
end module source_header
|
||||
|
|
@ -64,98 +64,6 @@ contains
|
|||
|
||||
end subroutine split_string
|
||||
|
||||
!===============================================================================
|
||||
! TOKENIZE takes a string that includes logical expressions for a list of
|
||||
! bounding surfaces in a cell and splits it into separate tokens. The characters
|
||||
! (, ), |, and ~ count as separate tokens since they represent operators.
|
||||
!===============================================================================
|
||||
|
||||
subroutine tokenize(string, tokens)
|
||||
character(*), intent(in) :: string
|
||||
type(VectorInt), intent(inout) :: tokens
|
||||
|
||||
integer :: i ! current index
|
||||
integer :: i_start ! starting index of word
|
||||
integer :: token
|
||||
character(len=len_trim(string)) :: string_
|
||||
|
||||
! Remove leading blanks
|
||||
string_ = adjustl(string)
|
||||
|
||||
i_start = 0
|
||||
i = 1
|
||||
do while (i <= len_trim(string_))
|
||||
! Check for special characters
|
||||
if (index('()|~ ', string_(i:i)) > 0) then
|
||||
! If the special character appears immediately after a non-operator,
|
||||
! create a token with the surface half-space
|
||||
if (i_start > 0) then
|
||||
call tokens%push_back(int(str_to_int(&
|
||||
string_(i_start:i - 1)), 4))
|
||||
end if
|
||||
|
||||
select case (string_(i:i))
|
||||
case ('(')
|
||||
call tokens%push_back(OP_LEFT_PAREN)
|
||||
case (')')
|
||||
if (tokens%size() > 0) then
|
||||
token = tokens%data(tokens%size())
|
||||
if (token >= OP_UNION .and. token < OP_RIGHT_PAREN) then
|
||||
call fatal_error("Right parentheses cannot follow an operator in &
|
||||
®ion specification: " // trim(string))
|
||||
end if
|
||||
end if
|
||||
call tokens%push_back(OP_RIGHT_PAREN)
|
||||
case ('|')
|
||||
if (tokens%size() > 0) then
|
||||
token = tokens%data(tokens%size())
|
||||
if (.not. (token < OP_UNION .or. token == OP_RIGHT_PAREN)) then
|
||||
call fatal_error("Union cannot follow an operator in region &
|
||||
&specification: " // trim(string))
|
||||
end if
|
||||
end if
|
||||
call tokens%push_back(OP_UNION)
|
||||
case ('~')
|
||||
call tokens%push_back(OP_COMPLEMENT)
|
||||
case (' ')
|
||||
! Find next non-space character
|
||||
do while (string_(i+1:i+1) == ' ')
|
||||
i = i + 1
|
||||
end do
|
||||
|
||||
! If previous token is a halfspace or right parenthesis and next token
|
||||
! is not a left parenthese or union operator, that implies that the
|
||||
! whitespace is to be interpreted as an intersection operator
|
||||
if (i_start > 0 .or. tokens%data(tokens%size()) == OP_RIGHT_PAREN) then
|
||||
if (index(')|', string_(i+1:i+1)) == 0) then
|
||||
call tokens%push_back(OP_INTERSECTION)
|
||||
end if
|
||||
end if
|
||||
end select
|
||||
|
||||
i_start = 0
|
||||
else
|
||||
! Check for invalid characters
|
||||
if (index('-+0123456789', string_(i:i)) == 0) then
|
||||
call fatal_error("Invalid character '" // string_(i:i) // "' in &
|
||||
®ion specification.")
|
||||
end if
|
||||
|
||||
! If we haven't yet reached the start of a word, start a new word
|
||||
if (i_start == 0) i_start = i
|
||||
end if
|
||||
|
||||
i = i + 1
|
||||
end do
|
||||
|
||||
! If we've reached the end and we're still in a word, create a token from it
|
||||
! and add it to the list
|
||||
if (i_start > 0) then
|
||||
call tokens%push_back(int(str_to_int(&
|
||||
string_(i_start:len_trim(string_))), 4))
|
||||
end if
|
||||
end subroutine tokenize
|
||||
|
||||
!===============================================================================
|
||||
! CONCATENATE takes an array of words and concatenates them together in one
|
||||
! string with a single space between words
|
||||
|
|
|
|||
157
src/summary.F90
157
src/summary.F90
|
|
@ -29,6 +29,13 @@ contains
|
|||
|
||||
subroutine write_summary()
|
||||
|
||||
interface
|
||||
subroutine write_geometry(file_id) bind(C)
|
||||
import HID_T
|
||||
integer(HID_T), intent(in), value :: file_id
|
||||
end subroutine write_geometry
|
||||
end interface
|
||||
|
||||
integer(HID_T) :: file_id
|
||||
|
||||
! Display output message
|
||||
|
|
@ -154,156 +161,6 @@ contains
|
|||
|
||||
end subroutine write_nuclides
|
||||
|
||||
!===============================================================================
|
||||
! WRITE_GEOMETRY
|
||||
!===============================================================================
|
||||
|
||||
subroutine write_geometry(file_id)
|
||||
integer(HID_T), intent(in) :: file_id
|
||||
|
||||
integer :: i, j, cell_fill
|
||||
integer, allocatable :: cell_materials(:)
|
||||
integer, allocatable :: cell_ids(:)
|
||||
real(8), allocatable :: cell_temperatures(:)
|
||||
integer(HID_T) :: geom_group
|
||||
integer(HID_T) :: cells_group, cell_group
|
||||
integer(HID_T) :: surfaces_group
|
||||
integer(HID_T) :: universes_group, univ_group
|
||||
integer(HID_T) :: lattices_group
|
||||
type(Cell), pointer :: c
|
||||
class(Lattice), pointer :: lat
|
||||
|
||||
! Use H5LT interface to write number of geometry objects
|
||||
geom_group = create_group(file_id, "geometry")
|
||||
call write_attribute(geom_group, "n_cells", n_cells)
|
||||
call write_attribute(geom_group, "n_surfaces", n_surfaces)
|
||||
call write_attribute(geom_group, "n_universes", n_universes)
|
||||
call write_attribute(geom_group, "n_lattices", size(lattices))
|
||||
|
||||
! ==========================================================================
|
||||
! WRITE INFORMATION ON CELLS
|
||||
|
||||
! Create a cell group (nothing directly written in this group) then close
|
||||
cells_group = create_group(geom_group, "cells")
|
||||
|
||||
! Write information on each cell
|
||||
CELL_LOOP: do i = 1, n_cells
|
||||
c => cells(i)
|
||||
cell_group = create_group(cells_group, "cell " // trim(to_str(c%id())))
|
||||
|
||||
call c % to_hdf5(cell_group)
|
||||
|
||||
! Write information on what fills this cell
|
||||
select case (c%type())
|
||||
case (FILL_MATERIAL)
|
||||
call write_dataset(cell_group, "fill_type", "material")
|
||||
|
||||
if (c % material_size() == 1) then
|
||||
if (c % material(1) == MATERIAL_VOID) then
|
||||
call write_dataset(cell_group, "material", MATERIAL_VOID)
|
||||
else
|
||||
call write_dataset(cell_group, "material", &
|
||||
materials(c % material(1)) % id())
|
||||
end if
|
||||
else
|
||||
allocate(cell_materials(c % material_size()))
|
||||
do j = 1, c % material_size()
|
||||
if (c % material(j) == MATERIAL_VOID) then
|
||||
cell_materials(j) = MATERIAL_VOID
|
||||
else
|
||||
cell_materials(j) = materials(c % material(j)) % id()
|
||||
end if
|
||||
end do
|
||||
call write_dataset(cell_group, "material", cell_materials)
|
||||
deallocate(cell_materials)
|
||||
end if
|
||||
|
||||
allocate(cell_temperatures(size(c % sqrtkT)))
|
||||
cell_temperatures(:) = c % sqrtkT(:)
|
||||
cell_temperatures(:) = cell_temperatures(:)**2 / K_BOLTZMANN
|
||||
call write_dataset(cell_group, "temperature", cell_temperatures)
|
||||
deallocate(cell_temperatures)
|
||||
|
||||
case (FILL_UNIVERSE)
|
||||
call write_dataset(cell_group, "fill_type", "universe")
|
||||
call write_dataset(cell_group, "fill", universes(c%fill()+1)%id)
|
||||
|
||||
if (allocated(c%translation)) then
|
||||
call write_dataset(cell_group, "translation", c%translation)
|
||||
end if
|
||||
if (allocated(c%rotation)) then
|
||||
call write_dataset(cell_group, "rotation", c%rotation)
|
||||
end if
|
||||
|
||||
case (FILL_LATTICE)
|
||||
call write_dataset(cell_group, "fill_type", "lattice")
|
||||
! Do not access the 'lattices' array with 'c % fill() + 1' directly; it
|
||||
! causes a segfault in GCC 7.3.0
|
||||
cell_fill = c % fill() + 1
|
||||
call write_dataset(cell_group, "lattice", lattices(cell_fill)%obj%id())
|
||||
end select
|
||||
|
||||
call close_group(cell_group)
|
||||
end do CELL_LOOP
|
||||
|
||||
call close_group(cells_group)
|
||||
|
||||
! ==========================================================================
|
||||
! WRITE INFORMATION ON SURFACES
|
||||
|
||||
! Create surfaces group
|
||||
surfaces_group = create_group(geom_group, "surfaces")
|
||||
|
||||
! Write information on each surface
|
||||
SURFACE_LOOP: do i = 1, n_surfaces
|
||||
call surfaces(i) % to_hdf5(surfaces_group)
|
||||
end do SURFACE_LOOP
|
||||
|
||||
call close_group(surfaces_group)
|
||||
|
||||
! ==========================================================================
|
||||
! WRITE INFORMATION ON UNIVERSES
|
||||
|
||||
! Create universes group (nothing directly written here) then close
|
||||
universes_group = create_group(geom_group, "universes")
|
||||
|
||||
! Write information on each universe
|
||||
UNIVERSE_LOOP: do i = 1, n_universes
|
||||
associate (u => universes(i))
|
||||
univ_group = create_group(universes_group, "universe " // &
|
||||
trim(to_str(u%id)))
|
||||
|
||||
! Write list of cells in this universe
|
||||
if (size(u % cells) > 0) then
|
||||
allocate(cell_ids(size(u % cells)))
|
||||
do j = 1, size(u % cells)
|
||||
cell_ids(j) = cells(u % cells(j)) % id()
|
||||
end do
|
||||
call write_dataset(univ_group, "cells", cell_ids)
|
||||
deallocate(cell_ids)
|
||||
end if
|
||||
|
||||
call close_group(univ_group)
|
||||
end associate
|
||||
end do UNIVERSE_LOOP
|
||||
|
||||
call close_group(universes_group)
|
||||
|
||||
! ==========================================================================
|
||||
! WRITE INFORMATION ON LATTICES
|
||||
|
||||
lattices_group = create_group(geom_group, "lattices")
|
||||
|
||||
do i = 1, size(lattices)
|
||||
lat => lattices(i)%obj
|
||||
call lat % to_hdf5(lattices_group)
|
||||
end do
|
||||
|
||||
call close_group(lattices_group)
|
||||
call close_group(geom_group)
|
||||
|
||||
end subroutine write_geometry
|
||||
|
||||
!===============================================================================
|
||||
! WRITE_MATERIALS
|
||||
!===============================================================================
|
||||
|
|
|
|||
36
src/summary.cpp
Normal file
36
src/summary.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "openmc/cell.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/lattice.h"
|
||||
#include "openmc/surface.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
extern "C" void
|
||||
write_geometry(hid_t file_id) {
|
||||
auto geom_group = create_group(file_id, "geometry");
|
||||
write_attribute(geom_group, "n_cells", cells.size());
|
||||
write_attribute(geom_group, "n_surfaces", surfaces.size());
|
||||
write_attribute(geom_group, "n_universes", universes.size());
|
||||
write_attribute(geom_group, "n_lattices", lattices.size());
|
||||
|
||||
auto cells_group = create_group(geom_group, "cells");
|
||||
for (Cell* c : cells) c->to_hdf5(cells_group);
|
||||
close_group(cells_group);
|
||||
|
||||
auto surfaces_group = create_group(geom_group, "surfaces");
|
||||
for (Surface* surf : surfaces) surf->to_hdf5(surfaces_group);
|
||||
close_group(surfaces_group);
|
||||
|
||||
auto universes_group = create_group(geom_group, "universes");
|
||||
for (Universe* u : universes) u->to_hdf5(universes_group);
|
||||
close_group(universes_group);
|
||||
|
||||
auto lattices_group = create_group(geom_group, "lattices");
|
||||
for (Lattice* lat : lattices) lat->to_hdf5(lattices_group);
|
||||
close_group(lattices_group);
|
||||
|
||||
close_group(geom_group);
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
307
src/surface.cpp
307
src/surface.cpp
|
|
@ -27,7 +27,7 @@ extern "C" const int BC_PERIODIC {3};
|
|||
|
||||
int32_t n_surfaces;
|
||||
|
||||
std::vector<Surface*> global_surfaces;
|
||||
std::vector<Surface*> surfaces;
|
||||
|
||||
std::map<int, int> surface_map;
|
||||
|
||||
|
|
@ -141,38 +141,38 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2,
|
|||
Surface::Surface(pugi::xml_node surf_node)
|
||||
{
|
||||
if (check_for_node(surf_node, "id")) {
|
||||
id = std::stoi(get_node_value(surf_node, "id"));
|
||||
id_ = std::stoi(get_node_value(surf_node, "id"));
|
||||
} else {
|
||||
fatal_error("Must specify id of surface in geometry XML file.");
|
||||
}
|
||||
|
||||
if (check_for_node(surf_node, "name")) {
|
||||
name = get_node_value(surf_node, "name", false);
|
||||
name_ = get_node_value(surf_node, "name", false);
|
||||
}
|
||||
|
||||
if (check_for_node(surf_node, "boundary")) {
|
||||
std::string surf_bc = get_node_value(surf_node, "boundary", true, true);
|
||||
|
||||
if (surf_bc == "transmission" || surf_bc == "transmit" ||surf_bc.empty()) {
|
||||
bc = BC_TRANSMIT;
|
||||
bc_ = BC_TRANSMIT;
|
||||
|
||||
} else if (surf_bc == "vacuum") {
|
||||
bc = BC_VACUUM;
|
||||
bc_ = BC_VACUUM;
|
||||
|
||||
} else if (surf_bc == "reflective" || surf_bc == "reflect"
|
||||
|| surf_bc == "reflecting") {
|
||||
bc = BC_REFLECT;
|
||||
bc_ = BC_REFLECT;
|
||||
} else if (surf_bc == "periodic") {
|
||||
bc = BC_PERIODIC;
|
||||
bc_ = BC_PERIODIC;
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Unknown boundary condition \"" << surf_bc
|
||||
<< "\" specified on surface " << id;
|
||||
<< "\" specified on surface " << id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
bc = BC_TRANSMIT;
|
||||
bc_ = BC_TRANSMIT;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -211,11 +211,11 @@ void
|
|||
Surface::to_hdf5(hid_t group_id) const
|
||||
{
|
||||
std::string group_name {"surface "};
|
||||
group_name += std::to_string(id);
|
||||
group_name += std::to_string(id_);
|
||||
|
||||
hid_t surf_group = create_group(group_id, group_name);
|
||||
|
||||
switch(bc) {
|
||||
switch(bc_) {
|
||||
case BC_TRANSMIT :
|
||||
write_string(surf_group, "boundary_type", "transmission", false);
|
||||
break;
|
||||
|
|
@ -230,8 +230,8 @@ Surface::to_hdf5(hid_t group_id) const
|
|||
break;
|
||||
}
|
||||
|
||||
if (!name.empty()) {
|
||||
write_string(surf_group, "name", name, false);
|
||||
if (!name_.empty()) {
|
||||
write_string(surf_group, "name", name_, false);
|
||||
}
|
||||
|
||||
to_hdf5_inner(surf_group);
|
||||
|
|
@ -247,7 +247,7 @@ PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node)
|
|||
: Surface {surf_node}
|
||||
{
|
||||
if (check_for_node(surf_node, "periodic_surface_id")) {
|
||||
i_periodic = std::stoi(get_node_value(surf_node, "periodic_surface_id"));
|
||||
i_periodic_ = std::stoi(get_node_value(surf_node, "periodic_surface_id"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,17 +273,17 @@ axis_aligned_plane_distance(Position r, Direction u, bool coincident, double off
|
|||
SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node)
|
||||
: PeriodicSurface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0);
|
||||
read_coeffs(surf_node, id_, x0_);
|
||||
}
|
||||
|
||||
double SurfaceXPlane::evaluate(Position r) const
|
||||
{
|
||||
return r.x - x0;
|
||||
return r.x - x0_;
|
||||
}
|
||||
|
||||
double SurfaceXPlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_plane_distance<0>(r, u, coincident, x0);
|
||||
return axis_aligned_plane_distance<0>(r, u, coincident, x0_);
|
||||
}
|
||||
|
||||
Direction SurfaceXPlane::normal(Position r) const
|
||||
|
|
@ -294,7 +294,7 @@ Direction SurfaceXPlane::normal(Position r) const
|
|||
void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "x-plane", false);
|
||||
std::array<double, 1> coeffs {{x0}};
|
||||
std::array<double, 1> coeffs {{x0_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -303,15 +303,15 @@ bool SurfaceXPlane::periodic_translate(const PeriodicSurface* other,
|
|||
{
|
||||
Direction other_n = other->normal(r);
|
||||
if (other_n.x == 1 and other_n.y == 0 and other_n.z == 0) {
|
||||
r.x = x0;
|
||||
r.x = x0_;
|
||||
return false;
|
||||
} else {
|
||||
// Assume the partner is an YPlane (the only supported partner). Use the
|
||||
// evaluate function to find y0, then adjust position/Direction for rotational
|
||||
// symmetry.
|
||||
double y0 = -other->evaluate({0., 0., 0.});
|
||||
r.y = r.x - x0 + y0;
|
||||
r.x = x0;
|
||||
// evaluate function to find y0, then adjust position/Direction for
|
||||
// rotational symmetry.
|
||||
double y0_ = -other->evaluate({0., 0., 0.});
|
||||
r.y = r.x - x0_ + y0_;
|
||||
r.x = x0_;
|
||||
|
||||
double ux = u.x;
|
||||
u.x = -u.y;
|
||||
|
|
@ -324,7 +324,7 @@ bool SurfaceXPlane::periodic_translate(const PeriodicSurface* other,
|
|||
BoundingBox
|
||||
SurfaceXPlane::bounding_box() const
|
||||
{
|
||||
return {x0, x0, -INFTY, INFTY, -INFTY, INFTY};
|
||||
return {x0_, x0_, -INFTY, INFTY, -INFTY, INFTY};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -334,17 +334,17 @@ SurfaceXPlane::bounding_box() const
|
|||
SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node)
|
||||
: PeriodicSurface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, y0);
|
||||
read_coeffs(surf_node, id_, y0_);
|
||||
}
|
||||
|
||||
double SurfaceYPlane::evaluate(Position r) const
|
||||
{
|
||||
return r.y - y0;
|
||||
return r.y - y0_;
|
||||
}
|
||||
|
||||
double SurfaceYPlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_plane_distance<1>(r, u, coincident, y0);
|
||||
return axis_aligned_plane_distance<1>(r, u, coincident, y0_);
|
||||
}
|
||||
|
||||
Direction SurfaceYPlane::normal(Position r) const
|
||||
|
|
@ -355,7 +355,7 @@ Direction SurfaceYPlane::normal(Position r) const
|
|||
void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "y-plane", false);
|
||||
std::array<double, 1> coeffs {{y0}};
|
||||
std::array<double, 1> coeffs {{y0_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -365,15 +365,15 @@ bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other,
|
|||
Direction other_n = other->normal(r);
|
||||
if (other_n.x == 0 and other_n.y == 1 and other_n.z == 0) {
|
||||
// The periodic partner is also aligned along y. Just change the y coord.
|
||||
r.y = y0;
|
||||
r.y = y0_;
|
||||
return false;
|
||||
} else {
|
||||
// Assume the partner is an XPlane (the only supported partner). Use the
|
||||
// evaluate function to find x0, then adjust position/Direction for rotational
|
||||
// symmetry.
|
||||
double x0 = -other->evaluate({0., 0., 0.});
|
||||
r.x = r.y - y0 + x0;
|
||||
r.y = y0;
|
||||
double x0_ = -other->evaluate({0., 0., 0.});
|
||||
r.x = r.y - y0_ + x0_;
|
||||
r.y = y0_;
|
||||
|
||||
double ux = u.x;
|
||||
u.x = u.y;
|
||||
|
|
@ -386,7 +386,7 @@ bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other,
|
|||
BoundingBox
|
||||
SurfaceYPlane::bounding_box() const
|
||||
{
|
||||
return {-INFTY, INFTY, y0, y0, -INFTY, INFTY};
|
||||
return {-INFTY, INFTY, y0_, y0_, -INFTY, INFTY};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -396,17 +396,17 @@ SurfaceYPlane::bounding_box() const
|
|||
SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node)
|
||||
: PeriodicSurface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, z0);
|
||||
read_coeffs(surf_node, id_, z0_);
|
||||
}
|
||||
|
||||
double SurfaceZPlane::evaluate(Position r) const
|
||||
{
|
||||
return r.z - z0;
|
||||
return r.z - z0_;
|
||||
}
|
||||
|
||||
double SurfaceZPlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_plane_distance<2>(r, u, coincident, z0);
|
||||
return axis_aligned_plane_distance<2>(r, u, coincident, z0_);
|
||||
}
|
||||
|
||||
Direction SurfaceZPlane::normal(Position r) const
|
||||
|
|
@ -417,7 +417,7 @@ Direction SurfaceZPlane::normal(Position r) const
|
|||
void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "z-plane", false);
|
||||
std::array<double, 1> coeffs {{z0}};
|
||||
std::array<double, 1> coeffs {{z0_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -425,14 +425,14 @@ bool SurfaceZPlane::periodic_translate(const PeriodicSurface* other,
|
|||
Position& r, Direction& u) const
|
||||
{
|
||||
// Assume the other plane is aligned along z. Just change the z coord.
|
||||
r.z = z0;
|
||||
r.z = z0_;
|
||||
return false;
|
||||
}
|
||||
|
||||
BoundingBox
|
||||
SurfaceZPlane::bounding_box() const
|
||||
{
|
||||
return {-INFTY, INFTY, -INFTY, INFTY, z0, z0};
|
||||
return {-INFTY, INFTY, -INFTY, INFTY, z0_, z0_};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -442,20 +442,20 @@ SurfaceZPlane::bounding_box() const
|
|||
SurfacePlane::SurfacePlane(pugi::xml_node surf_node)
|
||||
: PeriodicSurface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, A, B, C, D);
|
||||
read_coeffs(surf_node, id_, A_, B_, C_, D_);
|
||||
}
|
||||
|
||||
double
|
||||
SurfacePlane::evaluate(Position r) const
|
||||
{
|
||||
return A*r.x + B*r.y + C*r.z - D;
|
||||
return A_*r.x + B_*r.y + C_*r.z - D_;
|
||||
}
|
||||
|
||||
double
|
||||
SurfacePlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
const double f = A*r.x + B*r.y + C*r.z - D;
|
||||
const double projection = A*u.x + B*u.y + C*u.z;
|
||||
const double f = A_*r.x + B_*r.y + C_*r.z - D_;
|
||||
const double projection = A_*u.x + B_*u.y + C_*u.z;
|
||||
if (coincident or std::abs(f) < FP_COINCIDENT or projection == 0.0) {
|
||||
return INFTY;
|
||||
} else {
|
||||
|
|
@ -468,13 +468,13 @@ SurfacePlane::distance(Position r, Direction u, bool coincident) const
|
|||
Direction
|
||||
SurfacePlane::normal(Position r) const
|
||||
{
|
||||
return {A, B, C};
|
||||
return {A_, B_, C_};
|
||||
}
|
||||
|
||||
void SurfacePlane::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "plane", false);
|
||||
std::array<double, 4> coeffs {{A, B, C, D}};
|
||||
std::array<double, 4> coeffs {{A_, B_, C_, D_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -484,12 +484,12 @@ bool SurfacePlane::periodic_translate(const PeriodicSurface* other, Position& r,
|
|||
// This function assumes the other plane shares this plane's normal direction.
|
||||
|
||||
// Determine the distance to intersection.
|
||||
double d = evaluate(r) / (A*A + B*B + C*C);
|
||||
double d = evaluate(r) / (A_*A_ + B_*B_ + C_*C_);
|
||||
|
||||
// Move the particle that distance along the normal vector.
|
||||
r.x -= d * A;
|
||||
r.y -= d * B;
|
||||
r.z -= d * C;
|
||||
r.x -= d * A_;
|
||||
r.y -= d * B_;
|
||||
r.z -= d * C_;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -582,30 +582,30 @@ axis_aligned_cylinder_normal(Position r, double offset1, double offset2)
|
|||
SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, y0, z0, radius);
|
||||
read_coeffs(surf_node, id_, y0_, z0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceXCylinder::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, radius);
|
||||
return axis_aligned_cylinder_evaluate<1, 2>(r, y0_, z0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceXCylinder::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0, z0,
|
||||
radius);
|
||||
return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0_, z0_,
|
||||
radius_);
|
||||
}
|
||||
|
||||
Direction SurfaceXCylinder::normal(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_normal<0, 1, 2>(r, y0, z0);
|
||||
return axis_aligned_cylinder_normal<0, 1, 2>(r, y0_, z0_);
|
||||
}
|
||||
|
||||
|
||||
void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "x-cylinder", false);
|
||||
std::array<double, 3> coeffs {{y0, z0, radius}};
|
||||
std::array<double, 3> coeffs {{y0_, z0_, radius_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -616,29 +616,29 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const
|
|||
SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, z0, radius);
|
||||
read_coeffs(surf_node, id_, x0_, z0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceYCylinder::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, radius);
|
||||
return axis_aligned_cylinder_evaluate<0, 2>(r, x0_, z0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceYCylinder::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0, z0,
|
||||
radius);
|
||||
return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0_, z0_,
|
||||
radius_);
|
||||
}
|
||||
|
||||
Direction SurfaceYCylinder::normal(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_normal<1, 0, 2>(r, x0, z0);
|
||||
return axis_aligned_cylinder_normal<1, 0, 2>(r, x0_, z0_);
|
||||
}
|
||||
|
||||
void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "y-cylinder", false);
|
||||
std::array<double, 3> coeffs {{x0, z0, radius}};
|
||||
std::array<double, 3> coeffs {{x0_, z0_, radius_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -649,29 +649,29 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const
|
|||
SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, y0, radius);
|
||||
read_coeffs(surf_node, id_, x0_, y0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceZCylinder::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, radius);
|
||||
return axis_aligned_cylinder_evaluate<0, 1>(r, x0_, y0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceZCylinder::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0, y0,
|
||||
radius);
|
||||
return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0_, y0_,
|
||||
radius_);
|
||||
}
|
||||
|
||||
Direction SurfaceZCylinder::normal(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_normal<2, 0, 1>(r, x0, y0);
|
||||
return axis_aligned_cylinder_normal<2, 0, 1>(r, x0_, y0_);
|
||||
}
|
||||
|
||||
void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "z-cylinder", false);
|
||||
std::array<double, 3> coeffs {{x0, y0, radius}};
|
||||
std::array<double, 3> coeffs {{x0_, y0_, radius_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -682,24 +682,24 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const
|
|||
SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius);
|
||||
read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_);
|
||||
}
|
||||
|
||||
double SurfaceSphere::evaluate(Position r) const
|
||||
{
|
||||
const double x = r.x - x0;
|
||||
const double y = r.y - y0;
|
||||
const double z = r.z - z0;
|
||||
return x*x + y*y + z*z - radius*radius;
|
||||
const double x = r.x - x0_;
|
||||
const double y = r.y - y0_;
|
||||
const double z = r.z - z0_;
|
||||
return x*x + y*y + z*z - radius_*radius_;
|
||||
}
|
||||
|
||||
double SurfaceSphere::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
const double x = r.x - x0;
|
||||
const double y = r.y - y0;
|
||||
const double z = r.z - z0;
|
||||
const double x = r.x - x0_;
|
||||
const double y = r.y - y0_;
|
||||
const double z = r.z - z0_;
|
||||
const double k = x*u.x + y*u.y + z*u.z;
|
||||
const double c = x*x + y*y + z*z - radius*radius;
|
||||
const double c = x*x + y*y + z*z - radius_*radius_;
|
||||
const double quad = k*k - c;
|
||||
|
||||
if (quad < 0.0) {
|
||||
|
|
@ -733,13 +733,13 @@ double SurfaceSphere::distance(Position r, Direction u, bool coincident) const
|
|||
|
||||
Direction SurfaceSphere::normal(Position r) const
|
||||
{
|
||||
return {2.0*(r.x - x0), 2.0*(r.y - y0), 2.0*(r.z - z0)};
|
||||
return {2.0*(r.x - x0_), 2.0*(r.y - y0_), 2.0*(r.z - z0_)};
|
||||
}
|
||||
|
||||
void SurfaceSphere::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "sphere", false);
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius}};
|
||||
std::array<double, 4> coeffs {{x0_, y0_, z0_, radius_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -835,29 +835,29 @@ axis_aligned_cone_normal(Position r, double offset1, double offset2,
|
|||
SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius_sq);
|
||||
read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
double SurfaceXCone::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, radius_sq);
|
||||
return axis_aligned_cone_evaluate<0, 1, 2>(r, x0_, y0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
double SurfaceXCone::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0, y0, z0,
|
||||
radius_sq);
|
||||
return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0_, y0_, z0_,
|
||||
radius_sq_);
|
||||
}
|
||||
|
||||
Direction SurfaceXCone::normal(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_normal<0, 1, 2>(r, x0, y0, z0, radius_sq);
|
||||
return axis_aligned_cone_normal<0, 1, 2>(r, x0_, y0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
void SurfaceXCone::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "x-cone", false);
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius_sq}};
|
||||
std::array<double, 4> coeffs {{x0_, y0_, z0_, radius_sq_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -868,29 +868,29 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const
|
|||
SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius_sq);
|
||||
read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
double SurfaceYCone::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, radius_sq);
|
||||
return axis_aligned_cone_evaluate<1, 0, 2>(r, y0_, x0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
double SurfaceYCone::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0, x0, z0,
|
||||
radius_sq);
|
||||
return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0_, x0_, z0_,
|
||||
radius_sq_);
|
||||
}
|
||||
|
||||
Direction SurfaceYCone::normal(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_normal<1, 0, 2>(r, y0, x0, z0, radius_sq);
|
||||
return axis_aligned_cone_normal<1, 0, 2>(r, y0_, x0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
void SurfaceYCone::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "y-cone", false);
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius_sq}};
|
||||
std::array<double, 4> coeffs {{x0_, y0_, z0_, radius_sq_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -901,29 +901,29 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const
|
|||
SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius_sq);
|
||||
read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_);
|
||||
}
|
||||
|
||||
double SurfaceZCone::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, radius_sq);
|
||||
return axis_aligned_cone_evaluate<2, 0, 1>(r, z0_, x0_, y0_, radius_sq_);
|
||||
}
|
||||
|
||||
double SurfaceZCone::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0, x0, y0,
|
||||
radius_sq);
|
||||
return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0_, x0_, y0_,
|
||||
radius_sq_);
|
||||
}
|
||||
|
||||
Direction SurfaceZCone::normal(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_normal<2, 0, 1>(r, z0, x0, y0, radius_sq);
|
||||
return axis_aligned_cone_normal<2, 0, 1>(r, z0_, x0_, y0_, radius_sq_);
|
||||
}
|
||||
|
||||
void SurfaceZCone::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "z-cone", false);
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius_sq}};
|
||||
std::array<double, 4> coeffs {{x0_, y0_, z0_, radius_sq_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -934,7 +934,7 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const
|
|||
SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, A, B, C, D, E, F, G, H, J, K);
|
||||
read_coeffs(surf_node, id_, A_, B_, C_, D_, E_, F_, G_, H_, J_, K_);
|
||||
}
|
||||
|
||||
double
|
||||
|
|
@ -943,9 +943,9 @@ SurfaceQuadric::evaluate(Position r) const
|
|||
const double x = r.x;
|
||||
const double y = r.y;
|
||||
const double z = r.z;
|
||||
return x*(A*x + D*y + G) +
|
||||
y*(B*y + E*z + H) +
|
||||
z*(C*z + F*x + J) + K;
|
||||
return x*(A_*x + D_*y + G_) +
|
||||
y*(B_*y + E_*z + H_) +
|
||||
z*(C_*z + F_*x + J_) + K_;
|
||||
}
|
||||
|
||||
double
|
||||
|
|
@ -958,11 +958,11 @@ SurfaceQuadric::distance(Position r, Direction ang, bool coincident) const
|
|||
const double &v = ang.y;
|
||||
const double &w = ang.z;
|
||||
|
||||
const double a = A*u*u + B*v*v + C*w*w + D*u*v + E*v*w + F*u*w;
|
||||
const double k = (A*u*x + B*v*y + C*w*z + 0.5*(D*(u*y + v*x) +
|
||||
E*(v*z + w*y) + F*(w*x + u*z) + G*u + H*v + J*w));
|
||||
const double c = A*x*x + B*y*y + C*z*z + D*x*y + E*y*z + F*x*z + G*x + H*y
|
||||
+ J*z + K;
|
||||
const double a = A_*u*u + B_*v*v + C_*w*w + D_*u*v + E_*v*w + F_*u*w;
|
||||
const double k = A_*u*x + B_*v*y + C_*w*z + 0.5*(D_*(u*y + v*x)
|
||||
+ E_*(v*z + w*y) + F_*(w*x + u*z) + G_*u + H_*v + J_*w);
|
||||
const double c = A_*x*x + B_*y*y + C_*z*z + D_*x*y + E_*y*z + F_*x*z + G_*x
|
||||
+ H_*y + J_*z + K_;
|
||||
double quad = k*k - a*c;
|
||||
|
||||
double d;
|
||||
|
|
@ -1008,15 +1008,15 @@ SurfaceQuadric::normal(Position r) const
|
|||
const double &x = r.x;
|
||||
const double &y = r.y;
|
||||
const double &z = r.z;
|
||||
return {2.0*A*x + D*y + F*z + G,
|
||||
2.0*B*y + D*x + E*z + H,
|
||||
2.0*C*z + E*y + F*x + J};
|
||||
return {2.0*A_*x + D_*y + F_*z + G_,
|
||||
2.0*B_*y + D_*x + E_*z + H_,
|
||||
2.0*C_*z + E_*y + F_*x + J_};
|
||||
}
|
||||
|
||||
void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
write_string(group_id, "type", "quadric", false);
|
||||
std::array<double, 10> coeffs {{A, B, C, D, E, F, G, H, J, K}};
|
||||
std::array<double, 10> coeffs {{A_, B_, C_, D_, E_, F_, G_, H_, J_, K_}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -1032,7 +1032,7 @@ read_surfaces(pugi::xml_node* node)
|
|||
}
|
||||
|
||||
// Loop over XML surface elements and populate the array.
|
||||
global_surfaces.reserve(n_surfaces);
|
||||
surfaces.reserve(n_surfaces);
|
||||
{
|
||||
pugi::xml_node surf_node;
|
||||
int i_surf;
|
||||
|
|
@ -1041,40 +1041,40 @@ read_surfaces(pugi::xml_node* node)
|
|||
std::string surf_type = get_node_value(surf_node, "type", true, true);
|
||||
|
||||
if (surf_type == "x-plane") {
|
||||
global_surfaces.push_back(new SurfaceXPlane(surf_node));
|
||||
surfaces.push_back(new SurfaceXPlane(surf_node));
|
||||
|
||||
} else if (surf_type == "y-plane") {
|
||||
global_surfaces.push_back(new SurfaceYPlane(surf_node));
|
||||
surfaces.push_back(new SurfaceYPlane(surf_node));
|
||||
|
||||
} else if (surf_type == "z-plane") {
|
||||
global_surfaces.push_back(new SurfaceZPlane(surf_node));
|
||||
surfaces.push_back(new SurfaceZPlane(surf_node));
|
||||
|
||||
} else if (surf_type == "plane") {
|
||||
global_surfaces.push_back(new SurfacePlane(surf_node));
|
||||
surfaces.push_back(new SurfacePlane(surf_node));
|
||||
|
||||
} else if (surf_type == "x-cylinder") {
|
||||
global_surfaces.push_back(new SurfaceXCylinder(surf_node));
|
||||
surfaces.push_back(new SurfaceXCylinder(surf_node));
|
||||
|
||||
} else if (surf_type == "y-cylinder") {
|
||||
global_surfaces.push_back(new SurfaceYCylinder(surf_node));
|
||||
surfaces.push_back(new SurfaceYCylinder(surf_node));
|
||||
|
||||
} else if (surf_type == "z-cylinder") {
|
||||
global_surfaces.push_back(new SurfaceZCylinder(surf_node));
|
||||
surfaces.push_back(new SurfaceZCylinder(surf_node));
|
||||
|
||||
} else if (surf_type == "sphere") {
|
||||
global_surfaces.push_back(new SurfaceSphere(surf_node));
|
||||
surfaces.push_back(new SurfaceSphere(surf_node));
|
||||
|
||||
} else if (surf_type == "x-cone") {
|
||||
global_surfaces.push_back(new SurfaceXCone(surf_node));
|
||||
surfaces.push_back(new SurfaceXCone(surf_node));
|
||||
|
||||
} else if (surf_type == "y-cone") {
|
||||
global_surfaces.push_back(new SurfaceYCone(surf_node));
|
||||
surfaces.push_back(new SurfaceYCone(surf_node));
|
||||
|
||||
} else if (surf_type == "z-cone") {
|
||||
global_surfaces.push_back(new SurfaceZCone(surf_node));
|
||||
surfaces.push_back(new SurfaceZCone(surf_node));
|
||||
|
||||
} else if (surf_type == "quadric") {
|
||||
global_surfaces.push_back(new SurfaceQuadric(surf_node));
|
||||
surfaces.push_back(new SurfaceQuadric(surf_node));
|
||||
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
|
|
@ -1086,7 +1086,7 @@ read_surfaces(pugi::xml_node* node)
|
|||
|
||||
// Fill the surface map.
|
||||
for (int i_surf = 0; i_surf < n_surfaces; i_surf++) {
|
||||
int id = global_surfaces[i_surf]->id;
|
||||
int id = surfaces[i_surf]->id_;
|
||||
auto in_map = surface_map.find(id);
|
||||
if (in_map == surface_map.end()) {
|
||||
surface_map[id] = i_surf;
|
||||
|
|
@ -1102,16 +1102,16 @@ read_surfaces(pugi::xml_node* node)
|
|||
zmin {INFTY}, zmax {-INFTY};
|
||||
int i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax;
|
||||
for (int i_surf = 0; i_surf < n_surfaces; i_surf++) {
|
||||
if (global_surfaces[i_surf]->bc == BC_PERIODIC) {
|
||||
if (surfaces[i_surf]->bc_ == BC_PERIODIC) {
|
||||
// Downcast to the PeriodicSurface type.
|
||||
Surface* surf_base = global_surfaces[i_surf];
|
||||
Surface* surf_base = surfaces[i_surf];
|
||||
PeriodicSurface* surf = dynamic_cast<PeriodicSurface*>(surf_base);
|
||||
|
||||
// Make sure this surface inherits from PeriodicSurface.
|
||||
if (!surf) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Periodic boundary condition not supported for surface "
|
||||
<< surf_base->id
|
||||
<< surf_base->id_
|
||||
<< ". Periodic BCs are only supported for planar surfaces.";
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
|
|
@ -1147,9 +1147,9 @@ read_surfaces(pugi::xml_node* node)
|
|||
|
||||
// Set i_periodic for periodic BC surfaces.
|
||||
for (int i_surf = 0; i_surf < n_surfaces; i_surf++) {
|
||||
if (global_surfaces[i_surf]->bc == BC_PERIODIC) {
|
||||
if (surfaces[i_surf]->bc_ == BC_PERIODIC) {
|
||||
// Downcast to the PeriodicSurface type.
|
||||
Surface* surf_base = global_surfaces[i_surf];
|
||||
Surface* surf_base = surfaces[i_surf];
|
||||
PeriodicSurface* surf = dynamic_cast<PeriodicSurface*>(surf_base);
|
||||
|
||||
// Also try downcasting to the SurfacePlane type (which must be handled
|
||||
|
|
@ -1158,48 +1158,48 @@ read_surfaces(pugi::xml_node* node)
|
|||
|
||||
if (!surf_p) {
|
||||
// This is not a SurfacePlane.
|
||||
if (surf->i_periodic == C_NONE) {
|
||||
if (surf->i_periodic_ == C_NONE) {
|
||||
// The user did not specify the matching periodic surface. See if we
|
||||
// can find the partnered surface from the bounding box information.
|
||||
if (i_surf == i_xmin) {
|
||||
surf->i_periodic = i_xmax;
|
||||
surf->i_periodic_ = i_xmax;
|
||||
} else if (i_surf == i_xmax) {
|
||||
surf->i_periodic = i_xmin;
|
||||
surf->i_periodic_ = i_xmin;
|
||||
} else if (i_surf == i_ymin) {
|
||||
surf->i_periodic = i_ymax;
|
||||
surf->i_periodic_ = i_ymax;
|
||||
} else if (i_surf == i_ymax) {
|
||||
surf->i_periodic = i_ymin;
|
||||
surf->i_periodic_ = i_ymin;
|
||||
} else if (i_surf == i_zmin) {
|
||||
surf->i_periodic = i_zmax;
|
||||
surf->i_periodic_ = i_zmax;
|
||||
} else if (i_surf == i_zmax) {
|
||||
surf->i_periodic = i_zmin;
|
||||
surf->i_periodic_ = i_zmin;
|
||||
} else {
|
||||
fatal_error("Periodic boundary condition applied to interior "
|
||||
"surface");
|
||||
}
|
||||
} else {
|
||||
// Convert the surface id to an index.
|
||||
surf->i_periodic = surface_map[surf->i_periodic];
|
||||
surf->i_periodic_ = surface_map[surf->i_periodic_];
|
||||
}
|
||||
} else {
|
||||
// This is a SurfacePlane. We won't try to find it's partner if the
|
||||
// user didn't specify one.
|
||||
if (surf->i_periodic == C_NONE) {
|
||||
if (surf->i_periodic_ == C_NONE) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "No matching periodic surface specified for periodic "
|
||||
"boundary condition on surface " << surf->id;
|
||||
"boundary condition on surface " << surf->id_;
|
||||
fatal_error(err_msg);
|
||||
} else {
|
||||
// Convert the surface id to an index.
|
||||
surf->i_periodic = surface_map[surf->i_periodic];
|
||||
surf->i_periodic_ = surface_map[surf->i_periodic_];
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the opposite surface is also periodic.
|
||||
if (global_surfaces[surf->i_periodic]->bc != BC_PERIODIC) {
|
||||
if (surfaces[surf->i_periodic_]->bc_ != BC_PERIODIC) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Could not find matching surface for periodic boundary "
|
||||
"condition on surface " << surf->id;
|
||||
"condition on surface " << surf->id_;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -1211,11 +1211,11 @@ read_surfaces(pugi::xml_node* node)
|
|||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
Surface* surface_pointer(int surf_ind) {return global_surfaces[surf_ind];}
|
||||
Surface* surface_pointer(int surf_ind) {return surfaces[surf_ind];}
|
||||
|
||||
int surface_id(Surface* surf) {return surf->id;}
|
||||
int surface_id(Surface* surf) {return surf->id_;}
|
||||
|
||||
int surface_bc(Surface* surf) {return surf->bc;}
|
||||
int surface_bc(Surface* surf) {return surf->bc_;}
|
||||
|
||||
void surface_reflect(Surface* surf, double xyz[3], double uvw[3])
|
||||
{
|
||||
|
|
@ -1228,18 +1228,7 @@ extern "C" {
|
|||
uvw[2] = u.z;
|
||||
}
|
||||
|
||||
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(Surface* surf, hid_t group) {surf->to_hdf5(group);}
|
||||
|
||||
int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic;}
|
||||
int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic_;}
|
||||
|
||||
bool
|
||||
surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3],
|
||||
|
|
@ -1262,8 +1251,8 @@ extern "C" {
|
|||
|
||||
void free_memory_surfaces_c()
|
||||
{
|
||||
for (Surface* surf : global_surfaces) {delete surf;}
|
||||
global_surfaces.clear();
|
||||
for (Surface* surf : surfaces) {delete surf;}
|
||||
surfaces.clear();
|
||||
n_surfaces = 0;
|
||||
surface_map.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,23 +38,6 @@ module surface_header
|
|||
real(C_DOUBLE), intent(inout) :: uvw(3);
|
||||
end subroutine surface_reflect_c
|
||||
|
||||
pure subroutine surface_normal_c(surf_ptr, xyz, uvw) &
|
||||
bind(C, name='surface_normal')
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
type(C_PTR), intent(in), value :: surf_ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(3);
|
||||
real(C_DOUBLE), intent(out) :: uvw(3);
|
||||
end subroutine surface_normal_c
|
||||
|
||||
subroutine surface_to_hdf5_c(surf_ptr, group) &
|
||||
bind(C, name='surface_to_hdf5')
|
||||
import C_PTR, HID_T
|
||||
implicit none
|
||||
type(C_PTR), intent(in), value :: surf_ptr
|
||||
integer(HID_T), intent(in), value :: group
|
||||
end subroutine surface_to_hdf5_c
|
||||
|
||||
pure function surface_i_periodic_c(surf_ptr) &
|
||||
bind(C, name="surface_i_periodic") result(i_periodic)
|
||||
use ISO_C_BINDING
|
||||
|
|
@ -84,9 +67,6 @@ module surface_header
|
|||
!===============================================================================
|
||||
|
||||
type :: Surface
|
||||
integer, allocatable :: &
|
||||
neighbor_pos(:), & ! List of cells on positive side
|
||||
neighbor_neg(:) ! List of cells on negative side
|
||||
type(C_PTR) :: ptr
|
||||
|
||||
contains
|
||||
|
|
@ -94,8 +74,6 @@ module surface_header
|
|||
procedure :: id => surface_id
|
||||
procedure :: bc => surface_bc
|
||||
procedure :: reflect => surface_reflect
|
||||
procedure :: normal => surface_normal
|
||||
procedure :: to_hdf5 => surface_to_hdf5
|
||||
procedure :: i_periodic => surface_i_periodic
|
||||
procedure :: periodic_translate => surface_periodic
|
||||
|
||||
|
|
@ -129,19 +107,6 @@ contains
|
|||
call surface_reflect_c(this % ptr, xyz, uvw)
|
||||
end subroutine surface_reflect
|
||||
|
||||
pure subroutine surface_normal(this, xyz, uvw)
|
||||
class(Surface), intent(in) :: this
|
||||
real(C_DOUBLE), intent(in) :: xyz(3);
|
||||
real(C_DOUBLE), intent(out) :: uvw(3);
|
||||
call surface_normal_c(this % ptr, xyz, uvw)
|
||||
end subroutine surface_normal
|
||||
|
||||
subroutine surface_to_hdf5(this, group)
|
||||
class(Surface), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: group
|
||||
call surface_to_hdf5_c(this % ptr, group)
|
||||
end subroutine surface_to_hdf5
|
||||
|
||||
pure function surface_i_periodic(this) result(i_periodic)
|
||||
class(Surface), intent(in) :: this
|
||||
integer(C_INT) :: i_periodic
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ contains
|
|||
|
||||
! Iterate over coordinate levels to see with cells match
|
||||
do i = 1, p % n_coord
|
||||
val = this % map % get(p % coord(i) % cell)
|
||||
val = this % map % get(p % coord(i) % cell + 1)
|
||||
if (val /= EMPTY) then
|
||||
call match % bins % push_back(val)
|
||||
call match % weights % push_back(ONE)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ contains
|
|||
|
||||
integer :: val
|
||||
|
||||
val = this % map % get(p % cell_born)
|
||||
val = this % map % get(p % cell_born + 1)
|
||||
if (val /= EMPTY) then
|
||||
call match % bins % push_back(val)
|
||||
call match % weights % push_back(ONE)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ contains
|
|||
|
||||
! Starting one coordinate level deeper, find the next bin.
|
||||
do i = 1, p % last_n_coord
|
||||
val = this % map % get(p % last_cell(i))
|
||||
val = this % map % get(p % last_cell(i) + 1)
|
||||
if (val /= EMPTY) then
|
||||
call match % bins % push_back(val)
|
||||
call match % weights % push_back(ONE)
|
||||
|
|
|
|||
|
|
@ -54,26 +54,25 @@ contains
|
|||
|
||||
integer :: distribcell_index, offset, i
|
||||
|
||||
distribcell_index = cells(this % cell) % distribcell_index
|
||||
distribcell_index = cells(this % cell) % distribcell_index()
|
||||
offset = 0
|
||||
do i = 1, p % n_coord
|
||||
if (cells(p % coord(i) % cell) % type() == FILL_UNIVERSE) then
|
||||
offset = offset + cells(p % coord(i) % cell) &
|
||||
% offset(distribcell_index-1)
|
||||
elseif (cells(p % coord(i) % cell) % type() == FILL_LATTICE) then
|
||||
if (lattices(p % coord(i + 1) % lattice) % obj &
|
||||
% are_valid_indices([&
|
||||
if (cells(p % coord(i) % cell + 1) % type() == FILL_UNIVERSE) then
|
||||
offset = offset + cells(p % coord(i) % cell + 1) &
|
||||
% offset(distribcell_index)
|
||||
elseif (cells(p % coord(i) % cell + 1) % type() == FILL_LATTICE) then
|
||||
if (lattices(p % coord(i + 1) % lattice) % are_valid_indices([&
|
||||
p % coord(i + 1) % lattice_x, &
|
||||
p % coord(i + 1) % lattice_y, &
|
||||
p % coord(i + 1) % lattice_z])) then
|
||||
offset = offset + lattices(p % coord(i + 1) % lattice) % obj &
|
||||
% offset(distribcell_index - 1, &
|
||||
offset = offset + lattices(p % coord(i + 1) % lattice) &
|
||||
% offset(distribcell_index, &
|
||||
[p % coord(i + 1) % lattice_x, &
|
||||
p % coord(i + 1) % lattice_y, &
|
||||
p % coord(i + 1) % lattice_z])
|
||||
end if
|
||||
end if
|
||||
if (this % cell == p % coord(i) % cell) then
|
||||
if (this % cell == p % coord(i) % cell + 1) then
|
||||
call match % bins % push_back(offset + 1)
|
||||
call match % weights % push_back(ONE)
|
||||
return
|
||||
|
|
@ -154,12 +153,12 @@ contains
|
|||
end interface
|
||||
|
||||
! Get the distribcell index for this cell
|
||||
map = cells(i_cell) % distribcell_index
|
||||
map = cells(i_cell) % distribcell_index()
|
||||
|
||||
path_len = distribcell_path_len(i_cell-1, map-1, target_offset, &
|
||||
root_universe-1)
|
||||
path_len = distribcell_path_len(i_cell-1, map, target_offset, &
|
||||
root_universe)
|
||||
allocate(path_c(path_len))
|
||||
call distribcell_path(i_cell-1, map-1, target_offset, root_universe-1, &
|
||||
call distribcell_path(i_cell-1, map, target_offset, root_universe, &
|
||||
path_c)
|
||||
do i = 1, min(path_len, MAX_LINE_LEN)
|
||||
if (path_c(i) == C_NULL_CHAR) exit
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ contains
|
|||
|
||||
allocate(universe_ids(size(this % universes)))
|
||||
do i = 1, size(this % universes)
|
||||
universe_ids(i) = universes(this % universes(i)) % id
|
||||
universe_ids(i) = universe_id(this % universes(i)-1)
|
||||
end do
|
||||
call write_dataset(filter_group, "bins", universe_ids)
|
||||
end subroutine to_statepoint_universe
|
||||
|
|
@ -112,7 +112,7 @@ contains
|
|||
integer, intent(in) :: bin
|
||||
character(MAX_LINE_LEN) :: label
|
||||
|
||||
label = "Universe " // to_str(universes(this % universes(bin)) % id)
|
||||
label = "Universe " // to_str(universe_id(this % universes(bin)))
|
||||
end function text_label_universe
|
||||
|
||||
end module tally_filter_universe
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ module tally_header
|
|||
use message_passing, only: n_procs
|
||||
use nuclide_header, only: nuclide_dict
|
||||
use settings, only: reduce_tallies, run_mode
|
||||
use source_header, only: external_source
|
||||
use stl_vector, only: VectorInt
|
||||
use string, only: to_lower, to_f_string, str_to_int, to_str
|
||||
use tally_filter_header, only: TallyFilterContainer, filters, n_filters
|
||||
|
|
@ -169,6 +168,13 @@ contains
|
|||
real(C_DOUBLE) :: val
|
||||
real(C_DOUBLE) :: total_source
|
||||
|
||||
interface
|
||||
function total_source_strength() result(strength) bind(C)
|
||||
import C_DOUBLE
|
||||
real(C_DOUBLE) :: strength
|
||||
end function
|
||||
end interface
|
||||
|
||||
! Increment number of realizations
|
||||
if (reduce_tallies) then
|
||||
this % n_realizations = this % n_realizations + 1
|
||||
|
|
@ -178,7 +184,7 @@ contains
|
|||
|
||||
! Calculate total source strength for normalization
|
||||
if (run_mode == MODE_FIXEDSOURCE) then
|
||||
total_source = sum(external_source(:) % strength)
|
||||
total_source = total_source_strength()
|
||||
else
|
||||
total_source = ONE
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ contains
|
|||
! If the cell hasn't been determined based on the particle's location,
|
||||
! initiate a search for the current cell. This generally happens at the
|
||||
! beginning of the history and again for any secondary particles
|
||||
if (p % coord(p % n_coord) % cell == NONE) then
|
||||
if (p % coord(p % n_coord) % cell == C_NONE) then
|
||||
call find_cell(p, found_cell)
|
||||
if (.not. found_cell) then
|
||||
call particle_mark_as_lost(p, "Could not find the cell containing" &
|
||||
|
|
@ -100,7 +100,7 @@ contains
|
|||
end if
|
||||
|
||||
! set birth cell attribute
|
||||
if (p % cell_born == NONE) p % cell_born = p % coord(p % n_coord) % cell
|
||||
if (p % cell_born == C_NONE) p % cell_born = p % coord(p % n_coord) % cell
|
||||
end if
|
||||
|
||||
! Write particle track.
|
||||
|
|
@ -183,7 +183,7 @@ contains
|
|||
end do
|
||||
p % last_n_coord = p % n_coord
|
||||
|
||||
p % coord(p % n_coord) % cell = NONE
|
||||
p % coord(p % n_coord) % cell = C_NONE
|
||||
if (any(lattice_translation /= 0)) then
|
||||
! Particle crosses lattice boundary
|
||||
p % surface = ERROR_INT
|
||||
|
|
@ -251,7 +251,7 @@ contains
|
|||
do j = 1, p % n_coord - 1
|
||||
if (p % coord(j + 1) % rotated) then
|
||||
! If next level is rotated, apply rotation matrix
|
||||
p % coord(j + 1) % uvw = matmul(cells(p % coord(j) % cell) % &
|
||||
p % coord(j + 1) % uvw = matmul(cells(p % coord(j) % cell + 1) % &
|
||||
rotation_matrix, p % coord(j) % uvw)
|
||||
else
|
||||
! Otherwise, copy this level's direction
|
||||
|
|
@ -467,21 +467,8 @@ contains
|
|||
! ==========================================================================
|
||||
! SEARCH NEIGHBOR LISTS FOR NEXT CELL
|
||||
|
||||
if (p % surface > 0 .and. allocated(surf%neighbor_pos)) then
|
||||
! If coming from negative side of surface, search all the neighboring
|
||||
! cells on the positive side
|
||||
|
||||
call find_cell(p, found, surf%neighbor_pos)
|
||||
if (found) return
|
||||
|
||||
elseif (p % surface < 0 .and. allocated(surf%neighbor_neg)) then
|
||||
! If coming from positive side of surface, search all the neighboring
|
||||
! cells on the negative side
|
||||
|
||||
call find_cell(p, found, surf%neighbor_neg)
|
||||
if (found) return
|
||||
|
||||
end if
|
||||
call find_cell(p, found, p % surface)
|
||||
if (found) return
|
||||
|
||||
! ==========================================================================
|
||||
! COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module volume_calc
|
|||
use constants
|
||||
use error, only: write_message
|
||||
use geometry, only: find_cell
|
||||
use geometry_header, only: universes, cells
|
||||
use geometry_header, only: cells, universe_id
|
||||
use hdf5_interface, only: file_open, file_close, write_attribute, &
|
||||
create_group, close_group, write_dataset, HID_T
|
||||
use output, only: header, time_stamp
|
||||
|
|
@ -205,7 +205,7 @@ contains
|
|||
elseif (this % domain_type == FILTER_CELL) THEN
|
||||
do level = 1, p % n_coord
|
||||
do i_domain = 1, size(this % domain_id)
|
||||
if (cells(p % coord(level) % cell) % id() &
|
||||
if (cells(p % coord(level) % cell + 1) % id() &
|
||||
== this % domain_id(i_domain)) then
|
||||
i_material = p % material
|
||||
call check_hit(i_domain, i_material, indices, hits, n_mat)
|
||||
|
|
@ -216,7 +216,7 @@ contains
|
|||
elseif (this % domain_type == FILTER_UNIVERSE) then
|
||||
do level = 1, p % n_coord
|
||||
do i_domain = 1, size(this % domain_id)
|
||||
if (universes(p % coord(level) % universe) % id == &
|
||||
if (universe_id(p % coord(level) % universe) == &
|
||||
this % domain_id(i_domain)) then
|
||||
i_material = p % material
|
||||
call check_hit(i_domain, i_material, indices, hits, n_mat)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ module xml_interface
|
|||
|
||||
interface get_node_value
|
||||
module procedure get_node_value_bool
|
||||
module procedure get_node_value_cbool
|
||||
module procedure get_node_value_integer
|
||||
module procedure get_node_value_long
|
||||
module procedure get_node_value_double
|
||||
|
|
@ -118,6 +119,16 @@ contains
|
|||
end if
|
||||
end subroutine get_node_value_bool
|
||||
|
||||
subroutine get_node_value_cbool(node, name, val)
|
||||
type(XMLNode), intent(in) :: node
|
||||
character(*), intent(in) :: name
|
||||
logical(kind=C_BOOL), intent(out) :: val
|
||||
|
||||
logical :: val_
|
||||
call get_node_value_bool(node, name, val_)
|
||||
val = val_
|
||||
end subroutine get_node_value_cbool
|
||||
|
||||
!===============================================================================
|
||||
! GET_NODE_VALUE_INTEGER returns a integer value from an attribute or node
|
||||
!===============================================================================
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0"?>
|
||||
<geometry>
|
||||
|
||||
<surface id="1" type="sphere" coeffs="0 0 0 10" boundary="vacuum"/>
|
||||
<surface id="2" type="z-plane" coeffs="-100" />
|
||||
<surface id="3" type="z-plane" coeffs="100" />
|
||||
<surface id="1" type="sphere" coeffs="0 0 0 10" boundary="vacuum" />
|
||||
<surface id="2" type="sphere" coeffs="1 0 0 5" />
|
||||
|
||||
<cell id="1" fill="2" rotation="45 45 45" region="-1" />
|
||||
<cell id="2" universe="2" material="1" region="2 -3" />
|
||||
<cell id="1" fill="2" rotation="10 20 30" region="-1" />
|
||||
<cell id="2" universe="2" material="1" region="-2" />
|
||||
<cell id="3" universe="2" material="2" region="2" />
|
||||
|
||||
</geometry>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,13 @@
|
|||
<materials>
|
||||
|
||||
<material id="1">
|
||||
<density value="4.5" units="g/cc" />
|
||||
<density value="10" units="g/cc" />
|
||||
<nuclide name="U235" ao="1.0" />
|
||||
</material>
|
||||
|
||||
<material id="2">
|
||||
<density value="0.1" units="g/cc" />
|
||||
<nuclide name="H1" ao="0.1" />
|
||||
</material>
|
||||
|
||||
</materials>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
2.943619E-01 3.309646E-03
|
||||
4.240695E-01 8.013236E-03
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0"?>
|
||||
<geometry>
|
||||
|
||||
<surface id="1" type="sphere" coeffs="0 0 0 10" boundary="vacuum"/>
|
||||
<surface id="2" type="z-plane" coeffs="-100" />
|
||||
<surface id="3" type="z-plane" coeffs="100" />
|
||||
<surface id="1" type="sphere" coeffs="0 0 0 10" boundary="vacuum" />
|
||||
<surface id="2" type="sphere" coeffs="0 0 0 5" />
|
||||
|
||||
<cell id="1" fill="2" translation="2.3 5.0 -10.0" region="-1" />
|
||||
<cell id="2" universe="2" material="1" region="2 -3" />
|
||||
<cell id="1" fill="2" translation="1 2 3" region="-1" />
|
||||
<cell id="2" universe="2" material="1" region="-2" />
|
||||
<cell id="3" universe="2" material="2" region="2" />
|
||||
|
||||
</geometry>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,13 @@
|
|||
<materials>
|
||||
|
||||
<material id="1">
|
||||
<density value="4.5" units="g/cc" />
|
||||
<density value="10" units="g/cc" />
|
||||
<nuclide name="U235" ao="1.0" />
|
||||
</material>
|
||||
|
||||
<material id="2">
|
||||
<density value="0.1" units="g/cc" />
|
||||
<nuclide name="H1" ao="0.1" />
|
||||
</material>
|
||||
|
||||
</materials>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
2.943619E-01 3.309646E-03
|
||||
4.101355E-01 1.577552E-02
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue