mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-26 21:25:36 -04:00
Merge remote-tracking branch 'upstream/develop' into cpp_tallies
This commit is contained in:
commit
0c8ea4f31f
149 changed files with 6802 additions and 7291 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
|
||||
|
|
@ -314,7 +312,6 @@ add_library(libopenmc SHARED
|
|||
src/material_header.F90
|
||||
src/math.F90
|
||||
src/matrix_header.F90
|
||||
src/mesh.F90
|
||||
src/mesh_header.F90
|
||||
src/message_passing.F90
|
||||
src/mgxs_data.F90
|
||||
|
|
@ -341,8 +338,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
|
||||
|
|
@ -384,22 +379,28 @@ add_library(libopenmc SHARED
|
|||
src/tallies/trigger.F90
|
||||
src/tallies/trigger_header.F90
|
||||
src/cell.cpp
|
||||
src/cmfd_execute.cpp
|
||||
src/distribution.cpp
|
||||
src/distribution_angle.cpp
|
||||
src/distribution_energy.cpp
|
||||
src/distribution_multi.cpp
|
||||
src/distribution_spatial.cpp
|
||||
src/eigenvalue.cpp
|
||||
src/endf.cpp
|
||||
src/initialize.cpp
|
||||
src/finalize.cpp
|
||||
src/geometry.cpp
|
||||
src/geometry_aux.cpp
|
||||
src/hdf5_interface.cpp
|
||||
src/lattice.cpp
|
||||
src/material.cpp
|
||||
src/math_functions.cpp
|
||||
src/mesh.cpp
|
||||
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 +415,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/tallies/tally_filter.cpp
|
||||
src/thermal.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);
|
||||
|
|
@ -38,6 +37,7 @@ extern "C" {
|
|||
int openmc_filter_set_type(int32_t index, const char* type);
|
||||
int openmc_finalize();
|
||||
int openmc_find_cell(double* xyz, int32_t* index, int32_t* instance);
|
||||
int openmc_fission_bank(struct Bank** ptr, int64_t* n);
|
||||
int openmc_get_cell_index(int32_t id, int32_t* index);
|
||||
int openmc_get_filter_index(int32_t id, int32_t* index);
|
||||
void openmc_get_filter_next_id(int32_t* id);
|
||||
|
|
@ -57,6 +57,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);
|
||||
|
|
@ -71,7 +72,7 @@ extern "C" {
|
|||
int openmc_mesh_get_params(int32_t index, double** ll, double** ur, double** width, int* n);
|
||||
int openmc_mesh_set_id(int32_t index, int32_t id);
|
||||
int openmc_mesh_set_dimension(int32_t index, int n, const int* dims);
|
||||
int openmc_mesh_set_params(int32_t index, const double* ll, const double* ur, const double* width, int n);
|
||||
int openmc_mesh_set_params(int32_t index, int n, const double* ll, const double* ur, const double* width);
|
||||
int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh);
|
||||
int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh);
|
||||
int openmc_next_batch(int* status);
|
||||
|
|
@ -84,7 +85,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);
|
||||
|
|
@ -136,16 +136,11 @@ extern "C" {
|
|||
extern char openmc_err_msg[256];
|
||||
extern double openmc_keff;
|
||||
extern double openmc_keff_std;
|
||||
extern int32_t gen_per_batch;
|
||||
extern int32_t n_batches;
|
||||
extern int32_t n_cells;
|
||||
extern int32_t n_filters;
|
||||
extern int32_t n_inactive;
|
||||
extern int32_t n_lattices;
|
||||
extern int32_t n_materials;
|
||||
extern int32_t n_meshes;
|
||||
extern int n_nuclides;
|
||||
extern int64_t n_particles;
|
||||
extern int32_t n_plots;
|
||||
extern int32_t n_realizations;
|
||||
extern int32_t n_sab_tables;
|
||||
|
|
@ -153,9 +148,7 @@ extern "C" {
|
|||
extern int32_t n_surfaces;
|
||||
extern int32_t n_tallies;
|
||||
extern int32_t n_universes;
|
||||
extern int openmc_run_mode;
|
||||
extern bool openmc_simulation_initialized;
|
||||
extern int openmc_verbosity;
|
||||
|
||||
// Variables that are shared by necessity (can be removed from public header
|
||||
// later)
|
||||
|
|
@ -165,13 +158,6 @@ extern "C" {
|
|||
extern int openmc_rank;
|
||||
extern int64_t openmc_work;
|
||||
|
||||
// Run modes
|
||||
const int RUN_MODE_FIXEDSOURCE = 1;
|
||||
const int RUN_MODE_EIGENVALUE = 2;
|
||||
const int RUN_MODE_PLOTTING = 3;
|
||||
const int RUN_MODE_PARTICLE = 4;
|
||||
const int RUN_MODE_VOLUME = 5;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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() {};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,16 +11,9 @@
|
|||
|
||||
namespace openmc {
|
||||
|
||||
// TODO: Replace with xtensor/other library?
|
||||
typedef std::vector<double> double_1dvec;
|
||||
typedef std::vector<std::vector<double> > double_2dvec;
|
||||
typedef std::vector<std::vector<std::vector<double> > > double_3dvec;
|
||||
typedef std::vector<std::vector<std::vector<std::vector<double> > > > double_4dvec;
|
||||
typedef std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > > double_5dvec;
|
||||
typedef std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > > > double_6dvec;
|
||||
typedef std::vector<int> int_1dvec;
|
||||
typedef std::vector<std::vector<int> > int_2dvec;
|
||||
typedef std::vector<std::vector<std::vector<int> > > int_3dvec;
|
||||
using double_2dvec = std::vector<std::vector<double>>;
|
||||
using double_3dvec = std::vector<std::vector<std::vector<double>>>;
|
||||
using double_4dvec = std::vector<std::vector<std::vector<std::vector<double>>>>;
|
||||
|
||||
// ============================================================================
|
||||
// VERSIONING NUMBERS
|
||||
|
|
@ -431,6 +424,13 @@ enum class Interpolation {
|
|||
histogram, lin_lin, lin_log, log_lin, log_log
|
||||
};
|
||||
|
||||
// Run modes
|
||||
constexpr int RUN_MODE_FIXEDSOURCE {1};
|
||||
constexpr int RUN_MODE_EIGENVALUE {2};
|
||||
constexpr int RUN_MODE_PLOTTING {3};
|
||||
constexpr int RUN_MODE_PARTICLE {4};
|
||||
constexpr int RUN_MODE_VOLUME {5};
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_CONSTANTS_H
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
41
include/openmc/eigenvalue.h
Normal file
41
include/openmc/eigenvalue.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef OPENMC_EIGENVALUE_H
|
||||
#define OPENMC_EIGENVALUE_H
|
||||
|
||||
#include <cstdint> // for int64_t
|
||||
#include <vector>
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
|
||||
#include "openmc/particle.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
extern std::vector<double> entropy; //!< Shannon entropy at each generation
|
||||
extern xt::xtensor<double, 1> source_frac; //!< Source fraction for UFS
|
||||
|
||||
extern "C" int64_t n_bank;
|
||||
#pragma omp threadprivate(n_bank)
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
//! Calculates the Shannon entropy of the fission source distribution to assess
|
||||
//! source convergence
|
||||
extern "C" void shannon_entropy();
|
||||
|
||||
//! Determines the source fraction in each UFS mesh cell and reweights the
|
||||
//! source bank so that the sum of the weights is equal to n_particles. The
|
||||
//! 'source_frac' variable is used later to bias the production of fission sites
|
||||
extern "C" void ufs_count_sites();
|
||||
|
||||
//! Get UFS weight corresponding to particle's location
|
||||
extern "C" double ufs_get_weight(const Particle* p);
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_EIGENVALUE_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.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "xtensor/xarray.hpp"
|
||||
|
||||
#include "openmc/position.h"
|
||||
#include "openmc/error.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
|
|
@ -36,43 +37,16 @@ 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);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name, std::vector<double>& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<double> >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<int> >& result, bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<double> > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<int> > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<double> > > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
std::vector<hsize_t> attribute_shape(hid_t obj_id, const char* name);
|
||||
std::vector<std::string> dataset_names(hid_t group_id);
|
||||
void ensure_exists(hid_t group_id, const char* name);
|
||||
|
|
@ -230,7 +204,7 @@ read_attribute(hid_t obj_id, const char* name, std::vector<std::string>& vec)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
// Templates/overloads for read_dataset
|
||||
// Templates/overloads for read_dataset and related methods
|
||||
//==============================================================================
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -288,6 +262,40 @@ void read_dataset(hid_t obj_id, const char* name, xt::xarray<T>& arr, bool indep
|
|||
close_dataset(dset);
|
||||
}
|
||||
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
void read_dataset_as_shape(hid_t obj_id, const char* name,
|
||||
xt::xtensor<T, N>& arr, bool indep=false)
|
||||
{
|
||||
hid_t dset = open_dataset(obj_id, name);
|
||||
|
||||
// Allocate new array to read data into
|
||||
std::size_t size = 1;
|
||||
for (const auto x : arr.shape())
|
||||
size *= x;
|
||||
T* buffer = new T[size];
|
||||
|
||||
// Read data from attribute
|
||||
read_dataset(dset, nullptr, H5TypeMap<T>::type_id, buffer, indep);
|
||||
|
||||
// Adapt into xarray
|
||||
arr = xt::adapt(buffer, size, xt::acquire_ownership(), arr.shape());
|
||||
|
||||
close_dataset(dset);
|
||||
}
|
||||
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor<T, N>& result,
|
||||
bool must_have=false)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
read_dataset_as_shape(obj_id, name, result, true);
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Templates/overloads for write_attribute
|
||||
//==============================================================================
|
||||
|
|
@ -295,7 +303,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
|
||||
|
|
@ -311,6 +319,14 @@ write_attribute(hid_t obj_id, const char* name, const std::array<T, N>& buffer)
|
|||
write_attr(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data());
|
||||
}
|
||||
|
||||
template<typename T> inline void
|
||||
write_attribute(hid_t obj_id, const char* name, const std::vector<T>& buffer)
|
||||
{
|
||||
hsize_t dims[] {buffer.size()};
|
||||
write_attr(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data());
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// Templates/overloads for write_dataset
|
||||
//==============================================================================
|
||||
|
|
@ -334,6 +350,22 @@ 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);
|
||||
}
|
||||
|
||||
template<typename T> inline void
|
||||
write_dataset(hid_t obj_id, const char* name, const xt::xarray<T>& arr)
|
||||
{
|
||||
auto s = arr.shape();
|
||||
std::vector<hsize_t> dims {s.cbegin(), s.cend()};
|
||||
write_dataset(obj_id, dims.size(), dims.data(), name, H5TypeMap<T>::type_id,
|
||||
arr.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);
|
||||
|
|
|
|||
131
include/openmc/mesh.h
Normal file
131
include/openmc/mesh.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
//! \file mesh.h
|
||||
//! \brief Mesh types used for tallies, Shannon entropy, CMFD, etc.
|
||||
|
||||
#ifndef OPENMC_MESH_H
|
||||
#define OPENMC_MESH_H
|
||||
|
||||
#include <memory> // for unique_ptr
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "xtensor/xarray.hpp"
|
||||
|
||||
#include "openmc/particle.h"
|
||||
#include "openmc/position.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
//! Tessellation of n-dimensional Euclidean space by congruent squares or cubes
|
||||
//==============================================================================
|
||||
|
||||
class RegularMesh {
|
||||
public:
|
||||
// Constructors
|
||||
RegularMesh() = default;
|
||||
RegularMesh(pugi::xml_node node);
|
||||
|
||||
// Methods
|
||||
|
||||
//! Determine which bins were crossed by a particle
|
||||
//!
|
||||
//! \param[in] p Particle to check
|
||||
//! \param[out] bins Bins that were crossed
|
||||
//! \param[out] lengths Fraction of tracklength in each bin
|
||||
void bins_crossed(const Particle* p, std::vector<int>& bins,
|
||||
std::vector<double>& lengths) const;
|
||||
|
||||
//! Determine which surface bins were crossed by a particle
|
||||
//!
|
||||
//! \param[in] p Particle to check
|
||||
//! \param[out] bins Surface bins that were crossed
|
||||
void surface_bins_crossed(const Particle* p, std::vector<int>& bins) const;
|
||||
|
||||
//! Get bin at a given position in space
|
||||
//!
|
||||
//! \param[in] r Position to get bin for
|
||||
//! \return Mesh bin
|
||||
int get_bin(Position r) const;
|
||||
|
||||
//! Get bin given mesh indices
|
||||
//!
|
||||
//! \param[in] Array of mesh indices
|
||||
//! \return Mesh bin
|
||||
int get_bin_from_indices(const int* ijk) const;
|
||||
|
||||
//! Get mesh indices given a position
|
||||
//!
|
||||
//! \param[in] r Position to get indices for
|
||||
//! \param[out] ijk Array of mesh indices
|
||||
//! \param[out] in_mesh Whether position is in mesh
|
||||
void get_indices(Position r, int* ijk, bool* in_mesh) const;
|
||||
|
||||
//! Get mesh indices corresponding to a mesh bin
|
||||
//!
|
||||
//! \param[in] bin Mesh bin
|
||||
//! \param[out] ijk Mesh indices
|
||||
void get_indices_from_bin(int bin, int* ijk) const;
|
||||
|
||||
//! Check if a line connected by two points intersects the mesh
|
||||
//!
|
||||
//! \param[in] r0 Starting position
|
||||
//! \param[in] r1 Ending position
|
||||
//! \return Whether line connecting r0 and r1 intersects mesh
|
||||
bool intersects(Position r0, Position r1) const;
|
||||
|
||||
//! Write mesh data to an HDF5 group
|
||||
//!
|
||||
//! \param[in] group HDF5 group
|
||||
void to_hdf5(hid_t group) const;
|
||||
|
||||
//! Count number of bank sites in each mesh bin / energy bin
|
||||
//!
|
||||
//! \param[in] n Number of bank sites
|
||||
//! \param[in] bank Array of bank sites
|
||||
//! \param[in] n_energy Number of energies
|
||||
//! \param[in] energies Array of energies
|
||||
//! \param[out] Whether any bank sites are outside the mesh
|
||||
//! \return Array indicating number of sites in each mesh/energy bin
|
||||
xt::xarray<double> count_sites(int64_t n, const Bank* bank,
|
||||
int n_energy, const double* energies, bool* outside) const;
|
||||
|
||||
int id_ {-1}; //!< User-specified ID
|
||||
int n_dimension_; //!< Number of dimensions
|
||||
double volume_frac_; //!< Volume fraction of each mesh element
|
||||
xt::xarray<int> shape_; //!< Number of mesh elements in each dimension
|
||||
xt::xarray<double> lower_left_; //!< Lower-left coordinates of mesh
|
||||
xt::xarray<double> upper_right_; //!< Upper-right coordinates of mesh
|
||||
xt::xarray<double> width_; //!< Width of each mesh element
|
||||
|
||||
private:
|
||||
bool intersects_1d(Position r0, Position r1) const;
|
||||
bool intersects_2d(Position r0, Position r1) const;
|
||||
bool intersects_3d(Position r0, Position r1) const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
//! Read meshes from either settings/tallies
|
||||
//! \param[in] root XML node
|
||||
extern "C" void read_meshes(pugi::xml_node* root);
|
||||
|
||||
//! Write mesh data to an HDF5 group
|
||||
//! \param[in] group HDF5 group
|
||||
extern "C" void meshes_to_hdf5(hid_t group);
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
extern std::vector<std::unique_ptr<RegularMesh>> meshes;
|
||||
|
||||
extern std::unordered_map<int32_t, int32_t> mesh_map;
|
||||
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_MESH_H
|
||||
|
|
@ -10,6 +10,7 @@ namespace mpi {
|
|||
|
||||
extern int rank;
|
||||
extern int n_procs;
|
||||
extern bool master;
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
extern MPI_Datatype bank;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/xsdata.h"
|
||||
|
|
@ -35,7 +37,7 @@ struct CacheData {
|
|||
class Mgxs {
|
||||
private:
|
||||
|
||||
double_1dvec kTs; // temperature in eV (k * T)
|
||||
xt::xtensor<double, 1> kTs; // temperature in eV (k * T)
|
||||
int scatter_format; // flag for if this is legendre, histogram, or tabular
|
||||
int num_delayed_groups; // number of delayed neutron groups
|
||||
int num_groups; // number of energy groups
|
||||
|
|
@ -44,8 +46,8 @@ class Mgxs {
|
|||
bool is_isotropic; // used to skip search for angle indices if isotropic
|
||||
int n_pol;
|
||||
int n_azi;
|
||||
double_1dvec polar;
|
||||
double_1dvec azimuthal;
|
||||
std::vector<double> polar;
|
||||
std::vector<double> azimuthal;
|
||||
|
||||
//! \brief Initializes the Mgxs object metadata
|
||||
//!
|
||||
|
|
@ -62,10 +64,10 @@ class Mgxs {
|
|||
//! @param in_polar Polar angle grid.
|
||||
//! @param in_azimuthal Azimuthal angle grid.
|
||||
void
|
||||
init(const std::string& in_name, double in_awr, const double_1dvec& in_kTs,
|
||||
init(const std::string& in_name, double in_awr, const std::vector<double>& in_kTs,
|
||||
bool in_fissionable, int in_scatter_format, int in_num_groups,
|
||||
int in_num_delayed_groups, bool in_is_isotropic,
|
||||
const double_1dvec& in_polar, const double_1dvec& in_azimuthal);
|
||||
const std::vector<double>& in_polar, const std::vector<double>& in_azimuthal);
|
||||
|
||||
//! \brief Initializes the Mgxs object metadata from the HDF5 file
|
||||
//!
|
||||
|
|
@ -80,8 +82,8 @@ class Mgxs {
|
|||
//! @param method Method of choosing nearest temperatures.
|
||||
void
|
||||
metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
||||
int in_num_delayed_groups, const double_1dvec& temperature,
|
||||
double tolerance, int_1dvec& temps_to_read, int& order_dim,
|
||||
int in_num_delayed_groups, const std::vector<double>& temperature,
|
||||
double tolerance, std::vector<int>& temps_to_read, int& order_dim,
|
||||
int& method);
|
||||
|
||||
//! \brief Performs the actual act of combining the microscopic data for a
|
||||
|
|
@ -93,8 +95,8 @@ class Mgxs {
|
|||
//! corresponds to the temperature of interest.
|
||||
//! @param this_t The temperature index of the macroscopic object.
|
||||
void
|
||||
combine(const std::vector<Mgxs*>& micros, const double_1dvec& scalars,
|
||||
const int_1dvec& micro_ts, int this_t);
|
||||
combine(const std::vector<Mgxs*>& micros, const std::vector<double>& scalars,
|
||||
const std::vector<int>& micro_ts, int this_t);
|
||||
|
||||
//! \brief Checks to see if this and that are able to be combined
|
||||
//!
|
||||
|
|
@ -128,7 +130,7 @@ class Mgxs {
|
|||
//! provides the number of points to use in the tabular representation.
|
||||
//! @param method Method of choosing nearest temperatures.
|
||||
Mgxs(hid_t xs_id, int energy_groups,
|
||||
int delayed_groups, const double_1dvec& temperature, double tolerance,
|
||||
int delayed_groups, const std::vector<double>& temperature, double tolerance,
|
||||
int max_order, bool legendre_to_tabular,
|
||||
int legendre_to_tabular_points, int& method);
|
||||
|
||||
|
|
@ -141,8 +143,8 @@ class Mgxs {
|
|||
//! @param atom_densities Atom densities of those microscopic quantities.
|
||||
//! @param tolerance Tolerance of temperature selection method.
|
||||
//! @param method Method of choosing nearest temperatures.
|
||||
Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
||||
const std::vector<Mgxs*>& micros, const double_1dvec& atom_densities,
|
||||
Mgxs(const std::string& in_name, const std::vector<double>& mat_kTs,
|
||||
const std::vector<Mgxs*>& micros, const std::vector<double>& atom_densities,
|
||||
double tolerance, int& method);
|
||||
|
||||
//! \brief Provides a cross section value given certain parameters
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
28
include/openmc/output.h
Normal file
28
include/openmc/output.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//! \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();
|
||||
|
||||
extern "C" void title();
|
||||
|
||||
} // 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,8 +154,14 @@ 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();
|
||||
void write_restart() const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef OPENMC_POSITION_H
|
||||
#define OPENMC_POSITION_H
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -12,6 +15,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);
|
||||
|
|
@ -43,6 +47,9 @@ struct Position {
|
|||
inline double dot(Position other) {
|
||||
return x*other.x + y*other.y + z*other.z;
|
||||
}
|
||||
inline double norm() {
|
||||
return std::sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
// Data members
|
||||
double x = 0.;
|
||||
|
|
@ -63,6 +70,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 +84,4 @@ using Direction = Position;
|
|||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_POSITION_H
|
||||
#endif // OPENMC_POSITION_H
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -25,23 +27,25 @@ class ScattData {
|
|||
protected:
|
||||
//! \brief Initializes the attributes of the base class.
|
||||
void
|
||||
base_init(int order, const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_energy, const double_2dvec& in_mult);
|
||||
base_init(int order, const xt::xtensor<int, 1>& in_gmin,
|
||||
const xt::xtensor<int, 1>& in_gmax, const double_2dvec& in_energy,
|
||||
const double_2dvec& in_mult);
|
||||
|
||||
//! \brief Combines microscopic ScattDatas into a macroscopic one.
|
||||
void
|
||||
base_combine(int max_order, const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax,
|
||||
double_2dvec& sparse_mult, double_3dvec& sparse_scatter);
|
||||
base_combine(size_t max_order, const std::vector<ScattData*>& those_scatts,
|
||||
const std::vector<double>& scalars, xt::xtensor<int, 1>& in_gmin,
|
||||
xt::xtensor<int, 1>& in_gmax, double_2dvec& sparse_mult,
|
||||
double_3dvec& sparse_scatter);
|
||||
|
||||
public:
|
||||
|
||||
double_2dvec energy; // Normalized p0 matrix for sampling Eout
|
||||
double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt)
|
||||
double_3dvec dist; // Angular distribution
|
||||
int_1dvec gmin; // minimum outgoing group
|
||||
int_1dvec gmax; // maximum outgoing group
|
||||
double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}}
|
||||
double_2dvec energy; // Normalized p0 matrix for sampling Eout
|
||||
double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt)
|
||||
double_3dvec dist; // Angular distribution
|
||||
xt::xtensor<double, 1> gmin; // minimum outgoing group
|
||||
xt::xtensor<double, 1> gmax; // maximum outgoing group
|
||||
xt::xtensor<double, 1> scattxs; // Isotropic Sigma_{s,g_{in}}
|
||||
|
||||
//! \brief Calculates the value of normalized f(mu).
|
||||
//!
|
||||
|
|
@ -72,7 +76,7 @@ class ScattData {
|
|||
//! @param in_mult Input sparse multiplicity matrix
|
||||
//! @param coeffs Input sparse scattering matrix
|
||||
virtual void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
init(const xt::xtensor<int, 1>& in_gmin, const xt::xtensor<int, 1>& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs) = 0;
|
||||
|
||||
//! \brief Combines the microscopic data.
|
||||
|
|
@ -81,7 +85,7 @@ class ScattData {
|
|||
//! @param scalars Scalars to multiply the microscopic data by.
|
||||
virtual void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars) = 0;
|
||||
const std::vector<double>& scalars) = 0;
|
||||
|
||||
//! \brief Getter for the dimensionality of the scattering order.
|
||||
//!
|
||||
|
|
@ -89,7 +93,7 @@ class ScattData {
|
|||
//! of points, and for Histogram this is the number of bins.
|
||||
//!
|
||||
//! @return The order.
|
||||
virtual int
|
||||
virtual size_t
|
||||
get_order() = 0;
|
||||
|
||||
//! \brief Builds a dense scattering matrix from the constituent parts
|
||||
|
|
@ -97,8 +101,8 @@ class ScattData {
|
|||
//! @param max_order If Legendre this is the maximum value of "n" in "Pn"
|
||||
//! requested; ignored otherwise.
|
||||
//! @return The dense scattering matrix.
|
||||
virtual double_3dvec
|
||||
get_matrix(int max_order) = 0;
|
||||
virtual xt::xtensor<double, 3>
|
||||
get_matrix(size_t max_order) = 0;
|
||||
|
||||
//! \brief Samples the outgoing energy from the ScattData info.
|
||||
//!
|
||||
|
|
@ -142,12 +146,12 @@ class ScattDataLegendre: public ScattData {
|
|||
public:
|
||||
|
||||
void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
init(const xt::xtensor<int, 1>& in_gmin, const xt::xtensor<int, 1>& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs);
|
||||
|
||||
void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars);
|
||||
const std::vector<double>& scalars);
|
||||
|
||||
//! \brief Find the maximal value of the angular distribution to use as a
|
||||
// bounding box with rejection sampling.
|
||||
|
|
@ -160,11 +164,11 @@ class ScattDataLegendre: public ScattData {
|
|||
void
|
||||
sample(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
int
|
||||
size_t
|
||||
get_order() {return dist[0][0].size() - 1;};
|
||||
|
||||
double_3dvec
|
||||
get_matrix(int max_order);
|
||||
xt::xtensor<double, 3>
|
||||
get_matrix(size_t max_order);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -176,19 +180,19 @@ class ScattDataHistogram: public ScattData {
|
|||
|
||||
protected:
|
||||
|
||||
double_1dvec mu; // Angle distribution mu bin boundaries
|
||||
double dmu; // Quick storage of the spacing between the mu bin points
|
||||
double_3dvec fmu; // The angular distribution histogram
|
||||
xt::xtensor<double, 1> mu; // Angle distribution mu bin boundaries
|
||||
double dmu; // Quick storage of the mu spacing
|
||||
double_3dvec fmu; // The angular distribution histogram
|
||||
|
||||
public:
|
||||
|
||||
void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
init(const xt::xtensor<int, 1>& in_gmin, const xt::xtensor<int, 1>& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs);
|
||||
|
||||
void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars);
|
||||
const std::vector<double>& scalars);
|
||||
|
||||
double
|
||||
calc_f(int gin, int gout, double mu);
|
||||
|
|
@ -196,11 +200,11 @@ class ScattDataHistogram: public ScattData {
|
|||
void
|
||||
sample(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
int
|
||||
size_t
|
||||
get_order() {return dist[0][0].size();};
|
||||
|
||||
double_3dvec
|
||||
get_matrix(int max_order);
|
||||
xt::xtensor<double, 3>
|
||||
get_matrix(size_t max_order);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -212,9 +216,9 @@ class ScattDataTabular: public ScattData {
|
|||
|
||||
protected:
|
||||
|
||||
double_1dvec mu; // Angle distribution mu grid points
|
||||
double dmu; // Quick storage of the spacing between the mu points
|
||||
double_3dvec fmu; // The angular distribution function
|
||||
xt::xtensor<double, 1> mu; // Angle distribution mu grid points
|
||||
double dmu; // Quick storage of the mu spacing
|
||||
double_3dvec fmu; // The angular distribution function
|
||||
|
||||
// Friend convert_legendre_to_tabular so it has access to protected
|
||||
// parameters
|
||||
|
|
@ -225,12 +229,12 @@ class ScattDataTabular: public ScattData {
|
|||
public:
|
||||
|
||||
void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
init(const xt::xtensor<int, 1>& in_gmin, const xt::xtensor<int, 1>& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs);
|
||||
|
||||
void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars);
|
||||
const std::vector<double>& scalars);
|
||||
|
||||
double
|
||||
calc_f(int gin, int gout, double mu);
|
||||
|
|
@ -238,10 +242,11 @@ class ScattDataTabular: public ScattData {
|
|||
void
|
||||
sample(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
int
|
||||
size_t
|
||||
get_order() {return dist[0][0].size();};
|
||||
|
||||
double_3dvec get_matrix(int max_order);
|
||||
xt::xtensor<double, 3>
|
||||
get_matrix(size_t max_order);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
//! \brief Settings for OpenMC
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "pugixml.hpp"
|
||||
|
|
@ -15,35 +16,84 @@ namespace openmc {
|
|||
// Global variable declarations
|
||||
//==============================================================================
|
||||
|
||||
// Defined on Fortran side
|
||||
extern "C" bool openmc_check_overlaps;
|
||||
extern "C" bool openmc_particle_restart_run;
|
||||
extern "C" bool openmc_restart_run;
|
||||
extern "C" bool openmc_write_all_tracks;
|
||||
namespace settings {
|
||||
|
||||
// Defined in .cpp
|
||||
// TODO: Make strings instead of char* once Fortran is gone
|
||||
extern "C" char* openmc_path_input;
|
||||
extern "C" char* openmc_path_statepoint;
|
||||
extern "C" char* openmc_path_sourcepoint;
|
||||
extern "C" char* openmc_path_particle_restart;
|
||||
extern std::string path_cross_sections;
|
||||
extern std::string path_multipole;
|
||||
extern std::string path_output;
|
||||
// Boolean flags
|
||||
extern "C" bool assume_separate; //!< assume tallies are spatially separate?
|
||||
extern "C" bool check_overlaps; //!< check overlaps in geometry?
|
||||
extern "C" bool cmfd_run; //!< use CMFD?
|
||||
extern "C" bool confidence_intervals; //!< use confidence intervals for results?
|
||||
extern "C" bool create_fission_neutrons; //!< create fission neutrons (fixed source)?
|
||||
extern "C" bool entropy_on; //!< calculate Shannon entropy?
|
||||
extern "C" bool legendre_to_tabular; //!< convert Legendre distributions to tabular?
|
||||
extern "C" bool output_summary; //!< write summary.h5?
|
||||
extern "C" bool output_tallies; //!< write tallies.out?
|
||||
extern "C" bool particle_restart_run; //!< particle restart run?
|
||||
extern "C" bool photon_transport; //!< photon transport turned on?
|
||||
extern "C" bool reduce_tallies; //!< reduce tallies at end of batch?
|
||||
extern "C" bool res_scat_on; //!< use resonance upscattering method?
|
||||
extern "C" bool restart_run; //!< restart run?
|
||||
extern "C" bool run_CE; //!< run with continuous-energy data?
|
||||
extern "C" bool source_latest; //!< write latest source at each batch?
|
||||
extern "C" bool source_separate; //!< write source to separate file?
|
||||
extern "C" bool source_write; //!< write source in HDF5 files?
|
||||
extern "C" bool survival_biasing; //!< use survival biasing?
|
||||
extern "C" bool temperature_multipole; //!< use multipole data?
|
||||
extern "C" bool trigger_on; //!< tally triggers enabled?
|
||||
extern "C" bool trigger_predict; //!< predict batches for triggers?
|
||||
extern "C" bool ufs_on; //!< uniform fission site method on?
|
||||
extern "C" bool urr_ptables_on; //!< use unresolved resonance prob. tables?
|
||||
extern "C" bool write_all_tracks; //!< write track files for every particle?
|
||||
extern "C" bool write_initial_source; //!< write out initial source file?
|
||||
|
||||
// Paths to various files
|
||||
extern std::string path_cross_sections; //!< path to cross_sections.xml
|
||||
extern std::string path_input; //!< directory where main .xml files resides
|
||||
extern std::string path_multipole; //!< directory containing multipole files
|
||||
extern std::string path_output; //!< directory where output files are written
|
||||
extern std::string path_particle_restart; //!< path to a particle restart file
|
||||
extern std::string path_source;
|
||||
extern std::string path_sourcepoint; //!< path to a source file
|
||||
extern std::string path_statepoint; //!< path to a statepoint file
|
||||
|
||||
extern int temperature_method;
|
||||
extern bool temperature_multipole;
|
||||
extern double temperature_tolerance;
|
||||
extern double temperature_default;
|
||||
extern std::array<double, 2> temperature_range;
|
||||
extern "C" int32_t index_entropy_mesh; //!< Index of entropy mesh in global mesh array
|
||||
extern "C" int32_t index_ufs_mesh; //!< Index of UFS mesh in global mesh array
|
||||
|
||||
extern "C" int32_t n_batches; //!< number of (inactive+active) batches
|
||||
extern "C" int32_t n_inactive; //!< number of inactive batches
|
||||
extern "C" int32_t gen_per_batch; //!< number of generations per batch
|
||||
extern "C" int64_t n_particles; //!< number of particles per generation
|
||||
|
||||
extern "C" int electron_treatment; //!< how to treat secondary electrons
|
||||
extern "C" double energy_cutoff[4]; //!< Energy cutoff in [eV] for each particle type
|
||||
extern "C" int legendre_to_tabular_points; //!< number of points to convert Legendres
|
||||
extern "C" int max_order; //!< Maximum Legendre order for multigroup data
|
||||
extern "C" int n_log_bins; //!< number of bins for logarithmic energy grid
|
||||
extern "C" int n_max_batches; //!< Maximum number of batches
|
||||
|
||||
extern "C" int res_scat_method; //!< resonance upscattering method
|
||||
extern "C" double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering
|
||||
extern "C" double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering
|
||||
extern "C" int run_mode; //!< Run mode (eigenvalue, fixed src, etc.)
|
||||
extern "C" int temperature_method; //!< method for choosing temperatures
|
||||
extern "C" double temperature_tolerance; //!< Tolerance in [K] on choosing temperatures
|
||||
extern "C" double temperature_default; //!< Default T in [K]
|
||||
extern "C" double temperature_range[2]; //!< Min/max T in [K] over which to load xs
|
||||
extern "C" int trace_batch; //!< Batch to trace particle on
|
||||
extern "C" int trace_gen; //!< Generation to trace particle on
|
||||
extern "C" int64_t trace_particle; //!< Particle ID to enable trace on
|
||||
extern "C" int trigger_batch_interval; //!< Batch interval for triggers
|
||||
extern "C" int verbosity; //!< How verbose to make output
|
||||
extern "C" double weight_cutoff; //!< Weight cutoff for Russian roulette
|
||||
extern "C" double weight_survive; //!< Survival weight after Russian roulette
|
||||
|
||||
} // namespace settings
|
||||
|
||||
//==============================================================================
|
||||
//! Read settings from XML file
|
||||
//! \param[in] root XML node for <settings>
|
||||
//==============================================================================
|
||||
extern "C" void read_settings_xml();
|
||||
|
||||
extern "C" void read_settings(pugi::xml_node* root);
|
||||
extern "C" void read_settings_xml_f(pugi::xml_node_struct* root_ptr);
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
#ifndef OPENMC_XML_INTERFACE_H
|
||||
#define OPENMC_XML_INTERFACE_H
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
#include <sstream> // for stringstream
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "pugixml.hpp"
|
||||
#include "xtensor/xarray.hpp"
|
||||
#include "xtensor/xadapt.hpp"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -38,5 +41,14 @@ std::vector<T> get_node_array(pugi::xml_node node, const char* name,
|
|||
return values;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
xt::xarray<T> get_node_xarray(pugi::xml_node node, const char* name,
|
||||
bool lowercase=false)
|
||||
{
|
||||
std::vector<T> v = get_node_array<T>(node, name, lowercase);
|
||||
std::vector<std::size_t> shape = {v.size()};
|
||||
return xt::adapt(v, shape);
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
#endif // OPENMC_XML_INTERFACE_H
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/scattdata.h"
|
||||
|
||||
|
|
@ -22,41 +24,77 @@ class XsData {
|
|||
private:
|
||||
//! \brief Reads scattering data from the HDF5 file
|
||||
void
|
||||
scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups,
|
||||
scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups,
|
||||
int scatter_format, int final_scatter_format, int order_data,
|
||||
int max_order, int legendre_to_tabular_points);
|
||||
|
||||
//! \brief Reads fission data from the HDF5 file
|
||||
void
|
||||
fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups,
|
||||
int delayed_groups, bool is_isotropic);
|
||||
fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups,
|
||||
size_t delayed_groups, bool is_isotropic);
|
||||
|
||||
//! \brief Reads fission data formatted as chi and nu-fission vectors from
|
||||
// the HDF5 file when beta is provided.
|
||||
void
|
||||
fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang,
|
||||
size_t energy_groups, size_t delayed_groups, bool is_isotropic);
|
||||
|
||||
//! \brief Reads fission data formatted as chi and nu-fission vectors from
|
||||
// the HDF5 file when beta is not provided.
|
||||
void
|
||||
fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang,
|
||||
size_t energy_groups, size_t delayed_groups);
|
||||
|
||||
//! \brief Reads fission data formatted as chi and nu-fission vectors from
|
||||
// the HDF5 file when no delayed data is provided.
|
||||
void
|
||||
fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang,
|
||||
size_t energy_groups);
|
||||
|
||||
//! \brief Reads fission data formatted as a nu-fission matrix from
|
||||
// the HDF5 file when beta is provided.
|
||||
void
|
||||
fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang,
|
||||
size_t energy_groups, size_t delayed_groups, bool is_isotropic);
|
||||
|
||||
//! \brief Reads fission data formatted as a nu-fission matrix from
|
||||
// the HDF5 file when beta is not provided.
|
||||
void
|
||||
fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang,
|
||||
size_t energy_groups, size_t delayed_groups);
|
||||
|
||||
//! \brief Reads fission data formatted as a nu-fission matrix from
|
||||
// the HDF5 file when no delayed data is provided.
|
||||
void
|
||||
fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang,
|
||||
size_t energy_groups);
|
||||
|
||||
public:
|
||||
|
||||
// The following quantities have the following dimensions:
|
||||
// [angle][incoming group]
|
||||
double_2dvec total;
|
||||
double_2dvec absorption;
|
||||
double_2dvec nu_fission;
|
||||
double_2dvec prompt_nu_fission;
|
||||
double_2dvec kappa_fission;
|
||||
double_2dvec fission;
|
||||
double_2dvec inverse_velocity;
|
||||
xt::xtensor<double, 2> total;
|
||||
xt::xtensor<double, 2> absorption;
|
||||
xt::xtensor<double, 2> nu_fission;
|
||||
xt::xtensor<double, 2> prompt_nu_fission;
|
||||
xt::xtensor<double, 2> kappa_fission;
|
||||
xt::xtensor<double, 2> fission;
|
||||
xt::xtensor<double, 2> inverse_velocity;
|
||||
|
||||
// decay_rate has the following dimensions:
|
||||
// [angle][delayed group]
|
||||
double_2dvec decay_rate;
|
||||
xt::xtensor<double, 2> decay_rate;
|
||||
// delayed_nu_fission has the following dimensions:
|
||||
// [angle][incoming group][delayed group]
|
||||
double_3dvec delayed_nu_fission;
|
||||
xt::xtensor<double, 3> delayed_nu_fission;
|
||||
// chi_prompt has the following dimensions:
|
||||
// [angle][incoming group][outgoing group]
|
||||
double_3dvec chi_prompt;
|
||||
xt::xtensor<double, 3> chi_prompt;
|
||||
// chi_delayed has the following dimensions:
|
||||
// [angle][incoming group][outgoing group][delayed group]
|
||||
double_4dvec chi_delayed;
|
||||
xt::xtensor<double, 4> chi_delayed;
|
||||
// scatter has the following dimensions: [angle]
|
||||
std::vector<std::shared_ptr<ScattData> > scatter;
|
||||
std::vector<std::shared_ptr<ScattData>> scatter;
|
||||
|
||||
XsData() = default;
|
||||
|
||||
|
|
@ -68,7 +106,7 @@ class XsData {
|
|||
//! @param scatter_format The scattering representation of the file.
|
||||
//! @param n_pol Number of polar angles.
|
||||
//! @param n_azi Number of azimuthal angles.
|
||||
XsData(int num_groups, int num_delayed_groups, bool fissionable,
|
||||
XsData(size_t num_groups, size_t num_delayed_groups, bool fissionable,
|
||||
int scatter_format, int n_pol, int n_azi);
|
||||
|
||||
//! \brief Loads the XsData object from the HDF5 file
|
||||
|
|
@ -101,7 +139,7 @@ class XsData {
|
|||
//! @param micros Microscopic objects to combine.
|
||||
//! @param scalars Scalars to multiply the microscopic data by.
|
||||
void
|
||||
combine(const std::vector<XsData*>& those_xs, const double_1dvec& scalars);
|
||||
combine(const std::vector<XsData*>& those_xs, const std::vector<double>& scalars);
|
||||
|
||||
//! \brief Checks to see if this and that are able to be combined
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ _dll.openmc_mesh_set_params.errcheck = _error_handler
|
|||
_dll.openmc_get_mesh_index.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_get_mesh_index.restype = c_int
|
||||
_dll.openmc_get_mesh_index.errcheck = _error_handler
|
||||
_dll.n_meshes.argtypes = []
|
||||
_dll.n_meshes.restype = c_int
|
||||
|
||||
|
||||
class Mesh(_FortranObjectWithID):
|
||||
|
|
@ -172,10 +174,10 @@ class _MeshMapping(Mapping):
|
|||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield Mesh(index=i + 1).id
|
||||
yield Mesh(index=i).id
|
||||
|
||||
def __len__(self):
|
||||
return c_int32.in_dll(_dll, 'n_meshes').value
|
||||
return _dll.n_meshes()
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(self))
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ class _Settings(object):
|
|||
generations_per_batch = _DLLGlobal(c_int32, 'gen_per_batch')
|
||||
inactive = _DLLGlobal(c_int32, 'n_inactive')
|
||||
particles = _DLLGlobal(c_int64, 'n_particles')
|
||||
verbosity = _DLLGlobal(c_int, 'openmc_verbosity')
|
||||
verbosity = _DLLGlobal(c_int, 'verbosity')
|
||||
|
||||
@property
|
||||
def run_mode(self):
|
||||
i = c_int.in_dll(_dll, 'openmc_run_mode').value
|
||||
i = c_int.in_dll(_dll, 'run_mode').value
|
||||
try:
|
||||
return _RUN_MODES[i]
|
||||
except KeyError:
|
||||
|
|
@ -32,7 +32,7 @@ class _Settings(object):
|
|||
|
||||
@run_mode.setter
|
||||
def run_mode(self, mode):
|
||||
current_idx = c_int.in_dll(_dll, 'openmc_run_mode')
|
||||
current_idx = c_int.in_dll(_dll, 'run_mode')
|
||||
for idx, mode_value in _RUN_MODES.items():
|
||||
if mode_value == mode:
|
||||
current_idx.value = idx
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from numbers import Integral
|
||||
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
|
|
@ -538,20 +540,20 @@ def pwr_assembly():
|
|||
return model
|
||||
|
||||
|
||||
def slab_mg(reps=None, as_macro=True):
|
||||
"""Create a one-group, 1D slab model.
|
||||
def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5'):
|
||||
"""Create a 1D slab model.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
reps : list, optional
|
||||
List of angular representations. Each item corresponds to materials and
|
||||
dictates the angular representation of the multi-group cross
|
||||
sections---isotropic ('iso') or angle-dependent ('ang'), and if Legendre
|
||||
scattering or tabular scattering ('mu') is used. Thus, items can be
|
||||
'ang', 'ang_mu', 'iso', or 'iso_mu'.
|
||||
num_regions : int, optional
|
||||
Number of regions in the problem, each with a unique MGXS dataset.
|
||||
Defaults to 1.
|
||||
|
||||
as_macro : bool, optional
|
||||
Whether :class:`openmc.Macroscopic` is used
|
||||
mat_names : Iterable of str, optional
|
||||
List of the material names to use; defaults to ['mat_1', 'mat_2',...].
|
||||
|
||||
mgxslib_name : str, optional
|
||||
MGXS Library file to use; defaults to '2g.h5'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -559,71 +561,82 @@ def slab_mg(reps=None, as_macro=True):
|
|||
One-group, 1D slab model
|
||||
|
||||
"""
|
||||
|
||||
openmc.check_type('num_regions', num_regions, Integral)
|
||||
openmc.check_greater_than('num_regions', num_regions, 0)
|
||||
if mat_names is not None:
|
||||
openmc.check_length('mat_names', mat_names, num_regions)
|
||||
openmc.check_iterable_type('mat_names', mat_names, str)
|
||||
else:
|
||||
mat_names = []
|
||||
for i in range(num_regions):
|
||||
mat_names.append('mat_' + str(i + 1))
|
||||
|
||||
# # Make Materials
|
||||
materials_file = openmc.Materials()
|
||||
macros = []
|
||||
mats = []
|
||||
for i in range(len(mat_names)):
|
||||
macros.append(openmc.Macroscopic('mat_' + str(i + 1)))
|
||||
mats.append(openmc.Material(name=mat_names[i]))
|
||||
mats[-1].set_density('macro', 1.0)
|
||||
mats[-1].add_macroscopic(macros[-1])
|
||||
|
||||
materials_file += mats
|
||||
|
||||
materials_file.cross_sections = mgxslib_name
|
||||
|
||||
# # Make Geometry
|
||||
rad_outer = 929.45
|
||||
# Set a cell boundary to exist for every material above (exclude the 0)
|
||||
rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:]
|
||||
|
||||
# Instantiate Universe
|
||||
root = openmc.Universe(universe_id=0, name='root universe')
|
||||
cells = []
|
||||
|
||||
surfs = []
|
||||
surfs.append(openmc.XPlane(x0=0., boundary_type='reflective'))
|
||||
for r, rad in enumerate(rads):
|
||||
if r == len(rads) - 1:
|
||||
surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum'))
|
||||
else:
|
||||
surfs.append(openmc.XPlane(x0=rad))
|
||||
|
||||
# Instantiate Cells
|
||||
cells = []
|
||||
for c in range(len(surfs) - 1):
|
||||
cells.append(openmc.Cell())
|
||||
cells[-1].region = (+surfs[c] & -surfs[c + 1])
|
||||
cells[-1].fill = mats[c]
|
||||
|
||||
# Register Cells with Universe
|
||||
root.add_cells(cells)
|
||||
|
||||
# Instantiate a Geometry, register the root Universe, and export to XML
|
||||
geometry_file = openmc.Geometry(root)
|
||||
|
||||
# # Make Settings
|
||||
# Instantiate a Settings object, set all runtime parameters
|
||||
settings_file = openmc.Settings()
|
||||
settings_file.energy_mode = "multi-group"
|
||||
settings_file.tabular_legendre = {'enable': False}
|
||||
settings_file.batches = 10
|
||||
settings_file.inactive = 5
|
||||
settings_file.particles = 1000
|
||||
|
||||
# Build source distribution
|
||||
INF = 1000.
|
||||
bounds = [0., -INF, -INF, rads[0], INF, INF]
|
||||
uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:])
|
||||
settings_file.source = openmc.source.Source(space=uniform_dist)
|
||||
|
||||
settings_file.output = {'summary': False}
|
||||
|
||||
model = openmc.model.Model()
|
||||
|
||||
# Define materials needed for 1D/1G slab problem
|
||||
mat_names = ['uo2', 'clad', 'lwtr']
|
||||
mgxs_reps = ['ang', 'ang_mu', 'iso', 'iso_mu']
|
||||
|
||||
if reps is None:
|
||||
reps = mgxs_reps
|
||||
|
||||
xs = []
|
||||
i = 0
|
||||
for mat in mat_names:
|
||||
for rep in reps:
|
||||
i += 1
|
||||
name = mat + '_' + rep
|
||||
xs.append(name)
|
||||
if as_macro:
|
||||
m = openmc.Material(name=str(i))
|
||||
m.set_density('macro', 1.)
|
||||
m.add_macroscopic(name)
|
||||
else:
|
||||
m = openmc.Material(name=str(i))
|
||||
m.set_density('atom/b-cm', 1.)
|
||||
m.add_nuclide(name, 1.0, 'ao')
|
||||
model.materials.append(m)
|
||||
|
||||
# Define the materials file
|
||||
model.xs_data = xs
|
||||
model.materials.cross_sections = "../../1d_mgxs.h5"
|
||||
|
||||
# Define surfaces.
|
||||
# Assembly/Problem Boundary
|
||||
left = openmc.XPlane(x0=0.0, boundary_type='reflective')
|
||||
right = openmc.XPlane(x0=10.0, boundary_type='reflective')
|
||||
bottom = openmc.YPlane(y0=0.0, boundary_type='reflective')
|
||||
top = openmc.YPlane(y0=10.0, boundary_type='reflective')
|
||||
|
||||
# for each material add a plane
|
||||
planes = [openmc.ZPlane(z0=0.0, boundary_type='reflective')]
|
||||
dz = round(5. / float(len(model.materials)), 4)
|
||||
for i in range(len(model.materials) - 1):
|
||||
planes.append(openmc.ZPlane(z0=dz * float(i + 1)))
|
||||
planes.append(openmc.ZPlane(z0=5.0, boundary_type='reflective'))
|
||||
|
||||
# Define cells for each material
|
||||
model.geometry.root_universe = openmc.Universe(name='root universe')
|
||||
xy = +left & -right & +bottom & -top
|
||||
for i, mat in enumerate(model.materials):
|
||||
c = openmc.Cell(fill=mat, region=xy & +planes[i] & -planes[i + 1])
|
||||
model.geometry.root_universe.add_cell(c)
|
||||
|
||||
model.settings.batches = 10
|
||||
model.settings.inactive = 5
|
||||
model.settings.particles = 100
|
||||
model.settings.source = openmc.Source(space=openmc.stats.Box(
|
||||
[0.0, 0.0, 0.0], [10.0, 10.0, 5.]))
|
||||
model.settings.energy_mode = "multi-group"
|
||||
|
||||
plot = openmc.Plot()
|
||||
plot.filename = 'mat'
|
||||
plot.origin = (5.0, 5.0, 2.5)
|
||||
plot.width = (2.5, 2.5)
|
||||
plot.basis = 'xz'
|
||||
plot.pixels = (3000, 3000)
|
||||
plot.color_by = 'material'
|
||||
model.plots.append(plot)
|
||||
model.geometry = geometry_file
|
||||
model.materials = materials_file
|
||||
model.settings = settings_file
|
||||
model.xs_data = macros
|
||||
|
||||
return model
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class ExpansionFilter(Filter):
|
|||
if type(self) is not type(other):
|
||||
return False
|
||||
else:
|
||||
return self.bins == other.bins
|
||||
return hash(self) == hash(other)
|
||||
|
||||
@property
|
||||
def order(self):
|
||||
|
|
@ -325,8 +325,8 @@ class ZernikeFilter(ExpansionFilter):
|
|||
|
||||
This filter allows scores to be multiplied by Zernike polynomials of the
|
||||
particle's position normalized to a given unit circle, up to a
|
||||
user-specified order. The standard Zernike polynomials follow the definition by
|
||||
Born and Wolf, *Principles of Optics* and are defined as
|
||||
user-specified order. The standard Zernike polynomials follow the
|
||||
definition by Born and Wolf, *Principles of Optics* and are defined as
|
||||
|
||||
.. math::
|
||||
Z_n^m(\rho, \theta) = R_n^m(\rho) \cos (m\theta), \quad m > 0
|
||||
|
|
@ -342,7 +342,7 @@ class ZernikeFilter(ExpansionFilter):
|
|||
\frac{n+m}{2} - k)! (\frac{n-m}{2} - k)!} \rho^{n-2k}.
|
||||
|
||||
With this definition, the integral of :math:`(Z_n^m)^2` over the unit disk
|
||||
is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where
|
||||
is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where
|
||||
:math:`\epsilon_m` is 2 if :math:`m` equals 0 and 1 otherwise.
|
||||
|
||||
Specifying a filter with order N tallies moments for all :math:`n` from 0
|
||||
|
|
@ -390,6 +390,9 @@ class ZernikeFilter(ExpansionFilter):
|
|||
def __hash__(self):
|
||||
string = type(self).__name__ + '\n'
|
||||
string += '{: <16}=\t{}\n'.format('\tOrder', self.order)
|
||||
string += '{: <16}=\t{}\n'.format('\tX', self.x)
|
||||
string += '{: <16}=\t{}\n'.format('\tY', self.y)
|
||||
string += '{: <16}=\t{}\n'.format('\tR', self.r)
|
||||
return hash(string)
|
||||
|
||||
def __repr__(self):
|
||||
|
|
@ -485,7 +488,7 @@ class ZernikeRadialFilter(ZernikeFilter):
|
|||
is :math:`\frac{\pi}{n+1}`.
|
||||
|
||||
If there is only radial dependency, the polynomials are integrated over
|
||||
the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta)
|
||||
the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta)
|
||||
= R_n^{0}(\rho)`. Note that :math:`n` could only be even orders.
|
||||
Therefore, for a radial Zernike polynomials up to order of :math:`n`,
|
||||
there are :math:`\frac{n}{2} + 1` terms in total. The indexing is from the
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import numpy as np
|
||||
import openmc
|
||||
import openmc.capi as capi
|
||||
from collections.abc import Iterable
|
||||
|
||||
|
||||
def legendre_from_expcoef(coef, domain= (-1,1)):
|
||||
def legendre_from_expcoef(coef, domain=(-1, 1)):
|
||||
"""Return a Legendre series object based on expansion coefficients.
|
||||
|
||||
Given a list of coefficients from FET tally and a array of down, return
|
||||
|
|
@ -73,5 +74,8 @@ class ZernikeRadial(Polynomial):
|
|||
return self._order
|
||||
|
||||
def __call__(self, r):
|
||||
zn_rad = capi.calc_zn_rad(self.order, r)
|
||||
return np.sum(self._norm_coef * zn_rad)
|
||||
if isinstance(r, Iterable):
|
||||
return [np.sum(self._norm_coef * capi.calc_zn_rad(self.order, r_i))
|
||||
for r_i in r]
|
||||
else:
|
||||
return np.sum(self._norm_coef * capi.calc_zn_rad(self.order, r))
|
||||
|
|
|
|||
|
|
@ -148,16 +148,11 @@ if not response or response.lower().startswith('y'):
|
|||
# get a list of all ACE files
|
||||
ace_files = sorted(glob.glob(os.path.join('nndc', '**', '*.ace*')))
|
||||
|
||||
# Get path to fission energy release data
|
||||
data_dir = os.path.dirname(sys.modules['openmc.data'].__file__)
|
||||
fer_file = os.path.join(data_dir, 'fission_Q_data_endfb71.h5')
|
||||
|
||||
# Call the ace-to-hdf5 conversion script
|
||||
pwd = os.path.dirname(os.path.realpath(__file__))
|
||||
ace2hdf5 = os.path.join(pwd, 'openmc-ace-to-hdf5')
|
||||
subprocess.call([ace2hdf5,
|
||||
'-d', 'nndc_hdf5',
|
||||
'--fission_energy_release', fer_file,
|
||||
'--libver', args.libver] + ace_files)
|
||||
|
||||
# Generate photo interaction library files
|
||||
|
|
|
|||
3
setup.py
3
setup.py
|
|
@ -32,7 +32,7 @@ kwargs = {
|
|||
# Data files and librarries
|
||||
'package_data': {
|
||||
'openmc.capi': ['libopenmc.{}'.format(suffix)],
|
||||
'openmc.data': ['mass.mas12', '*.h5']
|
||||
'openmc.data': ['mass.mas12', 'BREMX.DAT', '*.h5']
|
||||
},
|
||||
|
||||
# Metadata
|
||||
|
|
@ -52,6 +52,7 @@ kwargs = {
|
|||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
],
|
||||
|
||||
# Required dependencies
|
||||
|
|
|
|||
22
src/api.F90
22
src/api.F90
|
|
@ -11,7 +11,6 @@ module openmc_api
|
|||
use hdf5_interface
|
||||
use material_header
|
||||
use math
|
||||
use mesh_header
|
||||
use message_passing
|
||||
use nuclide_header
|
||||
use initialize, only: openmc_init_f
|
||||
|
|
@ -20,7 +19,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 +36,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 +79,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
|
||||
|
|
@ -136,7 +131,7 @@ contains
|
|||
legendre_to_tabular_points = C_NONE
|
||||
n_batch_interval = 1
|
||||
n_lost_particles = 0
|
||||
n_particles = 0
|
||||
n_particles = -1
|
||||
n_source_points = 0
|
||||
n_state_points = 0
|
||||
n_tallies = 0
|
||||
|
|
@ -153,7 +148,7 @@ contains
|
|||
restart_run = .false.
|
||||
root_universe = -1
|
||||
run_CE = .true.
|
||||
run_mode = NONE
|
||||
run_mode = -1
|
||||
satisfy_triggers = .false.
|
||||
call openmc_set_seed(DEFAULT_SEED)
|
||||
source_latest = .false.
|
||||
|
|
@ -210,8 +205,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 +296,19 @@ 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
|
||||
|
||||
subroutine free_memory_mesh() bind(C)
|
||||
end subroutine free_memory_mesh
|
||||
end interface
|
||||
|
||||
call free_memory_geometry()
|
||||
call free_memory_surfaces()
|
||||
call free_memory_material()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ module bank_header
|
|||
type(Bank), allocatable, target :: master_fission_bank(:)
|
||||
#endif
|
||||
|
||||
integer(8) :: n_bank ! # of sites in fission bank
|
||||
integer(C_INT64_T), bind(C) :: n_bank ! # of sites in fission bank
|
||||
|
||||
!$omp threadprivate(fission_bank, n_bank)
|
||||
|
||||
|
|
@ -71,4 +71,20 @@ contains
|
|||
end if
|
||||
end function openmc_source_bank
|
||||
|
||||
function openmc_fission_bank(ptr, n) result(err) bind(C)
|
||||
! Return a pointer to the source bank
|
||||
type(C_PTR), intent(out) :: ptr
|
||||
integer(C_INT64_T), intent(out) :: n
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (.not. allocated(fission_bank)) then
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Fission bank has not been allocated.")
|
||||
else
|
||||
err = 0
|
||||
ptr = C_LOC(fission_bank)
|
||||
n = size(fission_bank)
|
||||
end if
|
||||
end function openmc_fission_bank
|
||||
|
||||
end module bank_header
|
||||
|
|
|
|||
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 (settings::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);}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ contains
|
|||
integer :: i_mesh ! flattend index for mesh
|
||||
logical :: energy_filters! energy filters present
|
||||
real(8) :: flux ! temp variable for flux
|
||||
type(RegularMesh), pointer :: m ! pointer for mesh object
|
||||
type(RegularMesh) :: m ! pointer for mesh object
|
||||
|
||||
! Extract spatial and energy indices from object
|
||||
nx = cmfd % indices(1)
|
||||
|
|
@ -99,7 +99,7 @@ contains
|
|||
|
||||
select type(filt => filters(i_filter_mesh) % obj)
|
||||
type is (MeshFilter)
|
||||
m => meshes(filt % mesh)
|
||||
m = meshes(filt % mesh)
|
||||
end select
|
||||
|
||||
! Set mesh widths
|
||||
|
|
@ -354,9 +354,6 @@ contains
|
|||
! Normalize openmc source distribution
|
||||
cmfd % openmc_src = cmfd % openmc_src/sum(cmfd % openmc_src)*cmfd%norm
|
||||
|
||||
! Nullify all pointers
|
||||
if (associated(m)) nullify(m)
|
||||
|
||||
end subroutine compute_xs
|
||||
|
||||
!===============================================================================
|
||||
|
|
|
|||
|
|
@ -214,8 +214,6 @@ contains
|
|||
use bank_header, only: source_bank
|
||||
use constants, only: ZERO, ONE
|
||||
use error, only: warning, fatal_error
|
||||
use mesh_header, only: RegularMesh
|
||||
use mesh, only: count_bank_sites
|
||||
use message_passing
|
||||
use string, only: to_str
|
||||
|
||||
|
|
@ -224,7 +222,7 @@ contains
|
|||
integer :: nx ! maximum number of cells in x direction
|
||||
integer :: ny ! maximum number of cells in y direction
|
||||
integer :: nz ! maximum number of cells in z direction
|
||||
integer :: ng ! maximum number of energy groups
|
||||
integer(C_INT) :: ng ! maximum number of energy groups
|
||||
integer :: i ! iteration counter
|
||||
integer :: g ! index for group
|
||||
integer :: ijk(3) ! spatial bin location
|
||||
|
|
@ -232,12 +230,22 @@ contains
|
|||
integer :: mesh_bin ! mesh bin of soruce particle
|
||||
integer :: n_groups ! number of energy groups
|
||||
real(8) :: norm ! normalization factor
|
||||
logical :: outside ! any source sites outside mesh
|
||||
logical(C_BOOL) :: outside ! any source sites outside mesh
|
||||
logical :: in_mesh ! source site is inside mesh
|
||||
#ifdef OPENMC_MPI
|
||||
integer :: mpi_err
|
||||
#endif
|
||||
|
||||
interface
|
||||
subroutine cmfd_populate_sourcecounts(ng, energies, source_counts, outside) bind(C)
|
||||
import C_INT, C_DOUBLE, C_BOOL
|
||||
integer(C_INT), value :: ng
|
||||
real(C_DOUBLE), intent(in) :: energies
|
||||
real(C_DOUBLE), intent(out) :: source_counts
|
||||
logical(C_BOOL), intent(out) :: outside
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
! Get maximum of spatial and group indices
|
||||
nx = cmfd % indices(1)
|
||||
ny = cmfd % indices(2)
|
||||
|
|
@ -261,8 +269,8 @@ contains
|
|||
cmfd%weightfactors = ONE
|
||||
|
||||
! Count bank sites in mesh and reverse due to egrid structure
|
||||
call count_bank_sites(cmfd_mesh, source_bank, cmfd%sourcecounts, &
|
||||
cmfd % egrid, sites_outside=outside, size_bank=work)
|
||||
call cmfd_populate_sourcecounts(ng + 1, cmfd % egrid(1), &
|
||||
cmfd % sourcecounts(1,1), outside)
|
||||
|
||||
! Check for sites outside of the mesh
|
||||
if (master .and. outside) then
|
||||
|
|
|
|||
34
src/cmfd_execute.cpp
Normal file
34
src/cmfd_execute.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <algorithm> // for copy
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#include "xtensor/xarray.hpp"
|
||||
#include "xtensor/xio.hpp"
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/mesh.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
extern "C" int index_cmfd_mesh;
|
||||
|
||||
extern "C" void
|
||||
cmfd_populate_sourcecounts(int n_energy, const double* energies,
|
||||
double* source_counts, bool* outside)
|
||||
{
|
||||
// Get pointer to source bank
|
||||
Bank* source_bank;
|
||||
int64_t n;
|
||||
openmc_source_bank(&source_bank, &n);
|
||||
|
||||
// Get source counts in each mesh bin / energy bin
|
||||
auto& m = meshes.at(index_cmfd_mesh);
|
||||
xt::xarray<double> counts = m->count_sites(openmc_work, source_bank, n_energy, energies, outside);
|
||||
|
||||
std::cout << counts << "\n";
|
||||
|
||||
// Copy data from the xarray into the source counts array
|
||||
std::copy(counts.begin(), counts.end(), source_counts);
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
module cmfd_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants, only: CMFD_NOACCEL, ZERO, ONE
|
||||
use mesh_header, only: RegularMesh
|
||||
use set_header, only: SetInt
|
||||
|
|
@ -24,7 +26,7 @@ module cmfd_header
|
|||
integer :: mat_dim = CMFD_NOACCEL
|
||||
|
||||
! Energy grid
|
||||
real(8), allocatable :: egrid(:)
|
||||
real(C_DOUBLE), allocatable :: egrid(:)
|
||||
|
||||
! Cross sections
|
||||
real(8), allocatable :: totalxs(:,:,:,:)
|
||||
|
|
@ -53,7 +55,7 @@ module cmfd_header
|
|||
real(8), allocatable :: openmc_src(:,:,:,:)
|
||||
|
||||
! Source sites in each mesh box
|
||||
real(8), allocatable :: sourcecounts(:,:)
|
||||
real(C_DOUBLE), allocatable :: sourcecounts(:,:)
|
||||
|
||||
! Weight adjustment factors
|
||||
real(8), allocatable :: weightfactors(:,:,:,:)
|
||||
|
|
@ -95,7 +97,8 @@ module cmfd_header
|
|||
! Main object
|
||||
type(cmfd_type), public :: cmfd
|
||||
|
||||
type(RegularMesh), public, pointer :: cmfd_mesh => null()
|
||||
integer(C_INT), public, bind(C) :: index_cmfd_mesh
|
||||
type(RegularMesh), public :: cmfd_mesh
|
||||
|
||||
! Pointers for different tallies
|
||||
type(TallyContainer), public, pointer :: cmfd_tallies(:) => null()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module cmfd_input
|
|||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use cmfd_header
|
||||
use mesh_header, only: mesh_dict
|
||||
use mesh_header
|
||||
use mgxs_interface, only: energy_bins, num_energy_groups
|
||||
use tally
|
||||
use tally_header
|
||||
|
|
@ -241,7 +241,7 @@ contains
|
|||
|
||||
use constants, only: MAX_LINE_LEN
|
||||
use error, only: fatal_error, warning
|
||||
use mesh_header, only: RegularMesh, openmc_extend_meshes
|
||||
use mesh_header
|
||||
use string
|
||||
use tally, only: openmc_tally_allocate
|
||||
use tally_header, only: openmc_extend_tallies
|
||||
|
|
@ -263,115 +263,23 @@ contains
|
|||
integer :: i_filt ! index in filters array
|
||||
integer :: filt_id
|
||||
integer :: tally_id
|
||||
integer :: iarray3(3) ! temp integer array
|
||||
real(8) :: rarray3(3) ! temp double array
|
||||
real(C_DOUBLE), allocatable :: energies(:)
|
||||
type(RegularMesh), pointer :: m
|
||||
type(XMLNode) :: node_mesh
|
||||
|
||||
err = openmc_extend_meshes(1, i_start)
|
||||
! Read CMFD mesh
|
||||
call read_meshes(root % ptr)
|
||||
|
||||
! Allocate mesh
|
||||
cmfd_mesh => meshes(i_start)
|
||||
m => meshes(i_start)
|
||||
! Get index of cmfd mesh and set ID
|
||||
i_start = n_meshes() - 1
|
||||
err = openmc_mesh_set_id(i_start, i_start)
|
||||
|
||||
! Set mesh id
|
||||
m % id = i_start
|
||||
|
||||
! Set mesh type to rectangular
|
||||
m % type = MESH_REGULAR
|
||||
! Save reference to CMFD mesh
|
||||
index_cmfd_mesh = i_start
|
||||
cmfd_mesh = meshes(i_start)
|
||||
|
||||
! Get pointer to mesh XML node
|
||||
node_mesh = root % child("mesh")
|
||||
|
||||
! Determine number of dimensions for mesh
|
||||
n = node_word_count(node_mesh, "dimension")
|
||||
if (n /= 2 .and. n /= 3) then
|
||||
call fatal_error("Mesh must be two or three dimensions.")
|
||||
end if
|
||||
m % n_dimension = n
|
||||
|
||||
! Allocate attribute arrays
|
||||
allocate(m % dimension(n))
|
||||
allocate(m % lower_left(n))
|
||||
allocate(m % width(n))
|
||||
allocate(m % upper_right(n))
|
||||
|
||||
! Check that dimensions are all greater than zero
|
||||
call get_node_array(node_mesh, "dimension", iarray3(1:n))
|
||||
if (any(iarray3(1:n) <= 0)) then
|
||||
call fatal_error("All entries on the <dimension> element for a tally mesh&
|
||||
& must be positive.")
|
||||
end if
|
||||
|
||||
! Read dimensions in each direction
|
||||
m % dimension = iarray3(1:n)
|
||||
|
||||
! Read mesh lower-left corner location
|
||||
if (m % n_dimension /= node_word_count(node_mesh, "lower_left")) then
|
||||
call fatal_error("Number of entries on <lower_left> must be the same as &
|
||||
&the number of entries on <dimension>.")
|
||||
end if
|
||||
call get_node_array(node_mesh, "lower_left", m % lower_left)
|
||||
|
||||
! Make sure both upper-right or width were specified
|
||||
if (check_for_node(node_mesh, "upper_right") .and. &
|
||||
check_for_node(node_mesh, "width")) then
|
||||
call fatal_error("Cannot specify both <upper_right> and <width> on a &
|
||||
&tally mesh.")
|
||||
end if
|
||||
|
||||
! Make sure either upper-right or width was specified
|
||||
if (.not.check_for_node(node_mesh, "upper_right") .and. &
|
||||
.not.check_for_node(node_mesh, "width")) then
|
||||
call fatal_error("Must specify either <upper_right> and <width> on a &
|
||||
&tally mesh.")
|
||||
end if
|
||||
|
||||
if (check_for_node(node_mesh, "width")) then
|
||||
! Check to ensure width has same dimensions
|
||||
if (node_word_count(node_mesh, "width") /= &
|
||||
node_word_count(node_mesh, "lower_left")) then
|
||||
call fatal_error("Number of entries on <width> must be the same as the &
|
||||
&number of entries on <lower_left>.")
|
||||
end if
|
||||
|
||||
! Check for negative widths
|
||||
call get_node_array(node_mesh, "width", rarray3(1:n))
|
||||
if (any(rarray3(1:n) < ZERO)) then
|
||||
call fatal_error("Cannot have a negative <width> on a tally mesh.")
|
||||
end if
|
||||
|
||||
! Set width and upper right coordinate
|
||||
m % width = rarray3(1:n)
|
||||
m % upper_right = m % lower_left + m % dimension * m % width
|
||||
|
||||
elseif (check_for_node(node_mesh, "upper_right")) then
|
||||
! Check to ensure width has same dimensions
|
||||
if (node_word_count(node_mesh, "upper_right") /= &
|
||||
node_word_count(node_mesh, "lower_left")) then
|
||||
call fatal_error("Number of entries on <upper_right> must be the same &
|
||||
&as the number of entries on <lower_left>.")
|
||||
end if
|
||||
|
||||
! Check that upper-right is above lower-left
|
||||
call get_node_array(node_mesh, "upper_right", rarray3(1:n))
|
||||
if (any(rarray3(1:n) < m % lower_left)) then
|
||||
call fatal_error("The <upper_right> coordinates must be greater than &
|
||||
&the <lower_left> coordinates on a tally mesh.")
|
||||
end if
|
||||
|
||||
! Set upper right coordinate and width
|
||||
m % upper_right = rarray3(1:n)
|
||||
m % width = (m % upper_right - m % lower_left) / real(m % dimension, 8)
|
||||
end if
|
||||
|
||||
! Set volume fraction
|
||||
m % volume_frac = ONE/real(product(m % dimension),8)
|
||||
|
||||
! Add mesh to dictionary
|
||||
call mesh_dict % set(m % id, i_start)
|
||||
|
||||
! Determine number of filters
|
||||
energy_filters = check_for_node(node_mesh, "energy")
|
||||
n = merge(5, 3, energy_filters)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -6,8 +6,6 @@ module eigenvalue
|
|||
use constants, only: ZERO
|
||||
use error, only: fatal_error, warning
|
||||
use math, only: t_percentile
|
||||
use mesh, only: count_bank_sites
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use message_passing
|
||||
use random_lcg, only: prn, set_particle_seed, advance_prn_seed
|
||||
use settings
|
||||
|
|
@ -294,46 +292,6 @@ contains
|
|||
|
||||
end subroutine synchronize_bank
|
||||
|
||||
!===============================================================================
|
||||
! SHANNON_ENTROPY calculates the Shannon entropy of the fission source
|
||||
! distribution to assess source convergence
|
||||
!===============================================================================
|
||||
|
||||
subroutine shannon_entropy()
|
||||
|
||||
integer :: i ! index for mesh elements
|
||||
real(8) :: entropy_gen ! entropy at this generation
|
||||
logical :: sites_outside ! were there sites outside entropy box?
|
||||
|
||||
associate (m => meshes(index_entropy_mesh))
|
||||
! count number of fission sites over mesh
|
||||
call count_bank_sites(m, fission_bank, entropy_p, &
|
||||
size_bank=n_bank, sites_outside=sites_outside)
|
||||
|
||||
! display warning message if there were sites outside entropy box
|
||||
if (sites_outside) then
|
||||
if (master) call warning("Fission source site(s) outside of entropy box.")
|
||||
end if
|
||||
|
||||
! sum values to obtain shannon entropy
|
||||
if (master) then
|
||||
! Normalize to total weight of bank sites
|
||||
entropy_p = entropy_p / sum(entropy_p)
|
||||
|
||||
entropy_gen = ZERO
|
||||
do i = 1, size(entropy_p, 2)
|
||||
if (entropy_p(1,i) > ZERO) then
|
||||
entropy_gen = entropy_gen - &
|
||||
entropy_p(1,i) * log(entropy_p(1,i))/log(TWO)
|
||||
end if
|
||||
end do
|
||||
|
||||
! Add value to vector
|
||||
call entropy % push_back(entropy_gen)
|
||||
end if
|
||||
end associate
|
||||
end subroutine shannon_entropy
|
||||
|
||||
!===============================================================================
|
||||
! CALCULATE_GENERATION_KEFF collects the single-processor tracklength k's onto
|
||||
! the master processor and normalizes them. This should work whether or not the
|
||||
|
|
@ -577,61 +535,6 @@ contains
|
|||
|
||||
end function openmc_get_keff
|
||||
|
||||
!===============================================================================
|
||||
! COUNT_SOURCE_FOR_UFS determines the source fraction in each UFS mesh cell and
|
||||
! reweights the source bank so that the sum of the weights is equal to
|
||||
! n_particles. The 'source_frac' variable is used later to bias the production
|
||||
! of fission sites
|
||||
!===============================================================================
|
||||
|
||||
subroutine count_source_for_ufs()
|
||||
|
||||
real(8) :: total ! total weight in source bank
|
||||
logical :: sites_outside ! were there sites outside the ufs mesh?
|
||||
#ifdef OPENMC_MPI
|
||||
integer :: n ! total number of ufs mesh cells
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
|
||||
associate (m => meshes(index_ufs_mesh))
|
||||
|
||||
if (current_batch == 1 .and. current_gen == 1) then
|
||||
! On the first generation, just assume that the source is already evenly
|
||||
! distributed so that effectively the production of fission sites is not
|
||||
! biased
|
||||
|
||||
source_frac = m % volume_frac
|
||||
|
||||
else
|
||||
! count number of source sites in each ufs mesh cell
|
||||
call count_bank_sites(m, source_bank, source_frac, &
|
||||
sites_outside=sites_outside, size_bank=work)
|
||||
|
||||
! Check for sites outside of the mesh
|
||||
if (master .and. sites_outside) then
|
||||
call fatal_error("Source sites outside of the UFS mesh!")
|
||||
end if
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
! Send source fraction to all processors
|
||||
n = product(m % dimension)
|
||||
call MPI_BCAST(source_frac, n, MPI_REAL8, 0, mpi_intracomm, mpi_err)
|
||||
#endif
|
||||
|
||||
! Normalize to total weight to get fraction of source in each cell
|
||||
total = sum(source_frac)
|
||||
source_frac = source_frac / total
|
||||
|
||||
! Since the total starting weight is not equal to n_particles, we need to
|
||||
! renormalize the weight of the source sites
|
||||
|
||||
source_bank % wgt = source_bank % wgt * n_particles / total
|
||||
end if
|
||||
|
||||
end associate
|
||||
|
||||
end subroutine count_source_for_ufs
|
||||
|
||||
#ifdef _OPENMP
|
||||
!===============================================================================
|
||||
! JOIN_BANK_FROM_THREADS joins threadprivate fission banks into a single fission
|
||||
|
|
|
|||
155
src/eigenvalue.cpp
Normal file
155
src/eigenvalue.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
#include "openmc/eigenvalue.h"
|
||||
|
||||
#include "xtensor/xmath.hpp"
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include "xtensor/xview.hpp"
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/mesh.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/simulation.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<double> entropy;
|
||||
xt::xtensor<double, 1> source_frac;
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
void shannon_entropy()
|
||||
{
|
||||
// Get pointer to entropy mesh
|
||||
auto& m = meshes[settings::index_entropy_mesh];
|
||||
|
||||
// Get pointer to fission bank
|
||||
Bank* fission_bank;
|
||||
int64_t n;
|
||||
openmc_fission_bank(&fission_bank, &n);
|
||||
|
||||
// Get source weight in each mesh bin
|
||||
bool sites_outside;
|
||||
xt::xtensor<double, 1> p = m->count_sites(
|
||||
n_bank, fission_bank, 0, nullptr, &sites_outside);
|
||||
|
||||
// display warning message if there were sites outside entropy box
|
||||
if (sites_outside) {
|
||||
if (mpi::master) warning("Fission source site(s) outside of entropy box.");
|
||||
}
|
||||
|
||||
// sum values to obtain shannon entropy
|
||||
if (mpi::master) {
|
||||
// Normalize to total weight of bank sites
|
||||
p /= xt::sum(p);
|
||||
|
||||
double H = 0.0;
|
||||
for (auto p_i : p) {
|
||||
if (p_i > 0.0) {
|
||||
H -= p_i * std::log(p_i)/std::log(2.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Add value to vector
|
||||
entropy.push_back(H);
|
||||
}
|
||||
}
|
||||
|
||||
void ufs_count_sites()
|
||||
{
|
||||
auto &m = meshes[settings::index_ufs_mesh];
|
||||
|
||||
if (openmc_current_batch == 1 && openmc_current_gen == 1) {
|
||||
// On the first generation, just assume that the source is already evenly
|
||||
// distributed so that effectively the production of fission sites is not
|
||||
// biased
|
||||
|
||||
auto s = xt::view(source_frac, xt::all());
|
||||
s = m->volume_frac_;
|
||||
|
||||
} else {
|
||||
// Get pointer to source bank
|
||||
Bank* source_bank;
|
||||
int64_t n;
|
||||
openmc_source_bank(&source_bank, &n);
|
||||
|
||||
// count number of source sites in each ufs mesh cell
|
||||
bool sites_outside;
|
||||
source_frac = m->count_sites(openmc_work, source_bank, 0, nullptr,
|
||||
&sites_outside);
|
||||
|
||||
// Check for sites outside of the mesh
|
||||
if (mpi::master && sites_outside) {
|
||||
fatal_error("Source sites outside of the UFS mesh!");
|
||||
}
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
// Send source fraction to all processors
|
||||
int n_bins = xt::prod(m->shape_)();
|
||||
MPI_Bcast(source_frac.data(), n_bins, MPI_DOUBLE, 0, mpi::intracomm);
|
||||
#endif
|
||||
|
||||
// Normalize to total weight to get fraction of source in each cell
|
||||
double total = xt::sum(source_frac)();
|
||||
source_frac /= total;
|
||||
|
||||
// Since the total starting weight is not equal to n_particles, we need to
|
||||
// renormalize the weight of the source sites
|
||||
for (int i = 0; i < openmc_work; ++i) {
|
||||
source_bank[i].wgt *= settings::n_particles / total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double ufs_get_weight(const Particle* p)
|
||||
{
|
||||
auto& m = meshes[settings::index_ufs_mesh];
|
||||
|
||||
// Determine indices on ufs mesh for current location
|
||||
// TODO: off by one
|
||||
int mesh_bin = m->get_bin({p->coord[0].xyz}) - 1;
|
||||
if (mesh_bin < 0) {
|
||||
p->write_restart();
|
||||
fatal_error("Source site outside UFS mesh!");
|
||||
}
|
||||
|
||||
if (source_frac(mesh_bin) != 0.0) {
|
||||
return m->volume_frac_ / source_frac(mesh_bin);
|
||||
} else {
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void entropy_to_hdf5(hid_t group)
|
||||
{
|
||||
if (settings::entropy_on) {
|
||||
write_dataset(group, "entropy", entropy);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void entropy_from_hdf5(hid_t group)
|
||||
{
|
||||
if (settings::entropy_on) {
|
||||
read_dataset(group, "entropy", entropy);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" double entropy_c(int i)
|
||||
{
|
||||
return entropy.at(i - 1);
|
||||
}
|
||||
|
||||
extern "C" double entropy_clear()
|
||||
{
|
||||
entropy.clear();
|
||||
}
|
||||
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -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
|
||||
|
|
|
|||
409
src/geometry.cpp
Normal file
409
src/geometry.cpp
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
#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/settings.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 (settings::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);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
cross_lattice(Particle* p, int lattice_translation[3])
|
||||
{
|
||||
Lattice& lat {*lattices[p->coord[p->n_coord-1].lattice-1]};
|
||||
|
||||
if (settings::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,81 @@ 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 *
|
||||
settings::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 +154,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 +271,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 +295,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 +321,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 +343,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 +365,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 +398,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 +410,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 +424,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 +447,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
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include "xtensor/xarray.hpp"
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "hdf5_hl.h"
|
||||
#ifdef OPENMC_MPI
|
||||
#include "mpi.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#endif
|
||||
#include "openmc/error.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -532,172 +534,6 @@ read_complex(hid_t obj_id, const char* name, std::complex<double>* buffer, bool
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name, std::vector<double>& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
read_double(obj_id, name, result.data(), true);
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<double> >& result, bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
double temp_arr[dim1 * dim2];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
result[i][j] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<int> >& result, bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int temp_arr[dim1 * dim2];
|
||||
read_int(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
result[i][j] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<double> > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
double temp_arr[dim1 * dim2 * dim3];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
result[i][j][k] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<int> > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
int temp_arr[dim1 * dim2 * dim3];
|
||||
read_int(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
result[i][j][k] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<double> > > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
int dim4 = result[0][0][0].size();
|
||||
double temp_arr[dim1 * dim2 * dim3 * dim4];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
for (int l = 0; l < dim4; l++) {
|
||||
result[i][j][k][l] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
int dim4 = result[0][0][0].size();
|
||||
int dim5 = result[0][0][0][0].size();
|
||||
double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
for (int l = 0; l < dim4; l++) {
|
||||
for (int m = 0; m < dim5; m++) {
|
||||
result[i][j][k][l][m] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results)
|
||||
{
|
||||
|
|
@ -910,6 +746,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;
|
||||
|
|
|
|||
|
|
@ -17,10 +17,28 @@ module initialize
|
|||
|
||||
implicit none
|
||||
|
||||
type(C_PTR), bind(C) :: openmc_path_input
|
||||
type(C_PTR), bind(C) :: openmc_path_statepoint
|
||||
type(C_PTR), bind(C) :: openmc_path_sourcepoint
|
||||
type(C_PTR), bind(C) :: openmc_path_particle_restart
|
||||
interface
|
||||
function openmc_path_input() result(ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: ptr
|
||||
end function
|
||||
function openmc_path_output() result(ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: ptr
|
||||
end function
|
||||
function openmc_path_particle_restart() result(ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: ptr
|
||||
end function
|
||||
function openmc_path_statepoint() result(ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: ptr
|
||||
end function
|
||||
function openmc_path_sourcepoint() result(ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: ptr
|
||||
end function
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
||||
|
|
@ -164,29 +182,24 @@ contains
|
|||
end function is_null
|
||||
end interface
|
||||
|
||||
if (.not. is_null(openmc_path_input)) then
|
||||
call c_f_pointer(openmc_path_input, string, [255])
|
||||
if (.not. is_null(openmc_path_input())) then
|
||||
call c_f_pointer(openmc_path_input(), string, [255])
|
||||
path_input = to_f_string(string)
|
||||
else
|
||||
path_input = ''
|
||||
end if
|
||||
if (.not. is_null(openmc_path_statepoint)) then
|
||||
call c_f_pointer(openmc_path_statepoint, string, [255])
|
||||
if (.not. is_null(openmc_path_statepoint())) then
|
||||
call c_f_pointer(openmc_path_statepoint(), string, [255])
|
||||
path_state_point = to_f_string(string)
|
||||
end if
|
||||
if (.not. is_null(openmc_path_sourcepoint)) then
|
||||
call c_f_pointer(openmc_path_sourcepoint, string, [255])
|
||||
if (.not. is_null(openmc_path_sourcepoint())) then
|
||||
call c_f_pointer(openmc_path_sourcepoint(), string, [255])
|
||||
path_source_point = to_f_string(string)
|
||||
end if
|
||||
if (.not. is_null(openmc_path_particle_restart)) then
|
||||
call c_f_pointer(openmc_path_particle_restart, string, [255])
|
||||
if (.not. is_null(openmc_path_particle_restart())) then
|
||||
call c_f_pointer(openmc_path_particle_restart(), string, [255])
|
||||
path_particle_restart = to_f_string(string)
|
||||
end if
|
||||
|
||||
! Add slash at end of directory if it isn't there
|
||||
if (len_trim(path_input) > 0 .and. .not. ends_with(path_input, "/")) then
|
||||
path_input = trim(path_input) // "/"
|
||||
end if
|
||||
end subroutine read_command_line
|
||||
|
||||
end module initialize
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -11,10 +10,12 @@
|
|||
#endif
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/string_utils.h"
|
||||
|
||||
// data/functions from Fortran side
|
||||
extern "C" void print_usage();
|
||||
|
|
@ -60,7 +61,7 @@ namespace openmc {
|
|||
#ifdef OPENMC_MPI
|
||||
void initialize_mpi(MPI_Comm intracomm)
|
||||
{
|
||||
openmc::mpi::intracomm = intracomm;
|
||||
mpi::intracomm = intracomm;
|
||||
|
||||
// Initialize MPI
|
||||
int flag;
|
||||
|
|
@ -68,13 +69,13 @@ void initialize_mpi(MPI_Comm intracomm)
|
|||
if (!flag) MPI_Init(nullptr, nullptr);
|
||||
|
||||
// Determine number of processes and rank for each
|
||||
MPI_Comm_size(intracomm, &openmc::mpi::n_procs);
|
||||
MPI_Comm_rank(intracomm, &openmc::mpi::rank);
|
||||
MPI_Comm_size(intracomm, &mpi::n_procs);
|
||||
MPI_Comm_rank(intracomm, &mpi::rank);
|
||||
|
||||
// Set variable for Fortran side
|
||||
openmc_n_procs = openmc::mpi::n_procs;
|
||||
openmc_rank = openmc::mpi::rank;
|
||||
openmc_master = (openmc::mpi::rank == 0);
|
||||
openmc_n_procs = mpi::n_procs;
|
||||
openmc_rank = mpi::rank;
|
||||
openmc_master = mpi::master = (mpi::rank == 0);
|
||||
|
||||
// Create bank datatype
|
||||
Bank b;
|
||||
|
|
@ -87,19 +88,12 @@ void initialize_mpi(MPI_Comm intracomm)
|
|||
};
|
||||
int blocks[] {1, 3, 3, 1, 1};
|
||||
MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_INT};
|
||||
MPI_Type_create_struct(5, blocks, disp, types, &openmc::mpi::bank);
|
||||
MPI_Type_commit(&openmc::mpi::bank);
|
||||
MPI_Type_create_struct(5, blocks, disp, types, &mpi::bank);
|
||||
MPI_Type_commit(&mpi::bank);
|
||||
}
|
||||
#endif // OPENMC_MPI
|
||||
|
||||
|
||||
inline bool ends_with(std::string const& value, std::string const& ending)
|
||||
{
|
||||
if (ending.size() > value.size()) return false;
|
||||
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
parse_command_line(int argc, char* argv[])
|
||||
{
|
||||
|
|
@ -109,12 +103,12 @@ parse_command_line(int argc, char* argv[])
|
|||
std::string arg {argv[i]};
|
||||
if (arg[0] == '-') {
|
||||
if (arg == "-p" || arg == "--plot") {
|
||||
openmc_run_mode = RUN_MODE_PLOTTING;
|
||||
openmc_check_overlaps = true;
|
||||
settings::run_mode = RUN_MODE_PLOTTING;
|
||||
settings::check_overlaps = true;
|
||||
|
||||
} else if (arg == "-n" || arg == "--particles") {
|
||||
i += 1;
|
||||
n_particles = std::stoll(argv[i]);
|
||||
settings::n_particles = std::stoll(argv[i]);
|
||||
|
||||
} else if (arg == "-r" || arg == "--restart") {
|
||||
i += 1;
|
||||
|
|
@ -128,11 +122,11 @@ parse_command_line(int argc, char* argv[])
|
|||
|
||||
// Set path and flag for type of run
|
||||
if (filetype == "statepoint") {
|
||||
openmc_path_statepoint = argv[i];
|
||||
openmc_restart_run = true;
|
||||
settings::path_statepoint = argv[i];
|
||||
settings::restart_run = true;
|
||||
} else if (filetype == "particle restart") {
|
||||
openmc_path_particle_restart = argv[i];
|
||||
openmc_particle_restart_run = true;
|
||||
settings::path_particle_restart = argv[i];
|
||||
settings::particle_restart_run = true;
|
||||
} else {
|
||||
std::stringstream msg;
|
||||
msg << "Unrecognized file after restart flag: " << filetype << ".";
|
||||
|
|
@ -141,7 +135,7 @@ parse_command_line(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// If its a restart run check for additional source file
|
||||
if (openmc_restart_run && i + 1 < argc) {
|
||||
if (settings::restart_run && i + 1 < argc) {
|
||||
// Check if it has extension we can read
|
||||
if (ends_with(argv[i+1], ".h5")) {
|
||||
|
||||
|
|
@ -157,23 +151,23 @@ parse_command_line(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// It is a source file
|
||||
openmc_path_sourcepoint = argv[i+1];
|
||||
settings::path_sourcepoint = argv[i+1];
|
||||
i += 1;
|
||||
|
||||
} else {
|
||||
// Source is in statepoint file
|
||||
openmc_path_sourcepoint = openmc_path_statepoint;
|
||||
settings::path_sourcepoint = settings::path_statepoint;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Source is assumed to be in statepoint file
|
||||
openmc_path_sourcepoint = openmc_path_statepoint;
|
||||
settings::path_sourcepoint = settings::path_statepoint;
|
||||
}
|
||||
|
||||
} else if (arg == "-g" || arg == "--geometry-debug") {
|
||||
openmc_check_overlaps = true;
|
||||
settings::check_overlaps = true;
|
||||
} else if (arg == "-c" || arg == "--volume") {
|
||||
openmc_run_mode = RUN_MODE_VOLUME;
|
||||
settings::run_mode = RUN_MODE_VOLUME;
|
||||
} else if (arg == "-s" || arg == "--threads") {
|
||||
// Read number of threads
|
||||
i += 1;
|
||||
|
|
@ -201,7 +195,7 @@ parse_command_line(int argc, char* argv[])
|
|||
return OPENMC_E_UNASSIGNED;
|
||||
|
||||
} else if (arg == "-t" || arg == "--track") {
|
||||
openmc_write_all_tracks = true;
|
||||
settings::write_all_tracks = true;
|
||||
|
||||
} else {
|
||||
std::cerr << "Unknown option: " << argv[i] << '\n';
|
||||
|
|
@ -214,7 +208,14 @@ parse_command_line(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// Determine directory where XML input files are
|
||||
if (argc > 1 && last_flag < argc) openmc_path_input = argv[last_flag + 1];
|
||||
if (argc > 1 && last_flag < argc - 1) {
|
||||
settings::path_input = std::string(argv[last_flag + 1]);
|
||||
|
||||
// Add slash at end of directory if it isn't there
|
||||
if (!ends_with(settings::path_input, "/")) {
|
||||
settings::path_input += "/";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
1005
src/input_xml.F90
1005
src/input_xml.F90
File diff suppressed because it is too large
Load diff
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
|
||||
|
|
|
|||
14
src/main.cpp
14
src/main.cpp
|
|
@ -2,7 +2,9 @@
|
|||
#include "mpi.h"
|
||||
#endif
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/settings.h"
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
|
@ -23,18 +25,18 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
// start problem based on mode
|
||||
switch (openmc_run_mode) {
|
||||
case RUN_MODE_FIXEDSOURCE:
|
||||
case RUN_MODE_EIGENVALUE:
|
||||
switch (openmc::settings::run_mode) {
|
||||
case openmc::RUN_MODE_FIXEDSOURCE:
|
||||
case openmc::RUN_MODE_EIGENVALUE:
|
||||
err = openmc_run();
|
||||
break;
|
||||
case RUN_MODE_PLOTTING:
|
||||
case openmc::RUN_MODE_PLOTTING:
|
||||
err = openmc_plot_geometry();
|
||||
break;
|
||||
case RUN_MODE_PARTICLE:
|
||||
case openmc::RUN_MODE_PARTICLE:
|
||||
if (openmc_master) err = openmc_particle_restart();
|
||||
break;
|
||||
case RUN_MODE_VOLUME:
|
||||
case openmc::RUN_MODE_VOLUME:
|
||||
err = openmc_calculate_volumes();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
106
src/mesh.F90
106
src/mesh.F90
|
|
@ -1,106 +0,0 @@
|
|||
module mesh
|
||||
|
||||
use algorithm, only: binary_search
|
||||
use bank_header, only: bank
|
||||
use constants
|
||||
use mesh_header
|
||||
use message_passing
|
||||
|
||||
implicit none
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! COUNT_BANK_SITES determines the number of fission bank sites in each cell of a
|
||||
! given mesh as well as an optional energy group structure. This can be used for
|
||||
! a variety of purposes (Shannon entropy, CMFD, uniform fission source
|
||||
! weighting)
|
||||
!===============================================================================
|
||||
|
||||
subroutine count_bank_sites(m, bank_array, cnt, energies, size_bank, &
|
||||
sites_outside)
|
||||
|
||||
type(RegularMesh), intent(in) :: m ! mesh to count sites
|
||||
type(Bank), intent(in) :: bank_array(:) ! fission or source bank
|
||||
real(8), intent(out) :: cnt(:,:) ! weight of sites in each
|
||||
! cell and energy group
|
||||
real(8), intent(in), optional :: energies(:) ! energy grid to search
|
||||
integer(8), intent(in), optional :: size_bank ! # of bank sites (on each proc)
|
||||
logical, intent(inout), optional :: sites_outside ! were there sites outside mesh?
|
||||
real(8), allocatable :: cnt_(:,:)
|
||||
|
||||
integer :: i ! loop index for local fission sites
|
||||
integer :: n_sites ! size of bank array
|
||||
integer :: n ! number of energy groups / size
|
||||
integer :: mesh_bin ! mesh bin
|
||||
integer :: e_bin ! energy bin
|
||||
#ifdef OPENMC_MPI
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
logical :: outside ! was any site outside mesh?
|
||||
|
||||
! initialize variables
|
||||
allocate(cnt_(size(cnt,1), size(cnt,2)))
|
||||
cnt_ = ZERO
|
||||
outside = .false.
|
||||
|
||||
! Set size of bank
|
||||
if (present(size_bank)) then
|
||||
n_sites = int(size_bank,4)
|
||||
else
|
||||
n_sites = size(bank_array)
|
||||
end if
|
||||
|
||||
! Determine number of energies in group structure
|
||||
if (present(energies)) then
|
||||
n = size(energies) - 1
|
||||
else
|
||||
n = 1
|
||||
end if
|
||||
|
||||
! loop over fission sites and count how many are in each mesh box
|
||||
FISSION_SITES: do i = 1, n_sites
|
||||
! determine scoring bin for entropy mesh
|
||||
call m % get_bin(bank_array(i) % xyz, mesh_bin)
|
||||
|
||||
! if outside mesh, skip particle
|
||||
if (mesh_bin == NO_BIN_FOUND) then
|
||||
outside = .true.
|
||||
cycle
|
||||
end if
|
||||
|
||||
! determine energy bin
|
||||
if (present(energies)) then
|
||||
if (bank_array(i) % E < energies(1)) then
|
||||
e_bin = 1
|
||||
elseif (bank_array(i) % E > energies(n + 1)) then
|
||||
e_bin = n
|
||||
else
|
||||
e_bin = binary_search(energies, n + 1, bank_array(i) % E)
|
||||
end if
|
||||
else
|
||||
e_bin = 1
|
||||
end if
|
||||
|
||||
! add to appropriate mesh box
|
||||
cnt_(e_bin, mesh_bin) = cnt_(e_bin, mesh_bin) + bank_array(i) % wgt
|
||||
end do FISSION_SITES
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
! collect values from all processors
|
||||
n = size(cnt_)
|
||||
call MPI_REDUCE(cnt_, cnt, n, MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err)
|
||||
|
||||
! Check if there were sites outside the mesh for any processor
|
||||
if (present(sites_outside)) then
|
||||
call MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, &
|
||||
mpi_intracomm, mpi_err)
|
||||
end if
|
||||
#else
|
||||
sites_outside = outside
|
||||
cnt = cnt_
|
||||
#endif
|
||||
|
||||
end subroutine count_bank_sites
|
||||
|
||||
end module mesh
|
||||
963
src/mesh.cpp
Normal file
963
src/mesh.cpp
Normal file
|
|
@ -0,0 +1,963 @@
|
|||
#include "openmc/mesh.h"
|
||||
|
||||
#include <algorithm> // for copy, min
|
||||
#include <cstddef> // for size_t
|
||||
#include <cmath> // for ceil
|
||||
#include <string>
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
#include "mpi.h"
|
||||
#endif
|
||||
#include "xtensor/xbuilder.hpp"
|
||||
#include "xtensor/xeval.hpp"
|
||||
#include "xtensor/xmath.hpp"
|
||||
#include "xtensor/xsort.hpp"
|
||||
#include "xtensor/xtensor.hpp"
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/search.h"
|
||||
#include "openmc/tallies/tally_filter.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<std::unique_ptr<RegularMesh>> meshes;
|
||||
|
||||
std::unordered_map<int32_t, int32_t> mesh_map;
|
||||
|
||||
//==============================================================================
|
||||
// RegularMesh implementation
|
||||
//==============================================================================
|
||||
|
||||
RegularMesh::RegularMesh(pugi::xml_node node)
|
||||
{
|
||||
// Copy mesh id
|
||||
if (check_for_node(node, "id")) {
|
||||
id_ = std::stoi(get_node_value(node, "id"));
|
||||
|
||||
// Check to make sure 'id' hasn't been used
|
||||
if (mesh_map.find(id_) != mesh_map.end()) {
|
||||
fatal_error("Two or more meshes use the same unique ID: " +
|
||||
std::to_string(id_));
|
||||
}
|
||||
}
|
||||
|
||||
// Read mesh type
|
||||
if (check_for_node(node, "type")) {
|
||||
auto temp = get_node_value(node, "type", true, true);
|
||||
if (temp == "regular") {
|
||||
// TODO: move elsewhere
|
||||
} else {
|
||||
fatal_error("Invalid mesh type: " + temp);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine number of dimensions for mesh
|
||||
if (check_for_node(node, "dimension")) {
|
||||
shape_ = get_node_xarray<int>(node, "dimension");
|
||||
int n = n_dimension_ = shape_.size();
|
||||
if (n != 1 && n != 2 && n != 3) {
|
||||
fatal_error("Mesh must be one, two, or three dimensions.");
|
||||
}
|
||||
|
||||
// Check that dimensions are all greater than zero
|
||||
if (xt::any(shape_ <= 0)) {
|
||||
fatal_error("All entries on the <dimension> element for a tally "
|
||||
"mesh must be positive.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for lower-left coordinates
|
||||
if (check_for_node(node, "lower_left")) {
|
||||
// Read mesh lower-left corner location
|
||||
lower_left_ = get_node_xarray<double>(node, "lower_left");
|
||||
} else {
|
||||
fatal_error("Must specify <lower_left> on a mesh.");
|
||||
}
|
||||
|
||||
if (check_for_node(node, "width")) {
|
||||
// Make sure both upper-right or width were specified
|
||||
if (check_for_node(node, "upper_right")) {
|
||||
fatal_error("Cannot specify both <upper_right> and <width> on a mesh.");
|
||||
}
|
||||
|
||||
width_ = get_node_xarray<double>(node, "width");
|
||||
|
||||
// Check to ensure width has same dimensions
|
||||
auto n = width_.size();
|
||||
if (n != lower_left_.size()) {
|
||||
fatal_error("Number of entries on <width> must be the same as "
|
||||
"the number of entries on <lower_left>.");
|
||||
}
|
||||
|
||||
// Check for negative widths
|
||||
if (xt::any(width_ < 0.0)) {
|
||||
fatal_error("Cannot have a negative <width> on a tally mesh.");
|
||||
}
|
||||
|
||||
// Set width and upper right coordinate
|
||||
upper_right_ = xt::eval(lower_left_ + shape_ * width_);
|
||||
|
||||
} else if (check_for_node(node, "upper_right")) {
|
||||
upper_right_ = get_node_xarray<double>(node, "upper_right");
|
||||
|
||||
// Check to ensure width has same dimensions
|
||||
auto n = upper_right_.size();
|
||||
if (n != lower_left_.size()) {
|
||||
fatal_error("Number of entries on <upper_right> must be the "
|
||||
"same as the number of entries on <lower_left>.");
|
||||
}
|
||||
|
||||
// Check that upper-right is above lower-left
|
||||
if (xt::any(upper_right_ < lower_left_)) {
|
||||
fatal_error("The <upper_right> coordinates must be greater than "
|
||||
"the <lower_left> coordinates on a tally mesh.");
|
||||
}
|
||||
|
||||
// Set width and upper right coordinate
|
||||
width_ = xt::eval((upper_right_ - lower_left_) / shape_);
|
||||
} else {
|
||||
fatal_error("Must specify either <upper_right> and <width> on a mesh.");
|
||||
}
|
||||
|
||||
if (shape_.dimension() > 0) {
|
||||
if (shape_.size() != lower_left_.size()) {
|
||||
fatal_error("Number of entries on <lower_left> must be the same "
|
||||
"as the number of entries on <dimension>.");
|
||||
}
|
||||
|
||||
// Set volume fraction
|
||||
volume_frac_ = 1.0/xt::prod(shape_)();
|
||||
}
|
||||
}
|
||||
|
||||
int RegularMesh::get_bin(Position r) const
|
||||
{
|
||||
// Loop over the dimensions of the mesh
|
||||
for (int i = 0; i < n_dimension_; ++i) {
|
||||
// Check for cases where particle is outside of mesh
|
||||
if (r[i] < lower_left_[i]) {
|
||||
return -1;
|
||||
} else if (r[i] > upper_right_[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine indices
|
||||
int ijk[n_dimension_];
|
||||
bool in_mesh;
|
||||
get_indices(r, ijk, &in_mesh);
|
||||
if (!in_mesh) return -1;
|
||||
|
||||
// Convert indices to bin
|
||||
return get_bin_from_indices(ijk);
|
||||
}
|
||||
|
||||
int RegularMesh::get_bin_from_indices(const int* ijk) const
|
||||
{
|
||||
if (n_dimension_ == 1) {
|
||||
return ijk[0];
|
||||
} else if (n_dimension_ == 2) {
|
||||
return (ijk[1] - 1)*shape_[0] + ijk[0];
|
||||
} else if (n_dimension_ == 3) {
|
||||
return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0];
|
||||
}
|
||||
}
|
||||
|
||||
void RegularMesh::get_indices(Position r, int* ijk, bool* in_mesh) const
|
||||
{
|
||||
// Find particle in mesh
|
||||
*in_mesh = true;
|
||||
for (int i = 0; i < n_dimension_; ++i) {
|
||||
ijk[i] = std::ceil((r[i] - lower_left_[i]) / width_[i]);
|
||||
|
||||
// Check if indices are within bounds
|
||||
if (ijk[i] < 1 || ijk[i] > shape_[i]) *in_mesh = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RegularMesh::get_indices_from_bin(int bin, int* ijk) const
|
||||
{
|
||||
if (n_dimension_ == 1) {
|
||||
ijk[0] = bin;
|
||||
} else if (n_dimension_ == 2) {
|
||||
ijk[0] = (bin - 1) % shape_[0] + 1;
|
||||
ijk[1] = (bin - 1) / shape_[0] + 1;
|
||||
} else if (n_dimension_ == 3) {
|
||||
ijk[0] = (bin - 1) % shape_[0] + 1;
|
||||
ijk[1] = ((bin - 1) % (shape_[0] * shape_[1])) / shape_[0] + 1;
|
||||
ijk[2] = (bin - 1) / (shape_[0] * shape_[1]) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegularMesh::intersects(Position r0, Position r1) const
|
||||
{
|
||||
switch(n_dimension_) {
|
||||
case 1:
|
||||
return intersects_1d(r0, r1);
|
||||
case 2:
|
||||
return intersects_2d(r0, r1);
|
||||
case 3:
|
||||
return intersects_3d(r0, r1);
|
||||
}
|
||||
}
|
||||
|
||||
bool RegularMesh::intersects_1d(Position r0, Position r1) const
|
||||
{
|
||||
// Copy coordinates of mesh lower_left and upper_right
|
||||
double left = lower_left_[0];
|
||||
double right = upper_right_[0];
|
||||
|
||||
// Check if line intersects either left or right surface
|
||||
if (r0.x < left) {
|
||||
return r1.x > left;
|
||||
} else if (r0.x < right) {
|
||||
return r1.x < left || r1.x > right;
|
||||
} else {
|
||||
return r1.x < right;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegularMesh::intersects_2d(Position r0, Position r1) const
|
||||
{
|
||||
// Copy coordinates of starting point
|
||||
double x0 = r0.x;
|
||||
double y0 = r0.y;
|
||||
|
||||
// Copy coordinates of ending point
|
||||
double x1 = r1.x;
|
||||
double y1 = r1.y;
|
||||
|
||||
// Copy coordinates of mesh lower_left
|
||||
double xm0 = lower_left_[0];
|
||||
double ym0 = lower_left_[1];
|
||||
|
||||
// Copy coordinates of mesh upper_right
|
||||
double xm1 = upper_right_[0];
|
||||
double ym1 = upper_right_[1];
|
||||
|
||||
// Check if line intersects left surface -- calculate the intersection point y
|
||||
if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) {
|
||||
double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0);
|
||||
if (yi >= ym0 && yi < ym1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects back surface -- calculate the intersection point
|
||||
// x
|
||||
if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) {
|
||||
double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0);
|
||||
if (xi >= xm0 && xi < xm1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects right surface -- calculate the intersection
|
||||
// point y
|
||||
if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) {
|
||||
double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0);
|
||||
if (yi >= ym0 && yi < ym1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects front surface -- calculate the intersection point
|
||||
// x
|
||||
if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) {
|
||||
double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0);
|
||||
if (xi >= xm0 && xi < xm1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RegularMesh::intersects_3d(Position r0, Position r1) const
|
||||
{
|
||||
// Copy coordinates of starting point
|
||||
double x0 = r0.x;
|
||||
double y0 = r0.y;
|
||||
double z0 = r0.z;
|
||||
|
||||
// Copy coordinates of ending point
|
||||
double x1 = r1.x;
|
||||
double y1 = r1.y;
|
||||
double z1 = r1.z;
|
||||
|
||||
// Copy coordinates of mesh lower_left
|
||||
double xm0 = lower_left_[0];
|
||||
double ym0 = lower_left_[1];
|
||||
double zm0 = lower_left_[2];
|
||||
|
||||
// Copy coordinates of mesh upper_right
|
||||
double xm1 = upper_right_[0];
|
||||
double ym1 = upper_right_[1];
|
||||
double zm1 = upper_right_[2];
|
||||
|
||||
// Check if line intersects left surface -- calculate the intersection point
|
||||
// (y,z)
|
||||
if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) {
|
||||
double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0);
|
||||
double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0);
|
||||
if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects back surface -- calculate the intersection point
|
||||
// (x,z)
|
||||
if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) {
|
||||
double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0);
|
||||
double zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0);
|
||||
if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects bottom surface -- calculate the intersection
|
||||
// point (x,y)
|
||||
if ((z0 < zm0 && z1 > zm0) || (z0 > zm0 && z1 < zm0)) {
|
||||
double xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0);
|
||||
double yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0);
|
||||
if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects right surface -- calculate the intersection point
|
||||
// (y,z)
|
||||
if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) {
|
||||
double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0);
|
||||
double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0);
|
||||
if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects front surface -- calculate the intersection point
|
||||
// (x,z)
|
||||
if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) {
|
||||
double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0);
|
||||
double zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0);
|
||||
if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line intersects top surface -- calculate the intersection point
|
||||
// (x,y)
|
||||
if ((z0 < zm1 && z1 > zm1) || (z0 > zm1 && z1 < zm1)) {
|
||||
double xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0);
|
||||
double yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0);
|
||||
if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RegularMesh::bins_crossed(const Particle* p, std::vector<int>& bins,
|
||||
std::vector<double>& lengths) const
|
||||
{
|
||||
constexpr int MAX_SEARCH_ITER = 100;
|
||||
|
||||
// ========================================================================
|
||||
// Determine if the track intersects the tally mesh.
|
||||
|
||||
// Copy the starting and ending coordinates of the particle. Offset these
|
||||
// just a bit for the purposes of determining if there was an intersection
|
||||
// in case the mesh surfaces coincide with lattice/geometric surfaces which
|
||||
// might produce finite-precision errors.
|
||||
Position last_r {p->last_xyz};
|
||||
Position r {p->coord[0].xyz};
|
||||
Direction u {p->coord[0].uvw};
|
||||
|
||||
Position r0 = last_r + TINY_BIT*u;
|
||||
Position r1 = r - TINY_BIT*u;
|
||||
|
||||
// Determine indices for starting and ending location.
|
||||
int n = n_dimension_;
|
||||
xt::xtensor<int, 1> ijk0 = xt::empty<int>({n});
|
||||
bool start_in_mesh;
|
||||
get_indices(r0, ijk0.data(), &start_in_mesh);
|
||||
xt::xtensor<int, 1> ijk1 = xt::empty<int>({n});
|
||||
bool end_in_mesh;
|
||||
get_indices(r1, ijk1.data(), &end_in_mesh);
|
||||
|
||||
// Check if the track intersects any part of the mesh.
|
||||
if (!start_in_mesh && !end_in_mesh) {
|
||||
if (!intersects(r0, r1)) return;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Figure out which mesh cell to tally.
|
||||
|
||||
// Copy the un-modified coordinates the particle direction.
|
||||
r0 = last_r;
|
||||
r1 = r;
|
||||
|
||||
// Compute the length of the entire track.
|
||||
double total_distance = (r1 - r0).norm();
|
||||
|
||||
// We are looking for the first valid mesh bin. Check to see if the
|
||||
// particle starts inside the mesh.
|
||||
if (!start_in_mesh) {
|
||||
xt::xtensor<double, 1> d = xt::zeros<double>({n});
|
||||
|
||||
// The particle does not start in the mesh. Note that we nudged the
|
||||
// start and end coordinates by a TINY_BIT each so we will have
|
||||
// difficulty resolving tracks that are less than 2*TINY_BIT in length.
|
||||
// If the track is that short, it is also insignificant so we can
|
||||
// safely ignore it in the tallies.
|
||||
if (total_distance < 2*TINY_BIT) return;
|
||||
|
||||
// The particle does not start in the mesh so keep iterating the ijk0
|
||||
// indices to cross the nearest mesh surface until we've found a valid
|
||||
// bin. MAX_SEARCH_ITER prevents an infinite loop.
|
||||
int search_iter = 0;
|
||||
int j;
|
||||
while (xt::any(ijk0 < 1) || xt::any(ijk0 > shape_)) {
|
||||
if (search_iter == MAX_SEARCH_ITER) {
|
||||
warning("Failed to find a mesh intersection on a tally mesh filter.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (j = 0; j < n; ++j) {
|
||||
if (std::fabs(u[j]) < FP_PRECISION) {
|
||||
d(j) = INFTY;
|
||||
} else if (u[j] > 0.0) {
|
||||
double xyz_cross = lower_left_[j] + ijk0(j) * width_[j];
|
||||
d(j) = (xyz_cross - r0[j]) / u[j];
|
||||
} else {
|
||||
double xyz_cross = lower_left_[j] + (ijk0(j) - 1) * width_[j];
|
||||
d(j) = (xyz_cross - r0[j]) / u[j];
|
||||
}
|
||||
}
|
||||
|
||||
j = xt::argmin(d)(0);
|
||||
if (u[j] > 0.0) {
|
||||
++ijk0(j);
|
||||
} else {
|
||||
--ijk0(j);
|
||||
}
|
||||
|
||||
++search_iter;
|
||||
}
|
||||
|
||||
// Advance position
|
||||
r0 += d(j) * u;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// ========================================================================
|
||||
// Compute the length of the track segment in the each mesh cell and return
|
||||
|
||||
double distance;
|
||||
int j;
|
||||
if (ijk0 == ijk1) {
|
||||
// The track ends in this cell. Use the particle end location rather
|
||||
// than the mesh surface.
|
||||
distance = (r1 - r0).norm();
|
||||
} else {
|
||||
// The track exits this cell. Determine the distance to the closest mesh
|
||||
// surface.
|
||||
xt::xtensor<double, 1> d = xt::zeros<double>({n});
|
||||
for (int j = 0; j < n; ++j) {
|
||||
if (std::fabs(u[j]) < FP_PRECISION) {
|
||||
d(j) = INFTY;
|
||||
} else if (u[j] > 0) {
|
||||
double xyz_cross = lower_left_[j] + ijk0(j) * width_[j];
|
||||
d(j) = (xyz_cross - r0[j]) / u[j];
|
||||
} else {
|
||||
double xyz_cross = lower_left_[j] + (ijk0(j) - 1) * width_[j];
|
||||
d(j) = (xyz_cross - r0[j]) / u[j];
|
||||
}
|
||||
}
|
||||
j = xt::argmin(d)(0);
|
||||
distance = d(j);
|
||||
}
|
||||
|
||||
// Assign the next tally bin and the score.
|
||||
int bin = get_bin_from_indices(ijk0.data());
|
||||
bins.push_back(bin);
|
||||
lengths.push_back(distance / total_distance);
|
||||
|
||||
// If the particle track ends in that bin, then we are done.
|
||||
if (ijk0 == ijk1) break;
|
||||
|
||||
// Translate the starting coordintes by the distance to that face. This
|
||||
// should be the xyz that we computed the distance to in the last
|
||||
// iteration of the filter loop.
|
||||
r0 += distance * u;
|
||||
|
||||
// Increment the indices into the next mesh cell.
|
||||
if (u[j] > 0.0) {
|
||||
++ijk0(j);
|
||||
} else {
|
||||
--ijk0(j);
|
||||
}
|
||||
|
||||
// If the next indices are invalid, then the track has left the mesh and
|
||||
// we are done.
|
||||
if (xt::any(ijk0 < 1) || xt::any(ijk0 > shape_)) break;
|
||||
}
|
||||
}
|
||||
|
||||
void RegularMesh::surface_bins_crossed(const Particle* p, std::vector<int>& bins) const
|
||||
{
|
||||
// ========================================================================
|
||||
// Determine if the track intersects the tally mesh.
|
||||
|
||||
// Copy the starting and ending coordinates of the particle.
|
||||
Position r0 {p->last_xyz_current};
|
||||
Position r1 {p->coord[0].xyz};
|
||||
Direction u {p->coord[0].uvw};
|
||||
|
||||
// Determine indices for starting and ending location.
|
||||
int n = n_dimension_;
|
||||
xt::xtensor<int, 1> ijk0 = xt::empty<int>({n});
|
||||
bool start_in_mesh;
|
||||
get_indices(r0, ijk0.data(), &start_in_mesh);
|
||||
xt::xtensor<int, 1> ijk1 = xt::empty<int>({n});
|
||||
bool end_in_mesh;
|
||||
get_indices(r1, ijk1.data(), &end_in_mesh);
|
||||
|
||||
// Check if the track intersects any part of the mesh.
|
||||
if (!start_in_mesh && !end_in_mesh) {
|
||||
if (!intersects(r0, r1)) return;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Figure out which mesh cell to tally.
|
||||
|
||||
// Calculate number of surface crossings
|
||||
int n_cross = xt::sum(xt::abs(ijk1 - ijk0))();
|
||||
if (n_cross == 0) return;
|
||||
|
||||
// Bounding coordinates
|
||||
Position xyz_cross;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (u[i] > 0.0) {
|
||||
xyz_cross[i] = lower_left_[i] + ijk0[i] * width_[i];
|
||||
} else {
|
||||
xyz_cross[i] = lower_left_[i] + (ijk0[i] - 1) * width_[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < n_cross; ++j) {
|
||||
// Set the distances to infinity
|
||||
Position d {INFTY, INFTY, INFTY};
|
||||
|
||||
// Determine closest bounding surface. We need to treat
|
||||
// special case where the cosine of the angle is zero since this would
|
||||
// result in a divide-by-zero.
|
||||
double distance = INFTY;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (u[i] == 0) {
|
||||
d[i] = INFINITY;
|
||||
} else {
|
||||
d[i] = (xyz_cross[i] - r0[i])/u[i];
|
||||
}
|
||||
distance = std::min(distance, d[i]);
|
||||
}
|
||||
|
||||
// Loop over the dimensions
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// Check whether distance is the shortest distance
|
||||
if (distance == d[i]) {
|
||||
|
||||
// Check whether particle is moving in positive i direction
|
||||
if (u[i] > 0) {
|
||||
|
||||
// Outward current on i max surface
|
||||
if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_)) {
|
||||
int i_surf = 4*i + 3;
|
||||
int i_mesh = get_bin_from_indices(ijk0.data());
|
||||
int i_bin = 4*n*(i_mesh - 1) + i_surf;
|
||||
|
||||
bins.push_back(i_bin);
|
||||
}
|
||||
|
||||
// Advance position
|
||||
++ijk0[i];
|
||||
xyz_cross[i] += width_[i];
|
||||
|
||||
// If the particle crossed the surface, tally the inward current on
|
||||
// i min surface
|
||||
if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_)) {
|
||||
int i_surf = 4*i + 2;
|
||||
int i_mesh = get_bin_from_indices(ijk0.data());
|
||||
int i_bin = 4*n*(i_mesh - 1) + i_surf;
|
||||
|
||||
bins.push_back(i_bin);
|
||||
}
|
||||
|
||||
} else {
|
||||
// The particle is moving in the negative i direction
|
||||
|
||||
// Outward current on i min surface
|
||||
if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_) ){
|
||||
int i_surf = 4*i + 1;
|
||||
int i_mesh = get_bin_from_indices(ijk0.data());
|
||||
int i_bin = 4*n*(i_mesh - 1) + i_surf;
|
||||
|
||||
bins.push_back(i_bin);
|
||||
}
|
||||
|
||||
// Advance position
|
||||
--ijk0[i];
|
||||
xyz_cross[i] -= width_[i];
|
||||
|
||||
// If the particle crossed the surface, tally the inward current on
|
||||
// i max surface
|
||||
if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_)) {
|
||||
int i_surf = 4*i + 4;
|
||||
int i_mesh = get_bin_from_indices(ijk0.data());
|
||||
int i_bin = 4*n*(i_mesh - 1) + i_surf;
|
||||
|
||||
bins.push_back(i_bin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate new coordinates
|
||||
r0 += distance * u;
|
||||
}
|
||||
}
|
||||
|
||||
void RegularMesh::to_hdf5(hid_t group) const
|
||||
{
|
||||
hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_));
|
||||
|
||||
write_dataset(mesh_group, "type", "regular");
|
||||
write_dataset(mesh_group, "dimension", shape_);
|
||||
write_dataset(mesh_group, "lower_left", lower_left_);
|
||||
write_dataset(mesh_group, "upper_right", upper_right_);
|
||||
write_dataset(mesh_group, "width", width_);
|
||||
|
||||
close_group(mesh_group);
|
||||
}
|
||||
|
||||
xt::xarray<double> RegularMesh::count_sites(int64_t n, const Bank* bank,
|
||||
int n_energy, const double* energies, bool* outside) const
|
||||
{
|
||||
// Determine shape of array for counts
|
||||
std::size_t m = xt::prod(shape_)();
|
||||
std::vector<std::size_t> shape;
|
||||
if (n_energy > 0) {
|
||||
shape = {m, static_cast<std::size_t>(n_energy - 1)};
|
||||
} else {
|
||||
shape = {m};
|
||||
}
|
||||
|
||||
// Create array of zeros
|
||||
xt::xarray<double> cnt {shape, 0.0};
|
||||
bool outside_ = false;
|
||||
|
||||
for (int64_t i = 0; i < n; ++i) {
|
||||
// determine scoring bin for entropy mesh
|
||||
// TODO: off-by-one
|
||||
int mesh_bin = get_bin({bank[i].xyz}) - 1;
|
||||
|
||||
// if outside mesh, skip particle
|
||||
if (mesh_bin < 0) {
|
||||
outside_ = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n_energy > 0) {
|
||||
double E = bank[i].E;
|
||||
if (E >= energies[0] && E <= energies[n_energy - 1]) {
|
||||
// determine energy bin
|
||||
int e_bin = lower_bound_index(energies, energies + n_energy, E);
|
||||
|
||||
// Add to appropriate bin
|
||||
cnt(mesh_bin, e_bin) += bank[i].wgt;
|
||||
}
|
||||
} else {
|
||||
// Add to appropriate bin
|
||||
cnt(mesh_bin) += bank[i].wgt;
|
||||
}
|
||||
}
|
||||
|
||||
// Create copy of count data
|
||||
int total = cnt.size();
|
||||
double* cnt_reduced = new double[total];
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
// collect values from all processors
|
||||
MPI_Reduce(cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0,
|
||||
mpi::intracomm);
|
||||
|
||||
// Check if there were sites outside the mesh for any processor
|
||||
if (outside) {
|
||||
MPI_Reduce(&outside_, outside, 1, MPI_C_BOOL, MPI_LOR, 0, mpi::intracomm);
|
||||
}
|
||||
#else
|
||||
std::copy(cnt.data(), cnt.data() + total, cnt_reduced);
|
||||
if (outside) *outside = outside_;
|
||||
#endif
|
||||
|
||||
// Adapt reduced values in array back into an xarray
|
||||
auto arr = xt::adapt(cnt_reduced, total, xt::acquire_ownership(), shape);
|
||||
xt::xarray<double> counts = arr;
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// C API functions
|
||||
//==============================================================================
|
||||
|
||||
//! Extend the meshes array by n elements
|
||||
extern "C" int
|
||||
openmc_extend_meshes(int32_t n, int32_t* index_start, int32_t* index_end)
|
||||
{
|
||||
if (index_start) *index_start = meshes.size();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
meshes.emplace_back(new RegularMesh{});
|
||||
}
|
||||
if (index_end) *index_end = meshes.size() - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Return the index in the meshes array of a mesh with a given ID
|
||||
extern "C" int
|
||||
openmc_get_mesh_index(int32_t id, int32_t* index)
|
||||
{
|
||||
auto pair = mesh_map.find(id);
|
||||
if (pair == mesh_map.end()) {
|
||||
set_errmsg("No mesh exists with ID=" + std::to_string(id) + ".");
|
||||
return OPENMC_E_INVALID_ID;
|
||||
}
|
||||
*index = pair->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the ID of a mesh
|
||||
extern "C" int
|
||||
openmc_mesh_get_id(int32_t index, int32_t* id)
|
||||
{
|
||||
if (index < 0 || index >= meshes.size()) {
|
||||
set_errmsg("Index in meshes array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
*id = meshes[index]->id_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Set the ID of a mesh
|
||||
extern "C" int
|
||||
openmc_mesh_set_id(int32_t index, int32_t id)
|
||||
{
|
||||
if (index < 0 || index >= meshes.size()) {
|
||||
set_errmsg("Index in meshes array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
meshes[index]->id_ = id;
|
||||
mesh_map[id] = index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get the dimension of a mesh
|
||||
extern "C" int
|
||||
openmc_mesh_get_dimension(int32_t index, int** dims, int* n)
|
||||
{
|
||||
if (index < 0 || index >= meshes.size()) {
|
||||
set_errmsg("Index in meshes array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
*dims = meshes[index]->shape_.data();
|
||||
*n = meshes[index]->n_dimension_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Set the dimension of a mesh
|
||||
extern "C" int
|
||||
openmc_mesh_set_dimension(int32_t index, int n, const int* dims)
|
||||
{
|
||||
if (index < 0 || index >= meshes.size()) {
|
||||
set_errmsg("Index in meshes array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
// Copy dimension
|
||||
std::vector<std::size_t> shape = {static_cast<std::size_t>(n)};
|
||||
auto& m = meshes[index];
|
||||
m->shape_ = xt::adapt(dims, n, xt::no_ownership(), shape);
|
||||
m->n_dimension_ = m->shape_.size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get the mesh parameters
|
||||
extern "C" int
|
||||
openmc_mesh_get_params(int32_t index, double** ll, double** ur, double** width, int* n)
|
||||
{
|
||||
if (index < 0 || index >= meshes.size()) {
|
||||
set_errmsg("Index in meshes array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
auto& m = meshes[index];
|
||||
if (m->lower_left_.dimension() == 0) {
|
||||
set_errmsg("Mesh parameters have not been set.");
|
||||
return OPENMC_E_ALLOCATE;
|
||||
}
|
||||
|
||||
*ll = m->lower_left_.data();
|
||||
*ur = m->upper_right_.data();
|
||||
*width = m->width_.data();
|
||||
*n = m->n_dimension_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Set the mesh parameters
|
||||
extern "C" int
|
||||
openmc_mesh_set_params(int32_t index, int n, const double* ll, const double* ur,
|
||||
const double* width)
|
||||
{
|
||||
if (index < 0 || index >= meshes.size()) {
|
||||
set_errmsg("Index in meshes array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
auto& m = meshes[index];
|
||||
std::vector<std::size_t> shape = {static_cast<std::size_t>(n)};
|
||||
if (ll && ur) {
|
||||
m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape);
|
||||
m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape);
|
||||
m->width_ = (m->upper_right_ - m->lower_left_) / m->shape_;
|
||||
} else if (ll && width) {
|
||||
m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape);
|
||||
m->width_ = xt::adapt(width, n, xt::no_ownership(), shape);
|
||||
m->upper_right_ = m->lower_left_ + m->shape_ * m->width_;
|
||||
} else if (ur && width) {
|
||||
m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape);
|
||||
m->width_ = xt::adapt(width, n, xt::no_ownership(), shape);
|
||||
m->lower_left_ = m->upper_right_ - m->shape_ * m->width_;
|
||||
} else {
|
||||
set_errmsg("At least two parameters must be specified.");
|
||||
return OPENMC_E_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
void read_meshes(pugi::xml_node* root)
|
||||
{
|
||||
for (auto node : root->children("mesh")) {
|
||||
// Read mesh and add to vector
|
||||
meshes.emplace_back(new RegularMesh{node});
|
||||
|
||||
// Map ID to position in vector
|
||||
mesh_map[meshes.back()->id_] = meshes.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void meshes_to_hdf5(hid_t group)
|
||||
{
|
||||
// Write number of meshes
|
||||
hid_t meshes_group = create_group(group, "meshes");
|
||||
int32_t n_meshes = meshes.size();
|
||||
write_attribute(meshes_group, "n_meshes", n_meshes);
|
||||
|
||||
if (n_meshes > 0) {
|
||||
// Write IDs of meshes
|
||||
std::vector<int> ids;
|
||||
for (const auto& m : meshes) {
|
||||
m->to_hdf5(meshes_group);
|
||||
ids.push_back(m->id_);
|
||||
}
|
||||
write_attribute(meshes_group, "ids", ids);
|
||||
}
|
||||
|
||||
close_group(meshes_group);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Fortran compatibility
|
||||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
int n_meshes() { return meshes.size(); }
|
||||
|
||||
RegularMesh* mesh_ptr(int i) { return meshes.at(i).get(); }
|
||||
|
||||
int32_t mesh_id(RegularMesh* m) { return m->id_; }
|
||||
|
||||
double mesh_volume_frac(RegularMesh* m) { return m->volume_frac_; }
|
||||
|
||||
int mesh_n_dimension(RegularMesh* m) { return m->n_dimension_; }
|
||||
|
||||
int mesh_dimension(RegularMesh* m, int i) { return m->shape_(i - 1); }
|
||||
|
||||
double mesh_lower_left(RegularMesh* m, int i) { return m->lower_left_(i - 1); }
|
||||
|
||||
double mesh_upper_right(RegularMesh* m, int i) { return m->upper_right_(i - 1); }
|
||||
|
||||
double mesh_width(RegularMesh* m, int i) { return m->width_(i - 1); }
|
||||
|
||||
int mesh_get_bin(RegularMesh* m, const double* xyz)
|
||||
{
|
||||
return m->get_bin({xyz});
|
||||
}
|
||||
|
||||
int mesh_get_bin_from_indices(RegularMesh* m, const int* ijk)
|
||||
{
|
||||
return m->get_bin_from_indices(ijk);
|
||||
}
|
||||
|
||||
void mesh_get_indices(RegularMesh* m, const double* xyz, int* ijk, bool* in_mesh)
|
||||
{
|
||||
m->get_indices({xyz}, ijk, in_mesh);
|
||||
}
|
||||
|
||||
void mesh_get_indices_from_bin(RegularMesh* m, int bin, int* ijk)
|
||||
{
|
||||
m->get_indices_from_bin(bin, ijk);
|
||||
}
|
||||
|
||||
void mesh_bins_crossed(RegularMesh* m, const Particle* p,
|
||||
TallyFilterMatch* match)
|
||||
{
|
||||
match->bins.clear();
|
||||
match->weights.clear();
|
||||
m->bins_crossed(p, match->bins, match->weights);
|
||||
}
|
||||
|
||||
void mesh_surface_bins_crossed(RegularMesh* m, const Particle* p,
|
||||
TallyFilterMatch* match)
|
||||
{
|
||||
match->bins.clear();
|
||||
match->weights.clear();
|
||||
m->surface_bins_crossed(p, match->bins);
|
||||
for (auto b : match->bins) {
|
||||
match->weights.push_back(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void free_memory_mesh()
|
||||
{
|
||||
meshes.clear();
|
||||
mesh_map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace openmc
|
||||
|
|
@ -2,185 +2,242 @@ module mesh_header
|
|||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
use dict_header, only: DictIntInt
|
||||
use error
|
||||
use hdf5_interface
|
||||
use string, only: to_str, to_lower
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
private
|
||||
public :: free_memory_mesh
|
||||
public :: openmc_extend_meshes
|
||||
public :: openmc_get_mesh_index
|
||||
public :: openmc_mesh_get_id
|
||||
public :: openmc_mesh_get_dimension
|
||||
public :: openmc_mesh_get_params
|
||||
public :: openmc_mesh_set_id
|
||||
public :: openmc_mesh_set_dimension
|
||||
public :: openmc_mesh_set_params
|
||||
|
||||
!===============================================================================
|
||||
! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by
|
||||
! congruent squares or cubes
|
||||
!===============================================================================
|
||||
|
||||
type, public :: RegularMesh
|
||||
integer :: id = -1 ! user-specified id
|
||||
integer :: type = MESH_REGULAR ! rectangular, hexagonal
|
||||
integer(C_INT) :: n_dimension ! rank of mesh
|
||||
real(8) :: volume_frac ! volume fraction of each cell
|
||||
integer(C_INT), allocatable :: dimension(:) ! number of cells in each direction
|
||||
real(C_DOUBLE), allocatable :: lower_left(:) ! lower-left corner of mesh
|
||||
real(C_DOUBLE), allocatable :: upper_right(:) ! upper-right corner of mesh
|
||||
real(C_DOUBLE), allocatable :: width(:) ! width of each mesh cell
|
||||
type :: RegularMesh
|
||||
type(C_PTR) :: ptr
|
||||
contains
|
||||
procedure :: from_xml => regular_from_xml
|
||||
procedure :: id => regular_id
|
||||
procedure :: volume_frac => regular_volume_frac
|
||||
procedure :: n_dimension => regular_n_dimension
|
||||
procedure :: dimension => regular_dimension
|
||||
procedure :: lower_left => regular_lower_left
|
||||
procedure :: upper_right => regular_upper_right
|
||||
procedure :: width => regular_width
|
||||
|
||||
procedure :: get_bin => regular_get_bin
|
||||
procedure :: get_indices => regular_get_indices
|
||||
procedure :: get_bin_from_indices => regular_get_bin_from_indices
|
||||
procedure :: get_indices_from_bin => regular_get_indices_from_bin
|
||||
procedure :: intersects => regular_intersects
|
||||
procedure :: to_hdf5 => regular_to_hdf5
|
||||
end type RegularMesh
|
||||
|
||||
integer(C_INT32_T), public, bind(C) :: n_meshes = 0 ! # of structured meshes
|
||||
interface
|
||||
function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C)
|
||||
import C_INT32_T, C_INT
|
||||
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
|
||||
end function openmc_extend_meshes
|
||||
|
||||
type(RegularMesh), public, allocatable, target :: meshes(:)
|
||||
function openmc_get_mesh_index(id, index) result(err) bind(C)
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT32_T), value :: id
|
||||
integer(C_INT32_T), intent(out) :: index
|
||||
integer(C_INT) :: err
|
||||
end function openmc_get_mesh_index
|
||||
|
||||
! Dictionary that maps user IDs to indices in 'meshes'
|
||||
type(DictIntInt), public :: mesh_dict
|
||||
function openmc_mesh_get_id(index, id) result(err) bind(C)
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT32_T), value :: index
|
||||
integer(C_INT32_T), intent(out) :: id
|
||||
integer(C_INT) :: err
|
||||
end function openmc_mesh_get_id
|
||||
|
||||
function openmc_mesh_set_id(index, id) result(err) bind(C)
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT32_T), value, intent(in) :: id
|
||||
integer(C_INT) :: err
|
||||
end function openmc_mesh_set_id
|
||||
|
||||
function openmc_mesh_get_dimension(index, dims, n) result(err) bind(C)
|
||||
import C_INT32_T, C_PTR, C_INT
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
type(C_PTR), intent(out) :: dims
|
||||
integer(C_INT), intent(out) :: n
|
||||
integer(C_INT) :: err
|
||||
end function openmc_mesh_get_dimension
|
||||
|
||||
function openmc_mesh_set_dimension(index, n, dims) result(err) bind(C)
|
||||
import C_INT32_T, C_INT
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: n
|
||||
integer(C_INT), intent(in) :: dims(n)
|
||||
integer(C_INT) :: err
|
||||
end function openmc_mesh_set_dimension
|
||||
|
||||
function openmc_mesh_get_params(index, ll, ur, width, n) result(err) bind(C)
|
||||
import C_INT32_T, C_PTR, C_INT
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
type(C_PTR), intent(out) :: ll
|
||||
type(C_PTR), intent(out) :: ur
|
||||
type(C_PTR), intent(out) :: width
|
||||
integer(C_INT), intent(out) :: n
|
||||
integer(C_INT) :: err
|
||||
end function openmc_mesh_get_params
|
||||
|
||||
function openmc_mesh_set_params(index, n, ll, ur, width) result(err) bind(C)
|
||||
import C_INT32_T, C_INT, C_DOUBLE
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: n
|
||||
real(C_DOUBLE), intent(in), optional :: ll(n)
|
||||
real(C_DOUBLE), intent(in), optional :: ur(n)
|
||||
real(C_DOUBLE), intent(in), optional :: width(n)
|
||||
integer(C_INT) :: err
|
||||
end function openmc_mesh_set_params
|
||||
|
||||
function mesh_id(ptr) result(id) bind(C)
|
||||
import C_PTR, C_INT32_T
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT32_T) :: id
|
||||
end function
|
||||
|
||||
function mesh_volume_frac(ptr) result(volume_frac) bind(C)
|
||||
import C_PTR, C_DOUBLE
|
||||
type(C_PTR), value :: ptr
|
||||
real(C_DOUBLE) :: volume_frac
|
||||
end function
|
||||
|
||||
function mesh_n_dimension(ptr) result(n) bind(C)
|
||||
import C_PTR, C_INT
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT) :: n
|
||||
end function
|
||||
|
||||
function mesh_dimension(ptr, i) result(d) bind(C)
|
||||
import C_PTR, C_INT
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), value :: i
|
||||
integer(C_INT) :: d
|
||||
end function
|
||||
|
||||
function mesh_lower_left(ptr, i) result(ll) bind(C)
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), value :: i
|
||||
real(C_DOUBLE) :: ll
|
||||
end function
|
||||
|
||||
function mesh_upper_right(ptr, i) result(ur) bind(C)
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), value :: i
|
||||
real(C_DOUBLE) :: ur
|
||||
end function
|
||||
|
||||
function mesh_width(ptr, i) result(w) bind(C)
|
||||
import C_PTR, C_INT, C_DOUBLE
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), value :: i
|
||||
real(C_DOUBLE) :: w
|
||||
end function
|
||||
|
||||
pure function mesh_get_bin(ptr, xyz) result(bin) bind(C)
|
||||
import C_PTR, C_DOUBLE, C_INT
|
||||
type(C_PTR), value :: ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(*)
|
||||
integer(C_INT) :: bin
|
||||
end function
|
||||
|
||||
pure function mesh_get_bin_from_indices(ptr, ijk) result(bin) bind(C)
|
||||
import C_PTR, C_INT
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), intent(in) :: ijk(*)
|
||||
integer(C_INT) :: bin
|
||||
end function
|
||||
|
||||
pure subroutine mesh_get_indices(ptr, xyz, ijk, in_mesh) bind(C)
|
||||
import C_PTR, C_DOUBLE, C_INT, C_BOOL
|
||||
type(C_PTR), value :: ptr
|
||||
real(C_DOUBLE), intent(in) :: xyz(*)
|
||||
integer(C_INT), intent(out) :: ijk(*)
|
||||
logical(C_BOOL), intent(out) :: in_mesh
|
||||
end subroutine
|
||||
|
||||
pure subroutine mesh_get_indices_from_bin(ptr, bin, ijk) bind(C)
|
||||
import C_PTR, C_INT
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), value :: bin
|
||||
integer(C_INT), intent(out) :: ijk(*)
|
||||
end subroutine
|
||||
|
||||
function mesh_ptr(i) result(ptr) bind(C)
|
||||
import C_INT, C_PTR
|
||||
integer(C_INT), value :: i
|
||||
type(C_PTR) :: ptr
|
||||
end function
|
||||
|
||||
subroutine read_meshes(node_ptr) bind(C)
|
||||
import C_PTR
|
||||
type(C_PTR) :: node_ptr
|
||||
end subroutine
|
||||
|
||||
function n_meshes() result(n) bind(C)
|
||||
import C_INT
|
||||
integer(C_INT) :: n
|
||||
end function
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
||||
subroutine regular_from_xml(this, node)
|
||||
class(RegularMesh), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
function meshes(i) result(m)
|
||||
integer, intent(in) :: i
|
||||
type(RegularMesh) :: m
|
||||
|
||||
integer :: n
|
||||
character(MAX_LINE_LEN) :: temp_str
|
||||
m % ptr = mesh_ptr(i)
|
||||
end function
|
||||
|
||||
! Copy mesh id
|
||||
if (check_for_node(node, "id")) then
|
||||
call get_node_value(node, "id", this % id)
|
||||
function regular_id(this) result(id)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(C_INT32_T) :: id
|
||||
id = mesh_id(this % ptr)
|
||||
end function
|
||||
|
||||
! Check to make sure 'id' hasn't been used
|
||||
if (mesh_dict % has(this % id)) then
|
||||
call fatal_error("Two or more meshes use the same unique ID: " &
|
||||
// to_str(this % id))
|
||||
end if
|
||||
end if
|
||||
function regular_volume_frac(this) result(volume_frac)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
real(C_DOUBLE) :: volume_frac
|
||||
volume_frac = mesh_volume_frac(this % ptr)
|
||||
end function
|
||||
|
||||
! Read mesh type
|
||||
if (check_for_node(node, "type")) then
|
||||
call get_node_value(node, "type", temp_str)
|
||||
select case (to_lower(temp_str))
|
||||
case ('rect', 'rectangle', 'rectangular')
|
||||
call warning("Mesh type '" // trim(temp_str) // "' is deprecated. &
|
||||
&Please use 'regular' instead.")
|
||||
this % type = MESH_REGULAR
|
||||
case ('regular')
|
||||
this % type = MESH_REGULAR
|
||||
case default
|
||||
call fatal_error("Invalid mesh type: " // trim(temp_str))
|
||||
end select
|
||||
else
|
||||
this % type = MESH_REGULAR
|
||||
end if
|
||||
function regular_n_dimension(this) result(n)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(C_INT) :: n
|
||||
n = mesh_n_dimension(this % ptr)
|
||||
end function
|
||||
|
||||
! Determine number of dimensions for mesh
|
||||
if (check_for_node(node, "dimension")) then
|
||||
n = node_word_count(node, "dimension")
|
||||
if (n /= 1 .and. n /= 2 .and. n /= 3) then
|
||||
call fatal_error("Mesh must be one, two, or three dimensions.")
|
||||
end if
|
||||
this % n_dimension = n
|
||||
function regular_dimension(this, i) result(d)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(C_INT), intent(in) :: i
|
||||
integer(C_INT) :: d
|
||||
d = mesh_dimension(this % ptr, i)
|
||||
end function
|
||||
|
||||
! Allocate attribute arrays
|
||||
allocate(this % dimension(n))
|
||||
function regular_lower_left(this, i) result(ll)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(C_INT), intent(in) :: i
|
||||
real(C_DOUBLE) :: ll
|
||||
ll = mesh_lower_left(this % ptr, i)
|
||||
end function
|
||||
|
||||
! Check that dimensions are all greater than zero
|
||||
call get_node_array(node, "dimension", this % dimension)
|
||||
if (any(this % dimension <= 0)) then
|
||||
call fatal_error("All entries on the <dimension> element for a tally &
|
||||
&mesh must be positive.")
|
||||
end if
|
||||
end if
|
||||
function regular_upper_right(this, i) result(ur)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(C_INT), intent(in) :: i
|
||||
real(C_DOUBLE) :: ur
|
||||
ur = mesh_upper_right(this % ptr, i)
|
||||
end function
|
||||
|
||||
! Check for lower-left coordinates
|
||||
if (check_for_node(node, "lower_left")) then
|
||||
n = node_word_count(node, "lower_left")
|
||||
allocate(this % lower_left(n))
|
||||
|
||||
! Read mesh lower-left corner location
|
||||
call get_node_array(node, "lower_left", this % lower_left)
|
||||
else
|
||||
call fatal_error("Must specify <lower_left> on a mesh.")
|
||||
end if
|
||||
|
||||
if (check_for_node(node, "width")) then
|
||||
! Make sure both upper-right or width were specified
|
||||
if (check_for_node(node, "upper_right")) then
|
||||
call fatal_error("Cannot specify both <upper_right> and <width> on a &
|
||||
&mesh.")
|
||||
end if
|
||||
|
||||
n = node_word_count(node, "width")
|
||||
allocate(this % width(n))
|
||||
allocate(this % upper_right(n))
|
||||
|
||||
! Check to ensure width has same dimensions
|
||||
if (n /= size(this % lower_left)) then
|
||||
call fatal_error("Number of entries on <width> must be the same as &
|
||||
&the number of entries on <lower_left>.")
|
||||
end if
|
||||
|
||||
! Check for negative widths
|
||||
call get_node_array(node, "width", this % width)
|
||||
if (any(this % width < ZERO)) then
|
||||
call fatal_error("Cannot have a negative <width> on a tally mesh.")
|
||||
end if
|
||||
|
||||
! Set width and upper right coordinate
|
||||
this % upper_right = this % lower_left + this % dimension * this % width
|
||||
|
||||
elseif (check_for_node(node, "upper_right")) then
|
||||
n = node_word_count(node, "upper_right")
|
||||
allocate(this % upper_right(n))
|
||||
allocate(this % width(n))
|
||||
|
||||
! Check to ensure width has same dimensions
|
||||
if (n /= size(this % lower_left)) then
|
||||
call fatal_error("Number of entries on <upper_right> must be the &
|
||||
&same as the number of entries on <lower_left>.")
|
||||
end if
|
||||
|
||||
! Check that upper-right is above lower-left
|
||||
call get_node_array(node, "upper_right", this % upper_right)
|
||||
if (any(this % upper_right < this % lower_left)) then
|
||||
call fatal_error("The <upper_right> coordinates must be greater than &
|
||||
&the <lower_left> coordinates on a tally mesh.")
|
||||
end if
|
||||
|
||||
! Set width and upper right coordinate
|
||||
this % width = (this % upper_right - this % lower_left) / this % dimension
|
||||
else
|
||||
call fatal_error("Must specify either <upper_right> and <width> on a &
|
||||
&mesh.")
|
||||
end if
|
||||
|
||||
if (allocated(this % dimension)) then
|
||||
if (size(this % dimension) /= size(this % lower_left)) then
|
||||
call fatal_error("Number of entries on <lower_left> must be the same &
|
||||
&as the number of entries on <dimension>.")
|
||||
end if
|
||||
|
||||
! Set volume fraction
|
||||
this % volume_frac = ONE/real(product(this % dimension),8)
|
||||
end if
|
||||
|
||||
end subroutine regular_from_xml
|
||||
function regular_width(this, i) result(w)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(C_INT), intent(in) :: i
|
||||
real(C_DOUBLE) :: w
|
||||
w = mesh_width(this % ptr, i)
|
||||
end function
|
||||
|
||||
!===============================================================================
|
||||
! GET_MESH_BIN determines the tally bin for a particle in a structured mesh
|
||||
|
|
@ -191,38 +248,8 @@ contains
|
|||
real(8), intent(in) :: xyz(:) ! coordinates
|
||||
integer, intent(out) :: bin ! tally bin
|
||||
|
||||
integer :: n ! size of mesh
|
||||
integer :: d ! mesh dimension index
|
||||
integer :: ijk(3) ! indices in mesh
|
||||
logical :: in_mesh ! was given coordinate in mesh at all?
|
||||
|
||||
! Get number of dimensions
|
||||
n = this % n_dimension
|
||||
|
||||
! Loop over the dimensions of the mesh
|
||||
do d = 1, n
|
||||
|
||||
! Check for cases where particle is outside of mesh
|
||||
if (xyz(d) < this % lower_left(d)) then
|
||||
bin = NO_BIN_FOUND
|
||||
return
|
||||
elseif (xyz(d) > this % upper_right(d)) then
|
||||
bin = NO_BIN_FOUND
|
||||
return
|
||||
end if
|
||||
end do
|
||||
|
||||
! Determine indices
|
||||
call this % get_indices(xyz, ijk, in_mesh)
|
||||
|
||||
! Convert indices to bin
|
||||
if (in_mesh) then
|
||||
bin = this % get_bin_from_indices(ijk)
|
||||
else
|
||||
bin = NO_BIN_FOUND
|
||||
end if
|
||||
|
||||
end subroutine regular_get_bin
|
||||
bin = mesh_get_bin(this % ptr, xyz)
|
||||
end subroutine
|
||||
|
||||
!===============================================================================
|
||||
! GET_MESH_INDICES determines the indices of a particle in a structured mesh
|
||||
|
|
@ -234,18 +261,10 @@ contains
|
|||
integer, intent(out) :: ijk(:) ! indices in mesh
|
||||
logical, intent(out) :: in_mesh ! were given coords in mesh?
|
||||
|
||||
! Find particle in mesh
|
||||
ijk(:this % n_dimension) = ceiling((xyz(:this % n_dimension) - &
|
||||
this % lower_left)/this % width)
|
||||
|
||||
! Determine if particle is in mesh
|
||||
if (any(ijk(:this % n_dimension) < 1) .or. &
|
||||
any(ijk(:this % n_dimension) > this % dimension)) then
|
||||
in_mesh = .false.
|
||||
else
|
||||
in_mesh = .true.
|
||||
end if
|
||||
logical(C_BOOL) :: in_mesh_
|
||||
|
||||
call mesh_get_indices(this % ptr, xyz, ijk, in_mesh_)
|
||||
in_mesh = in_mesh_
|
||||
end subroutine regular_get_indices
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -258,15 +277,7 @@ contains
|
|||
integer, intent(in) :: ijk(:)
|
||||
integer :: bin
|
||||
|
||||
if (this % n_dimension == 1) then
|
||||
bin = ijk(1)
|
||||
elseif (this % n_dimension == 2) then
|
||||
bin = (ijk(2) - 1) * this % dimension(1) + ijk(1)
|
||||
elseif (this % n_dimension == 3) then
|
||||
bin = ((ijk(3) - 1) * this % dimension(2) + (ijk(2) - 1)) &
|
||||
* this % dimension(1) + ijk(1)
|
||||
end if
|
||||
|
||||
bin = mesh_get_bin_from_indices(this % ptr, ijk)
|
||||
end function regular_get_bin_from_indices
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -279,498 +290,7 @@ contains
|
|||
integer, intent(in) :: bin
|
||||
integer, intent(out) :: ijk(:)
|
||||
|
||||
if (this % n_dimension == 1) then
|
||||
ijk(1) = bin
|
||||
else if (this % n_dimension == 2) then
|
||||
ijk(1) = mod(bin - 1, this % dimension(1)) + 1
|
||||
ijk(2) = (bin - 1)/this % dimension(1) + 1
|
||||
else if (this % n_dimension == 3) then
|
||||
ijk(1) = mod(bin - 1, this % dimension(1)) + 1
|
||||
ijk(2) = mod(bin - 1, this % dimension(1) * this % dimension(2)) &
|
||||
/ this % dimension(1) + 1
|
||||
ijk(3) = (bin - 1)/(this % dimension(1) * this % dimension(2)) + 1
|
||||
end if
|
||||
|
||||
call mesh_get_indices_from_bin(this % ptr, bin, ijk)
|
||||
end subroutine regular_get_indices_from_bin
|
||||
|
||||
!===============================================================================
|
||||
! MESH_INTERSECTS determines if a line between xyz0 and xyz1 intersects the
|
||||
! outer boundary of the given mesh. This is important for determining whether a
|
||||
! track will score to a mesh tally.
|
||||
!===============================================================================
|
||||
|
||||
pure function regular_intersects(this, xyz0, xyz1) result(intersects)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
select case(this % n_dimension)
|
||||
case (1)
|
||||
intersects = mesh_intersects_1d(this, xyz0, xyz1)
|
||||
case (2)
|
||||
intersects = mesh_intersects_2d(this, xyz0, xyz1)
|
||||
case (3)
|
||||
intersects = mesh_intersects_3d(this, xyz0, xyz1)
|
||||
end select
|
||||
end function regular_intersects
|
||||
|
||||
pure function mesh_intersects_1d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0 ! track start point
|
||||
real(8) :: x1 ! track end point
|
||||
real(8) :: xm0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
end function mesh_intersects_1d
|
||||
|
||||
pure function mesh_intersects_2d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0, y0 ! track start point
|
||||
real(8) :: x1, y1 ! track end point
|
||||
real(8) :: xi, yi ! track intersection point with mesh
|
||||
real(8) :: xm0, ym0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1, ym1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
y0 = xyz0(2)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
y1 = xyz1(2)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
ym0 = m % lower_left(2)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
ym1 = m % upper_right(2)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface -- calculate the intersection point
|
||||
! y
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects back surface -- calculate the intersection point
|
||||
! x
|
||||
if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then
|
||||
xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface -- calculate the intersection
|
||||
! point y
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects front surface -- calculate the intersection point
|
||||
! x
|
||||
if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then
|
||||
xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
end function mesh_intersects_2d
|
||||
|
||||
pure function mesh_intersects_3d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0, y0, z0 ! track start point
|
||||
real(8) :: x1, y1, z1 ! track end point
|
||||
real(8) :: xi, yi, zi ! track intersection point with mesh
|
||||
real(8) :: xm0, ym0, zm0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1, ym1, zm1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
y0 = xyz0(2)
|
||||
z0 = xyz0(3)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
y1 = xyz1(2)
|
||||
z1 = xyz1(3)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
ym0 = m % lower_left(2)
|
||||
zm0 = m % lower_left(3)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
ym1 = m % upper_right(2)
|
||||
zm1 = m % upper_right(3)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface -- calculate the intersection point
|
||||
! (y,z)
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0)
|
||||
zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects back surface -- calculate the intersection point
|
||||
! (x,z)
|
||||
if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then
|
||||
xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0)
|
||||
zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects bottom surface -- calculate the intersection
|
||||
! point (x,y)
|
||||
if ((z0 < zm0 .and. z1 > zm0) .or. (z0 > zm0 .and. z1 < zm0)) then
|
||||
xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0)
|
||||
yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface -- calculate the intersection point
|
||||
! (y,z)
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0)
|
||||
zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects front surface -- calculate the intersection point
|
||||
! (x,z)
|
||||
if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then
|
||||
xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0)
|
||||
zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects top surface -- calculate the intersection point
|
||||
! (x,y)
|
||||
if ((z0 < zm1 .and. z1 > zm1) .or. (z0 > zm1 .and. z1 < zm1)) then
|
||||
xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0)
|
||||
yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
end function mesh_intersects_3d
|
||||
|
||||
!===============================================================================
|
||||
! TO_HDF5 writes the mesh data to an HDF5 group
|
||||
!===============================================================================
|
||||
|
||||
subroutine regular_to_hdf5(this, group)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: group
|
||||
|
||||
integer(HID_T) :: mesh_group
|
||||
|
||||
mesh_group = create_group(group, "mesh " // trim(to_str(this % id)))
|
||||
|
||||
call write_dataset(mesh_group, "type", "regular")
|
||||
call write_dataset(mesh_group, "dimension", this % dimension)
|
||||
call write_dataset(mesh_group, "lower_left", this % lower_left)
|
||||
call write_dataset(mesh_group, "upper_right", this % upper_right)
|
||||
call write_dataset(mesh_group, "width", this % width)
|
||||
|
||||
call close_group(mesh_group)
|
||||
end subroutine regular_to_hdf5
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_MESH deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_mesh()
|
||||
n_meshes = 0
|
||||
if (allocated(meshes)) deallocate(meshes)
|
||||
call mesh_dict % clear()
|
||||
end subroutine free_memory_mesh
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C)
|
||||
! Extend the meshes 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(RegularMesh), allocatable :: temp(:) ! temporary meshes array
|
||||
|
||||
if (n_meshes == 0) then
|
||||
! Allocate meshes array
|
||||
allocate(meshes(n))
|
||||
else
|
||||
! Allocate meshes array with increased size
|
||||
allocate(temp(n_meshes + n))
|
||||
|
||||
! Copy original meshes to temporary array
|
||||
temp(1:n_meshes) = meshes
|
||||
|
||||
! Move allocation from temporary array
|
||||
call move_alloc(FROM=temp, TO=meshes)
|
||||
end if
|
||||
|
||||
! Return indices in meshes array
|
||||
if (present(index_start)) index_start = n_meshes + 1
|
||||
if (present(index_end)) index_end = n_meshes + n
|
||||
n_meshes = n_meshes + n
|
||||
|
||||
err = 0
|
||||
end function openmc_extend_meshes
|
||||
|
||||
|
||||
function openmc_get_mesh_index(id, index) result(err) bind(C)
|
||||
! Return the index in the meshes array of a mesh with a given ID
|
||||
integer(C_INT32_T), value :: id
|
||||
integer(C_INT32_T), intent(out) :: index
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (allocated(meshes)) then
|
||||
if (mesh_dict % has(id)) then
|
||||
index = mesh_dict % get(id)
|
||||
err = 0
|
||||
else
|
||||
err = E_INVALID_ID
|
||||
call set_errmsg("No mesh exists with ID=" // trim(to_str(id)) // ".")
|
||||
end if
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Memory has not been allocated for meshes.")
|
||||
end if
|
||||
end function openmc_get_mesh_index
|
||||
|
||||
|
||||
function openmc_mesh_get_id(index, id) result(err) bind(C)
|
||||
! Return the ID of a mesh
|
||||
integer(C_INT32_T), value :: index
|
||||
integer(C_INT32_T), intent(out) :: id
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= size(meshes)) then
|
||||
id = meshes(index) % id
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in meshes array is out of bounds.")
|
||||
end if
|
||||
end function openmc_mesh_get_id
|
||||
|
||||
|
||||
function openmc_mesh_set_id(index, id) result(err) bind(C)
|
||||
! Set the ID of a mesh
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT32_T), value, intent(in) :: id
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= n_meshes) then
|
||||
meshes(index) % id = id
|
||||
call mesh_dict % set(id, index)
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in meshes array is out of bounds.")
|
||||
end if
|
||||
end function openmc_mesh_set_id
|
||||
|
||||
|
||||
function openmc_mesh_get_dimension(index, dims, n) result(err) bind(C)
|
||||
! Get the dimension of a mesh
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
type(C_PTR), intent(out) :: dims
|
||||
integer(C_INT), intent(out) :: n
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= n_meshes) then
|
||||
dims = C_LOC(meshes(index) % dimension)
|
||||
n = meshes(index) % n_dimension
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in meshes array is out of bounds.")
|
||||
end if
|
||||
end function openmc_mesh_get_dimension
|
||||
|
||||
|
||||
function openmc_mesh_set_dimension(index, n, dims) result(err) bind(C)
|
||||
! Set the dimension of a mesh
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: n
|
||||
integer(C_INT), intent(in) :: dims(n)
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= n_meshes) then
|
||||
associate (m => meshes(index))
|
||||
if (allocated(m % dimension)) deallocate (m % dimension)
|
||||
if (allocated(m % lower_left)) deallocate (m % lower_left)
|
||||
if (allocated(m % upper_right)) deallocate (m % upper_right)
|
||||
if (allocated(m % width)) deallocate (m % width)
|
||||
|
||||
m % n_dimension = n
|
||||
allocate(m % dimension(n))
|
||||
allocate(m % lower_left(n))
|
||||
allocate(m % upper_right(n))
|
||||
allocate(m % width(n))
|
||||
|
||||
! Copy dimension
|
||||
m % dimension(:) = dims
|
||||
end associate
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in meshes array is out of bounds.")
|
||||
end if
|
||||
end function openmc_mesh_set_dimension
|
||||
|
||||
|
||||
function openmc_mesh_get_params(index, ll, ur, width, n) result(err) bind(C)
|
||||
! Get the mesh parameters
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
type(C_PTR), intent(out) :: ll
|
||||
type(C_PTR), intent(out) :: ur
|
||||
type(C_PTR), intent(out) :: width
|
||||
integer(C_INT), intent(out) :: n
|
||||
integer(C_INT) :: err
|
||||
|
||||
err = 0
|
||||
if (index >= 1 .and. index <= n_meshes) then
|
||||
associate (m => meshes(index))
|
||||
if (allocated(m % lower_left)) then
|
||||
ll = C_LOC(m % lower_left(1))
|
||||
ur = C_LOC(m % upper_right(1))
|
||||
width = C_LOC(m % width(1))
|
||||
n = m % n_dimension
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Mesh parameters have not been set.")
|
||||
end if
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in meshes array is out of bounds.")
|
||||
end if
|
||||
end function openmc_mesh_get_params
|
||||
|
||||
|
||||
function openmc_mesh_set_params(index, n, ll, ur, width) result(err) bind(C)
|
||||
! Set the mesh parameters
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: n
|
||||
real(C_DOUBLE), intent(in), optional :: ll(n)
|
||||
real(C_DOUBLE), intent(in), optional :: ur(n)
|
||||
real(C_DOUBLE), intent(in), optional :: width(n)
|
||||
integer(C_INT) :: err
|
||||
|
||||
err = 0
|
||||
if (index >= 1 .and. index <= n_meshes) then
|
||||
associate (m => meshes(index))
|
||||
if (allocated(m % lower_left)) deallocate (m % lower_left)
|
||||
if (allocated(m % upper_right)) deallocate (m % upper_right)
|
||||
if (allocated(m % width)) deallocate (m % width)
|
||||
|
||||
allocate(m % lower_left(n))
|
||||
allocate(m % upper_right(n))
|
||||
allocate(m % width(n))
|
||||
|
||||
if (present(ll) .and. present(ur)) then
|
||||
m % lower_left(:) = ll
|
||||
m % upper_right(:) = ur
|
||||
m % width(:) = (ur - ll) / m % dimension
|
||||
elseif (present(ll) .and. present(width)) then
|
||||
m % lower_left(:) = ll
|
||||
m % width(:) = width
|
||||
m % upper_right(:) = ll + width * m % dimension
|
||||
elseif (present(ur) .and. present(width)) then
|
||||
m % upper_right(:) = ur
|
||||
m % width(:) = width
|
||||
m % lower_left(:) = ur - width * m % dimension
|
||||
else
|
||||
err = E_INVALID_ARGUMENT
|
||||
call set_errmsg("At least two parameters must be specified.")
|
||||
end if
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in meshes array is out of bounds.")
|
||||
end if
|
||||
end function openmc_mesh_set_params
|
||||
|
||||
end module mesh_header
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace mpi {
|
|||
|
||||
int rank {0};
|
||||
int n_procs {1};
|
||||
bool master {true};
|
||||
|
||||
#ifdef OPENMC_MPI
|
||||
MPI_Comm intracomm;
|
||||
|
|
|
|||
172
src/mgxs.cpp
172
src/mgxs.cpp
|
|
@ -3,12 +3,17 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <valarray>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "xtensor/xmath.hpp"
|
||||
#include "xtensor/xsort.hpp"
|
||||
#include "xtensor/xadapt.hpp"
|
||||
#include "xtensor/xview.hpp"
|
||||
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/math_functions.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
|
|
@ -28,14 +33,15 @@ std::vector<Mgxs> macro_xs;
|
|||
|
||||
void
|
||||
Mgxs::init(const std::string& in_name, double in_awr,
|
||||
const double_1dvec& in_kTs, bool in_fissionable, int in_scatter_format,
|
||||
const std::vector<double>& in_kTs, bool in_fissionable, int in_scatter_format,
|
||||
int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic,
|
||||
const double_1dvec& in_polar, const double_1dvec& in_azimuthal)
|
||||
const std::vector<double>& in_polar, const std::vector<double>& in_azimuthal)
|
||||
{
|
||||
// Set the metadata
|
||||
name = in_name;
|
||||
awr = in_awr;
|
||||
kTs = in_kTs;
|
||||
//TODO: Remove adapt when in_KTs is an xtensor
|
||||
kTs = xt::adapt(in_kTs);
|
||||
fissionable = in_fissionable;
|
||||
scatter_format = in_scatter_format;
|
||||
num_groups = in_num_groups;
|
||||
|
|
@ -61,8 +67,8 @@ Mgxs::init(const std::string& in_name, double in_awr,
|
|||
|
||||
void
|
||||
Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
||||
int in_num_delayed_groups, const double_1dvec& temperature,
|
||||
double tolerance, int_1dvec& temps_to_read, int& order_dim, int& method)
|
||||
int in_num_delayed_groups, const std::vector<double>& temperature,
|
||||
double tolerance, std::vector<int>& temps_to_read, int& order_dim, int& method)
|
||||
{
|
||||
// get name
|
||||
char char_name[MAX_WORD_LEN];
|
||||
|
|
@ -87,7 +93,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
|||
dset_names[i] = new char[151];
|
||||
}
|
||||
get_datasets(kT_group, dset_names);
|
||||
double_1dvec available_temps(num_temps);
|
||||
xt::xarray<double> available_temps(num_temps);
|
||||
for (int i = 0; i < num_temps; i++) {
|
||||
read_double(kT_group, dset_names[i], &available_temps[i], true);
|
||||
|
||||
|
|
@ -110,24 +116,20 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
|||
|
||||
switch(method) {
|
||||
case TEMPERATURE_NEAREST:
|
||||
// Find the minimum difference
|
||||
for (int i = 0; i < temperature.size(); i++) {
|
||||
std::valarray<double> temp_diff(available_temps.data(),
|
||||
available_temps.size());
|
||||
temp_diff = std::abs(temp_diff - temperature[i]);
|
||||
int i_closest = std::min_element(std::begin(temp_diff), std::end(temp_diff)) -
|
||||
std::begin(temp_diff);
|
||||
// Determine actual temperatures to read
|
||||
for (const auto& T : temperature) {
|
||||
auto i_closest = xt::argmin(xt::abs(available_temps - T))[0];
|
||||
double temp_actual = available_temps[i_closest];
|
||||
|
||||
if (std::abs(temp_actual - temperature[i]) < tolerance) {
|
||||
if (std::find(temps_to_read.begin(), temps_to_read.end(),
|
||||
std::round(temp_actual)) == temps_to_read.end()) {
|
||||
if (std::fabs(temp_actual - T) < tolerance) {
|
||||
if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual))
|
||||
== temps_to_read.end()) {
|
||||
temps_to_read.push_back(std::round(temp_actual));
|
||||
} else {
|
||||
fatal_error("MGXS Library does not contain cross section for " +
|
||||
in_name + " at or near " +
|
||||
std::to_string(std::round(temperature[i])) + " K.");
|
||||
}
|
||||
} else {
|
||||
std::stringstream msg;
|
||||
msg << "MGXS library does not contain cross sections for "
|
||||
<< in_name << " at or near " << std::round(T) << " K.";
|
||||
fatal_error(msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -160,7 +162,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
|||
|
||||
// Get the library's temperatures
|
||||
int n_temperature = temps_to_read.size();
|
||||
double_1dvec in_kTs(n_temperature);
|
||||
std::vector<double> in_kTs(n_temperature);
|
||||
for (int i = 0; i < n_temperature; i++) {
|
||||
std::string temp_str(std::to_string(temps_to_read[i]) + "K");
|
||||
|
||||
|
|
@ -254,12 +256,12 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
|||
}
|
||||
|
||||
// Set the angular bins to use equally-spaced bins
|
||||
double_1dvec in_polar(in_n_pol);
|
||||
std::vector<double> in_polar(in_n_pol);
|
||||
double dangle = PI / in_n_pol;
|
||||
for (int p = 0; p < in_n_pol; p++) {
|
||||
in_polar[p] = (p + 0.5) * dangle;
|
||||
}
|
||||
double_1dvec in_azimuthal(in_n_azi);
|
||||
std::vector<double> in_azimuthal(in_n_azi);
|
||||
dangle = 2. * PI / in_n_azi;
|
||||
for (int a = 0; a < in_n_azi; a++) {
|
||||
in_azimuthal[a] = (a + 0.5) * dangle - PI;
|
||||
|
|
@ -274,12 +276,12 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
|||
//==============================================================================
|
||||
|
||||
Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups,
|
||||
const double_1dvec& temperature, double tolerance, int max_order,
|
||||
const std::vector<double>& temperature, double tolerance, int max_order,
|
||||
bool legendre_to_tabular, int legendre_to_tabular_points, int& method)
|
||||
{
|
||||
// Call generic data gathering routine (will populate the metadata)
|
||||
int order_data;
|
||||
int_1dvec temps_to_read;
|
||||
std::vector<int> temps_to_read;
|
||||
metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature,
|
||||
tolerance, temps_to_read, order_data, method);
|
||||
|
||||
|
|
@ -310,8 +312,8 @@ Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups,
|
|||
|
||||
//==============================================================================
|
||||
|
||||
Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
||||
const std::vector<Mgxs*>& micros, const double_1dvec& atom_densities,
|
||||
Mgxs::Mgxs(const std::string& in_name, const std::vector<double>& mat_kTs,
|
||||
const std::vector<Mgxs*>& micros, const std::vector<double>& atom_densities,
|
||||
double tolerance, int& method)
|
||||
{
|
||||
// Get the minimum data needed to initialize:
|
||||
|
|
@ -328,8 +330,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
|||
int in_num_groups = micros[0]->num_groups;
|
||||
int in_num_delayed_groups = micros[0]->num_delayed_groups;
|
||||
bool in_is_isotropic = micros[0]->is_isotropic;
|
||||
double_1dvec in_polar = micros[0]->polar;
|
||||
double_1dvec in_azimuthal = micros[0]->azimuthal;
|
||||
std::vector<double> in_polar = micros[0]->polar;
|
||||
std::vector<double> in_azimuthal = micros[0]->azimuthal;
|
||||
|
||||
init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format,
|
||||
in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar,
|
||||
|
|
@ -345,33 +347,27 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
|||
|
||||
// Create the list of temperature indices and interpolation factors for
|
||||
// each microscopic data at the material temperature
|
||||
int_1dvec micro_t(micros.size(), 0);
|
||||
double_1dvec micro_t_interp(micros.size(), 0.);
|
||||
std::vector<int> micro_t(micros.size(), 0);
|
||||
std::vector<double> micro_t_interp(micros.size(), 0.);
|
||||
for (int m = 0; m < micros.size(); m++) {
|
||||
switch(method) {
|
||||
case TEMPERATURE_NEAREST:
|
||||
{
|
||||
// Find the nearest temperature
|
||||
std::valarray<double> temp_diff(micros[m]->kTs.data(),
|
||||
micros[m]->kTs.size());
|
||||
temp_diff = std::abs(temp_diff - temp_desired);
|
||||
micro_t[m] = std::min_element(std::begin(temp_diff),
|
||||
std::end(temp_diff)) -
|
||||
std::begin(temp_diff);
|
||||
double temp_actual = micros[m]->kTs[micro_t[m]];
|
||||
micro_t[m] = xt::argmin(xt::abs(micros[m]->kTs - temp_desired))[0];
|
||||
auto temp_actual = micros[m]->kTs[micro_t[m]];
|
||||
|
||||
if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) {
|
||||
fatal_error("MGXS Library does not contain cross section for " +
|
||||
name + " at or near " +
|
||||
std::to_string(std::round(temp_desired / K_BOLTZMANN))
|
||||
+ " K.");
|
||||
std::stringstream msg;
|
||||
msg << "MGXS Library does not contain cross section for " << name
|
||||
<< " at or near " << std::round(temp_desired / K_BOLTZMANN) << "K.";
|
||||
fatal_error(msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEMPERATURE_INTERPOLATION:
|
||||
// Get a list of bounding temperatures for each actual temperature
|
||||
// present in the model
|
||||
for (int k = 0; k < micros[m]->kTs.size() - 1; k++) {
|
||||
for (int k = 0; k < micros[m]->kTs.shape()[0] - 1; k++) {
|
||||
if ((micros[m]->kTs[k] <= temp_desired) &&
|
||||
(temp_desired < micros[m]->kTs[k + 1])) {
|
||||
micro_t[m] = k;
|
||||
|
|
@ -394,8 +390,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
|||
int num_interp_points = 2;
|
||||
if (method == TEMPERATURE_NEAREST) num_interp_points = 1;
|
||||
for (int interp_point = 0; interp_point < num_interp_points; interp_point++) {
|
||||
double_1dvec interp(micros.size());
|
||||
double_1dvec temp_indices(micros.size());
|
||||
std::vector<double> interp(micros.size());
|
||||
std::vector<double> temp_indices(micros.size());
|
||||
for (int m = 0; m < micros.size(); m++) {
|
||||
interp[m] = (1. - micro_t_interp[m]) * atom_densities[m];
|
||||
temp_indices[m] = micro_t[m] + interp_point;
|
||||
|
|
@ -409,8 +405,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::combine(const std::vector<Mgxs*>& micros, const double_1dvec& scalars,
|
||||
const int_1dvec& micro_ts, int this_t)
|
||||
Mgxs::combine(const std::vector<Mgxs*>& micros, const std::vector<double>& scalars,
|
||||
const std::vector<int>& micro_ts, int this_t)
|
||||
{
|
||||
// Build the vector of pointers to the xs objects within micros
|
||||
std::vector<XsData*> those_xs(micros.size());
|
||||
|
|
@ -441,19 +437,19 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg)
|
|||
double val;
|
||||
switch(xstype) {
|
||||
case MG_GET_XS_TOTAL:
|
||||
val = xs_t->total[a][gin];
|
||||
val = xs_t->total(a, gin);
|
||||
break;
|
||||
case MG_GET_XS_NU_FISSION:
|
||||
val = fissionable ? xs_t->nu_fission[a][gin] : 0.;
|
||||
val = fissionable ? xs_t->nu_fission(a, gin) : 0.;
|
||||
break;
|
||||
case MG_GET_XS_ABSORPTION:
|
||||
val = xs_t->absorption[a][gin];
|
||||
val = xs_t->absorption(a, gin);;
|
||||
break;
|
||||
case MG_GET_XS_FISSION:
|
||||
val = fissionable ? xs_t->fission[a][gin] : 0.;
|
||||
val = fissionable ? xs_t->fission(a, gin) : 0.;
|
||||
break;
|
||||
case MG_GET_XS_KAPPA_FISSION:
|
||||
val = fissionable ? xs_t->kappa_fission[a][gin] : 0.;
|
||||
val = fissionable ? xs_t->kappa_fission(a, gin) : 0.;
|
||||
break;
|
||||
case MG_GET_XS_SCATTER:
|
||||
case MG_GET_XS_SCATTER_MULT:
|
||||
|
|
@ -462,16 +458,16 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg)
|
|||
val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu);
|
||||
break;
|
||||
case MG_GET_XS_PROMPT_NU_FISSION:
|
||||
val = fissionable ? xs_t->prompt_nu_fission[a][gin] : 0.;
|
||||
val = fissionable ? xs_t->prompt_nu_fission(a, gin) : 0.;
|
||||
break;
|
||||
case MG_GET_XS_DELAYED_NU_FISSION:
|
||||
if (fissionable) {
|
||||
if (dg != nullptr) {
|
||||
val = xs_t->delayed_nu_fission[a][gin][*dg];
|
||||
val = xs_t->delayed_nu_fission(a, *dg, gin);
|
||||
} else {
|
||||
val = 0.;
|
||||
for (auto& num : xs_t->delayed_nu_fission[a][gin]) {
|
||||
val += num;
|
||||
for (int d = 0; d < xs_t->delayed_nu_fission.shape()[2]; d++) {
|
||||
val += xs_t->delayed_nu_fission(a, d, gin);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -481,12 +477,12 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg)
|
|||
case MG_GET_XS_CHI_PROMPT:
|
||||
if (fissionable) {
|
||||
if (gout != nullptr) {
|
||||
val = xs_t->chi_prompt[a][gin][*gout];
|
||||
val = xs_t->chi_prompt(a, gin, *gout);
|
||||
} else {
|
||||
// provide an outgoing group-wise sum
|
||||
val = 0.;
|
||||
for (auto& num : xs_t->chi_prompt[a][gin]) {
|
||||
val += num;
|
||||
for (int g = 0; g < xs_t->chi_prompt.shape()[2]; g++) {
|
||||
val += xs_t->chi_prompt(a, gin, g);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -497,21 +493,21 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg)
|
|||
if (fissionable) {
|
||||
if (gout != nullptr) {
|
||||
if (dg != nullptr) {
|
||||
val = xs_t->chi_delayed[a][gin][*gout][*dg];
|
||||
val = xs_t->chi_delayed(a, *dg, gin, *gout);
|
||||
} else {
|
||||
val = xs_t->chi_delayed[a][gin][*gout][0];
|
||||
val = xs_t->chi_delayed(a, 0, gin, *gout);
|
||||
}
|
||||
} else {
|
||||
if (dg != nullptr) {
|
||||
val = 0.;
|
||||
for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) {
|
||||
val += xs_t->chi_delayed[a][gin][i][*dg];
|
||||
for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) {
|
||||
val += xs_t->delayed_nu_fission(a, *dg, gin, g);
|
||||
}
|
||||
} else {
|
||||
val = 0.;
|
||||
for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) {
|
||||
for (auto& num : xs_t->chi_delayed[a][gin][i]) {
|
||||
val += num;
|
||||
for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) {
|
||||
for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) {
|
||||
val += xs_t->delayed_nu_fission(a, d, gin, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -521,13 +517,13 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg)
|
|||
}
|
||||
break;
|
||||
case MG_GET_XS_INVERSE_VELOCITY:
|
||||
val = xs_t->inverse_velocity[a][gin];
|
||||
val = xs_t->inverse_velocity(a, gin);
|
||||
break;
|
||||
case MG_GET_XS_DECAY_RATE:
|
||||
if (dg != nullptr) {
|
||||
val = xs_t->decay_rate[a][*dg + 1];
|
||||
val = xs_t->decay_rate(a, *dg + 1);
|
||||
} else {
|
||||
val = xs_t->decay_rate[a][0];
|
||||
val = xs_t->decay_rate(a, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -548,11 +544,11 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout)
|
|||
int tid = 0;
|
||||
#endif
|
||||
XsData* xs_t = &xs[cache[tid].t];
|
||||
double nu_fission = xs_t->nu_fission[cache[tid].a][gin];
|
||||
double nu_fission = xs_t->nu_fission(cache[tid].a, gin);
|
||||
|
||||
// Find the probability of having a prompt neutron
|
||||
double prob_prompt =
|
||||
xs_t->prompt_nu_fission[cache[tid].a][gin];
|
||||
xs_t->prompt_nu_fission(cache[tid].a, gin);
|
||||
|
||||
// sample random numbers
|
||||
double xi_pd = prn() * nu_fission;
|
||||
|
|
@ -568,10 +564,10 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout)
|
|||
// sample the outgoing energy group
|
||||
gout = 0;
|
||||
double prob_gout =
|
||||
xs_t->chi_prompt[cache[tid].a][gin][gout];
|
||||
xs_t->chi_prompt(cache[tid].a, gin, gout);
|
||||
while (prob_gout < xi_gout) {
|
||||
gout++;
|
||||
prob_gout += xs_t->chi_prompt[cache[tid].a][gin][gout];
|
||||
prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -582,7 +578,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout)
|
|||
while (xi_pd >= prob_prompt) {
|
||||
dg++;
|
||||
prob_prompt +=
|
||||
xs_t->delayed_nu_fission[cache[tid].a][gin][dg];
|
||||
xs_t->delayed_nu_fission(cache[tid].a, dg, gin);
|
||||
}
|
||||
|
||||
// adjust dg in case of round-off error
|
||||
|
|
@ -591,11 +587,11 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout)
|
|||
// sample the outgoing energy group
|
||||
gout = 0;
|
||||
double prob_gout =
|
||||
xs_t->chi_delayed[cache[tid].a][gin][gout][dg];
|
||||
xs_t->chi_delayed(cache[tid].a, dg, gin, gout);
|
||||
while (prob_gout < xi_gout) {
|
||||
gout++;
|
||||
prob_gout +=
|
||||
xs_t->chi_delayed[cache[tid].a][gin][gout][dg];
|
||||
xs_t->chi_delayed(cache[tid].a, dg, gin, gout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -630,10 +626,10 @@ Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3],
|
|||
set_temperature_index(sqrtkT);
|
||||
set_angle_index(uvw);
|
||||
XsData* xs_t = &xs[cache[tid].t];
|
||||
total_xs = xs_t->total[cache[tid].a][gin];
|
||||
abs_xs = xs_t->absorption[cache[tid].a][gin];
|
||||
total_xs = xs_t->total(cache[tid].a, gin);
|
||||
abs_xs = xs_t->absorption(cache[tid].a, gin);
|
||||
|
||||
nu_fiss_xs = fissionable ? xs_t->nu_fission[cache[tid].a][gin] : 0.;
|
||||
nu_fiss_xs = fissionable ? xs_t->nu_fission(cache[tid].a, gin) : 0.;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -662,17 +658,7 @@ Mgxs::set_temperature_index(double sqrtkT)
|
|||
int tid = 0;
|
||||
#endif
|
||||
if (sqrtkT != cache[tid].sqrtkT) {
|
||||
double kT = sqrtkT * sqrtkT;
|
||||
|
||||
// initialize vector for storage of the differences
|
||||
std::valarray<double> temp_diff(kTs.data(), kTs.size());
|
||||
|
||||
// Find the minimum difference of kT and kTs
|
||||
temp_diff = std::abs(temp_diff - kT);
|
||||
cache[tid].t = std::min_element(std::begin(temp_diff), std::end(temp_diff)) -
|
||||
std::begin(temp_diff);
|
||||
|
||||
// store this temperature as the last one used
|
||||
cache[tid].t = xt::argmin(xt::abs(kTs - sqrtkT * sqrtkT))[0];
|
||||
cache[tid].sqrtkT = sqrtkT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ add_mgxs_c(hid_t file_id, const char* name, int energy_groups,
|
|||
int& method)
|
||||
{
|
||||
// Convert temps to a vector for the from_hdf5 function
|
||||
double_1dvec temperature(temps, temps + n_temps);
|
||||
std::vector<double> temperature(temps, temps + n_temps);
|
||||
|
||||
write_message("Loading " + std::string(name) + " data...", 6);
|
||||
|
||||
|
|
@ -60,10 +60,10 @@ create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[],
|
|||
{
|
||||
if (n_temps > 0) {
|
||||
// // Convert temps to a vector
|
||||
double_1dvec temperature(temps, temps + n_temps);
|
||||
std::vector<double> temperature(temps, temps + n_temps);
|
||||
|
||||
// Convert atom_densities to a vector
|
||||
double_1dvec atom_densities_vec(atom_densities,
|
||||
std::vector<double> atom_densities_vec(atom_densities,
|
||||
atom_densities + n_nuclides);
|
||||
|
||||
// Build array of pointers to nuclides_MG's Mgxs objects needed for this
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
module multipole_header
|
||||
|
||||
use constants
|
||||
use dict_header, only: DictIntInt
|
||||
use error, only: fatal_error
|
||||
use hdf5_interface
|
||||
|
||||
|
|
@ -74,12 +73,11 @@ contains
|
|||
character(len=*), intent(in) :: filename
|
||||
|
||||
character(len=10) :: version
|
||||
integer :: i, n_poles, n_residues, n_windows
|
||||
integer :: n_poles, n_residues, n_windows
|
||||
integer(HSIZE_T) :: dims_1d(1), dims_2d(2), dims_3d(3)
|
||||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: group_id
|
||||
integer(HID_T) :: dset
|
||||
type(DictIntInt) :: l_val_dict
|
||||
|
||||
! Open file for reading and move into the /isotope group
|
||||
file_id = file_open(filename, 'r', parallel=.true.)
|
||||
|
|
|
|||
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
|
||||
|
|
@ -600,7 +600,6 @@ contains
|
|||
|
||||
integer :: i, j, k, l
|
||||
integer :: t
|
||||
integer :: m
|
||||
integer :: n
|
||||
integer :: n_grid
|
||||
integer :: i_fission
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ module output
|
|||
use error, only: fatal_error, warning
|
||||
use geometry_header
|
||||
use math, only: t_percentile
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use message_passing, only: master, n_procs
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
|
|
@ -34,6 +33,14 @@ module output
|
|||
integer :: ou = OUTPUT_UNIT
|
||||
integer :: eu = ERROR_UNIT
|
||||
|
||||
interface
|
||||
function entropy(i) result(h) bind(C, name='entropy_c')
|
||||
import C_INT, C_DOUBLE
|
||||
integer(C_INT), value :: i
|
||||
real(C_DOUBLE) :: h
|
||||
end function
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -41,7 +48,7 @@ contains
|
|||
! developers, version, and date/time which the problem was run.
|
||||
!===============================================================================
|
||||
|
||||
subroutine title()
|
||||
subroutine title() bind(C)
|
||||
|
||||
#ifdef _OPENMP
|
||||
use omp_lib
|
||||
|
|
@ -211,7 +218,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 +238,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(&
|
||||
|
|
@ -337,7 +343,7 @@ contains
|
|||
|
||||
! write out entropy info
|
||||
if (entropy_on) write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5)', ADVANCE='NO') &
|
||||
entropy % data(i)
|
||||
entropy(i)
|
||||
|
||||
if (n > 1) then
|
||||
write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5," +/-",F8.5)', ADVANCE='NO') &
|
||||
|
|
@ -371,7 +377,7 @@ contains
|
|||
|
||||
! write out entropy info
|
||||
if (entropy_on) write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5)', ADVANCE='NO') &
|
||||
entropy % data(i)
|
||||
entropy(i)
|
||||
|
||||
! write out accumulated k-effective if after first active batch
|
||||
if (n > 1) then
|
||||
|
|
@ -622,42 +628,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 (settings::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;
|
||||
|
|
@ -130,7 +130,7 @@ Particle::mark_as_lost(const char* message)
|
|||
openmc_n_lost_particles += 1;
|
||||
|
||||
// Count the total number of simulated particles (on this processor)
|
||||
auto n = openmc_current_batch * gen_per_batch * openmc_work;
|
||||
auto n = openmc_current_batch * settings::gen_per_batch * openmc_work;
|
||||
|
||||
// Abort the simulation if the maximum number of lost particles has been
|
||||
// reached
|
||||
|
|
@ -141,14 +141,15 @@ Particle::mark_as_lost(const char* message)
|
|||
}
|
||||
|
||||
void
|
||||
Particle::write_restart()
|
||||
Particle::write_restart() const
|
||||
{
|
||||
// Dont write another restart file if in particle restart mode
|
||||
if (openmc_run_mode == RUN_MODE_PARTICLE) return;
|
||||
if (settings::run_mode == RUN_MODE_PARTICLE) return;
|
||||
|
||||
// Set up file name
|
||||
std::stringstream filename;
|
||||
filename << path_output << "particle_" << openmc_current_batch << '_' << id << ".h5";
|
||||
filename << settings::path_output << "particle_" << openmc_current_batch
|
||||
<< '_' << id << ".h5";
|
||||
|
||||
#pragma omp critical (WriteParticleRestart)
|
||||
{
|
||||
|
|
@ -165,10 +166,10 @@ Particle::write_restart()
|
|||
|
||||
// Write data to file
|
||||
write_dataset(file_id, "current_batch", openmc_current_batch);
|
||||
write_dataset(file_id, "generations_per_batch", gen_per_batch);
|
||||
write_dataset(file_id, "generations_per_batch", settings::gen_per_batch);
|
||||
write_dataset(file_id, "current_generation", openmc_current_gen);
|
||||
write_dataset(file_id, "n_particles", n_particles);
|
||||
switch (openmc_run_mode) {
|
||||
write_dataset(file_id, "n_particles", settings::n_particles);
|
||||
switch (settings::run_mode) {
|
||||
case RUN_MODE_FIXEDSOURCE:
|
||||
write_dataset(file_id, "run_mode", "fixed source");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ module physics
|
|||
use error, only: fatal_error, warning, write_message
|
||||
use material_header, only: Material, materials
|
||||
use math
|
||||
use mesh_header, only: meshes
|
||||
use message_passing
|
||||
use nuclide_header
|
||||
use particle_header
|
||||
|
|
@ -1182,11 +1181,18 @@ contains
|
|||
integer :: nu_d(MAX_DELAYED_GROUPS) ! number of delayed neutrons born
|
||||
integer :: i ! loop index
|
||||
integer :: nu ! actual number of neutrons produced
|
||||
integer :: mesh_bin ! mesh bin for source site
|
||||
real(8) :: nu_t ! total nu
|
||||
real(8) :: weight ! weight adjustment for ufs method
|
||||
type(Nuclide), pointer :: nuc
|
||||
|
||||
interface
|
||||
function ufs_get_weight(p) result(weight) bind(C)
|
||||
import Particle, C_DOUBLE
|
||||
type(Particle), intent(in) :: p
|
||||
real(C_DOUBLE) :: WEIGHT
|
||||
end function
|
||||
end interface
|
||||
|
||||
! Get pointers
|
||||
nuc => nuclides(i_nuclide)
|
||||
|
||||
|
|
@ -1196,20 +1202,7 @@ contains
|
|||
! the expected number of fission sites produced
|
||||
|
||||
if (ufs) then
|
||||
associate (m => meshes(index_ufs_mesh))
|
||||
! Determine indices on ufs mesh for current location
|
||||
call m % get_bin(p % coord(1) % xyz, mesh_bin)
|
||||
if (mesh_bin == NO_BIN_FOUND) then
|
||||
call particle_write_restart(p)
|
||||
call fatal_error("Source site outside UFS mesh!")
|
||||
end if
|
||||
|
||||
if (source_frac(1, mesh_bin) /= ZERO) then
|
||||
weight = m % volume_frac / source_frac(1, mesh_bin)
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
end associate
|
||||
weight = ufs_get_weight(p)
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ module physics_mg
|
|||
use error, only: fatal_error, warning, write_message
|
||||
use material_header, only: Material, materials
|
||||
use math, only: rotate_angle
|
||||
use mesh_header, only: meshes
|
||||
use mgxs_interface
|
||||
use message_passing
|
||||
use nuclide_header, only: material_xs
|
||||
|
|
@ -168,33 +167,26 @@ contains
|
|||
integer :: dg ! delayed group
|
||||
integer :: gout ! group out
|
||||
integer :: nu ! actual number of neutrons produced
|
||||
integer :: mesh_bin ! mesh bin for source site
|
||||
real(8) :: nu_t ! total nu
|
||||
real(8) :: mu ! fission neutron angular cosine
|
||||
real(8) :: phi ! fission neutron azimuthal angle
|
||||
real(8) :: weight ! weight adjustment for ufs method
|
||||
|
||||
interface
|
||||
function ufs_get_weight(p) result(weight) bind(C)
|
||||
import Particle, C_DOUBLE
|
||||
type(Particle), intent(in) :: p
|
||||
real(C_DOUBLE) :: WEIGHT
|
||||
end function
|
||||
end interface
|
||||
|
||||
! TODO: Heat generation from fission
|
||||
|
||||
! If uniform fission source weighting is turned on, we increase of decrease
|
||||
! the expected number of fission sites produced
|
||||
|
||||
if (ufs) then
|
||||
associate (m => meshes(index_ufs_mesh))
|
||||
! Determine indices on ufs mesh for current location
|
||||
call m % get_bin(p % coord(1) % xyz, mesh_bin)
|
||||
|
||||
if (mesh_bin == NO_BIN_FOUND) then
|
||||
call particle_write_restart(p)
|
||||
call fatal_error("Source site outside UFS mesh!")
|
||||
end if
|
||||
|
||||
if (source_frac(1, mesh_bin) /= ZERO) then
|
||||
weight = m % volume_frac / source_frac(1, mesh_bin)
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
end associate
|
||||
weight = ufs_get_weight(p)
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
|
|
|
|||
91
src/plot.F90
91
src/plot.F90
|
|
@ -9,6 +9,7 @@ module plot
|
|||
use hdf5_interface
|
||||
use output, only: time_stamp
|
||||
use material_header, only: materials
|
||||
use mesh_header, only: meshes, RegularMesh
|
||||
use particle_header
|
||||
use plot_header
|
||||
use progress_header, only: ProgressBar
|
||||
|
|
@ -84,7 +85,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 +101,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
|
||||
|
|
@ -184,7 +185,7 @@ contains
|
|||
!$omp end parallel do
|
||||
|
||||
! Draw tally mesh boundaries on the image if requested
|
||||
if (associated(pl % meshlines_mesh)) call draw_mesh_lines(pl, data)
|
||||
if (pl % index_meshlines_mesh >= 0) call draw_mesh_lines(pl, data)
|
||||
|
||||
! Write out the ppm to a file
|
||||
call output_ppm(pl, data)
|
||||
|
|
@ -214,6 +215,7 @@ contains
|
|||
real(8) :: xyz_ur_plot(3) ! upper right xyz of plot image
|
||||
real(8) :: xyz_ll(3) ! lower left xyz
|
||||
real(8) :: xyz_ur(3) ! upper right xyz
|
||||
type(RegularMesh) :: m
|
||||
|
||||
rgb(:) = pl % meshlines_color % rgb
|
||||
|
||||
|
|
@ -239,57 +241,56 @@ contains
|
|||
|
||||
width = xyz_ur_plot - xyz_ll_plot
|
||||
|
||||
associate (m => pl % meshlines_mesh)
|
||||
call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh)
|
||||
call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh)
|
||||
m = meshes(pl % index_meshlines_mesh)
|
||||
call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension()), in_mesh)
|
||||
call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension()), in_mesh)
|
||||
|
||||
! sweep through all meshbins on this plane and draw borders
|
||||
do i = ijk_ll(outer), ijk_ur(outer)
|
||||
do j = ijk_ll(inner), ijk_ur(inner)
|
||||
! check if we're in the mesh for this ijk
|
||||
if (i > 0 .and. i <= m % dimension(outer) .and. &
|
||||
j > 0 .and. j <= m % dimension(inner)) then
|
||||
! sweep through all meshbins on this plane and draw borders
|
||||
do i = ijk_ll(outer), ijk_ur(outer)
|
||||
do j = ijk_ll(inner), ijk_ur(inner)
|
||||
! check if we're in the mesh for this ijk
|
||||
if (i > 0 .and. i <= m % dimension(outer) .and. &
|
||||
j > 0 .and. j <= m % dimension(inner)) then
|
||||
|
||||
! get xyz's of lower left and upper right of this mesh cell
|
||||
xyz_ll(outer) = m % lower_left(outer) + m % width(outer) * (i - 1)
|
||||
xyz_ll(inner) = m % lower_left(inner) + m % width(inner) * (j - 1)
|
||||
xyz_ur(outer) = m % lower_left(outer) + m % width(outer) * i
|
||||
xyz_ur(inner) = m % lower_left(inner) + m % width(inner) * j
|
||||
! get xyz's of lower left and upper right of this mesh cell
|
||||
xyz_ll(outer) = m % lower_left(outer) + m % width(outer) * (i - 1)
|
||||
xyz_ll(inner) = m % lower_left(inner) + m % width(inner) * (j - 1)
|
||||
xyz_ur(outer) = m % lower_left(outer) + m % width(outer) * i
|
||||
xyz_ur(inner) = m % lower_left(inner) + m % width(inner) * j
|
||||
|
||||
! map the xyz ranges to pixel ranges
|
||||
! map the xyz ranges to pixel ranges
|
||||
|
||||
frac = (xyz_ll(outer) - xyz_ll_plot(outer)) / width(outer)
|
||||
outrange(1) = int(frac * real(pl % pixels(1), 8))
|
||||
frac = (xyz_ur(outer) - xyz_ll_plot(outer)) / width(outer)
|
||||
outrange(2) = int(frac * real(pl % pixels(1), 8))
|
||||
frac = (xyz_ll(outer) - xyz_ll_plot(outer)) / width(outer)
|
||||
outrange(1) = int(frac * real(pl % pixels(1), 8))
|
||||
frac = (xyz_ur(outer) - xyz_ll_plot(outer)) / width(outer)
|
||||
outrange(2) = int(frac * real(pl % pixels(1), 8))
|
||||
|
||||
frac = (xyz_ur(inner) - xyz_ll_plot(inner)) / width(inner)
|
||||
inrange(1) = int((ONE - frac) * real(pl % pixels(2), 8))
|
||||
frac = (xyz_ll(inner) - xyz_ll_plot(inner)) / width(inner)
|
||||
inrange(2) = int((ONE - frac) * real(pl % pixels(2), 8))
|
||||
frac = (xyz_ur(inner) - xyz_ll_plot(inner)) / width(inner)
|
||||
inrange(1) = int((ONE - frac) * real(pl % pixels(2), 8))
|
||||
frac = (xyz_ll(inner) - xyz_ll_plot(inner)) / width(inner)
|
||||
inrange(2) = int((ONE - frac) * real(pl % pixels(2), 8))
|
||||
|
||||
! draw lines
|
||||
do out_ = outrange(1), outrange(2)
|
||||
do plus = 0, pl % meshlines_width
|
||||
data(:, out_ + 1, inrange(1) + plus + 1) = rgb
|
||||
data(:, out_ + 1, inrange(2) + plus + 1) = rgb
|
||||
data(:, out_ + 1, inrange(1) - plus + 1) = rgb
|
||||
data(:, out_ + 1, inrange(2) - plus + 1) = rgb
|
||||
end do
|
||||
! draw lines
|
||||
do out_ = outrange(1), outrange(2)
|
||||
do plus = 0, pl % meshlines_width
|
||||
data(:, out_ + 1, inrange(1) + plus + 1) = rgb
|
||||
data(:, out_ + 1, inrange(2) + plus + 1) = rgb
|
||||
data(:, out_ + 1, inrange(1) - plus + 1) = rgb
|
||||
data(:, out_ + 1, inrange(2) - plus + 1) = rgb
|
||||
end do
|
||||
do in_ = inrange(1), inrange(2)
|
||||
do plus = 0, pl % meshlines_width
|
||||
data(:, outrange(1) + plus + 1, in_ + 1) = rgb
|
||||
data(:, outrange(2) + plus + 1, in_ + 1) = rgb
|
||||
data(:, outrange(1) - plus + 1, in_ + 1) = rgb
|
||||
data(:, outrange(2) - plus + 1, in_ + 1) = rgb
|
||||
end do
|
||||
end do
|
||||
do in_ = inrange(1), inrange(2)
|
||||
do plus = 0, pl % meshlines_width
|
||||
data(:, outrange(1) + plus + 1, in_ + 1) = rgb
|
||||
data(:, outrange(2) + plus + 1, in_ + 1) = rgb
|
||||
data(:, outrange(1) - plus + 1, in_ + 1) = rgb
|
||||
data(:, outrange(2) - plus + 1, in_ + 1) = rgb
|
||||
end do
|
||||
end do
|
||||
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
end do
|
||||
end associate
|
||||
end do
|
||||
|
||||
end subroutine draw_mesh_lines
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ module plot_header
|
|||
|
||||
use constants
|
||||
use dict_header, only: DictIntInt
|
||||
use mesh_header, only: RegularMesh
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ module plot_header
|
|||
integer :: pixels(3) ! pixel width/height of plot slice
|
||||
integer :: meshlines_width ! pixel width of meshlines
|
||||
integer :: level ! universe depth to plot the cells of
|
||||
type(RegularMesh), pointer :: meshlines_mesh => null() ! mesh to plot
|
||||
integer :: index_meshlines_mesh = -1 ! index of mesh to plot
|
||||
type(ObjectColor) :: meshlines_color ! Color for meshlines
|
||||
type(ObjectColor) :: not_found ! color for positions where no cell found
|
||||
type(ObjectColor), allocatable :: colors(:) ! colors of cells/mats
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include <numeric>
|
||||
#include <cmath>
|
||||
|
||||
#include "xtensor/xbuilder.hpp"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/math_functions.h"
|
||||
|
|
@ -16,11 +18,11 @@ namespace openmc {
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattData::base_init(int order, const int_1dvec& in_gmin,
|
||||
const int_1dvec& in_gmax, const double_2dvec& in_energy,
|
||||
ScattData::base_init(int order, const xt::xtensor<int, 1>& in_gmin,
|
||||
const xt::xtensor<int, 1>& in_gmax, const double_2dvec& in_energy,
|
||||
const double_2dvec& in_mult)
|
||||
{
|
||||
int groups = in_energy.size();
|
||||
size_t groups = in_energy.size();
|
||||
|
||||
gmin = in_gmin;
|
||||
gmax = in_gmax;
|
||||
|
|
@ -51,18 +53,17 @@ ScattData::base_init(int order, const int_1dvec& in_gmin,
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattData::base_combine(int max_order,
|
||||
const std::vector<ScattData*>& those_scatts, const double_1dvec& scalars,
|
||||
int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult,
|
||||
ScattData::base_combine(size_t max_order,
|
||||
const std::vector<ScattData*>& those_scatts, const std::vector<double>& scalars,
|
||||
xt::xtensor<int, 1>& in_gmin, xt::xtensor<int, 1>& in_gmax, double_2dvec& sparse_mult,
|
||||
double_3dvec& sparse_scatter)
|
||||
{
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
size_t groups = those_scatts[0] -> energy.size();
|
||||
|
||||
// Now allocate and zero our storage spaces
|
||||
double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(max_order, 0.)));
|
||||
double_2dvec mult_numer(groups, double_1dvec(groups, 0.));
|
||||
double_2dvec mult_denom(groups, double_1dvec(groups, 0.));
|
||||
xt::xtensor<double, 3> this_matrix({groups, groups, max_order}, 0.);
|
||||
xt::xtensor<double, 2> mult_numer({groups, groups}, 0.);
|
||||
xt::xtensor<double, 2> mult_denom({groups, groups}, 0.);
|
||||
|
||||
// Build the dense scattering and multiplicity matrices
|
||||
// Get the multiplicity_matrix
|
||||
|
|
@ -80,26 +81,26 @@ ScattData::base_combine(int max_order,
|
|||
ScattData* that = those_scatts[i];
|
||||
|
||||
// Build the dense matrix for that object
|
||||
double_3dvec that_matrix = that->get_matrix(max_order);
|
||||
xt::xtensor<double, 3> that_matrix = that->get_matrix(max_order);
|
||||
|
||||
// Now add that to this for the scattering and multiplicity
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
// Only spend time adding that's gmin to gmax data since the rest will
|
||||
// be zeros
|
||||
int i_gout = 0;
|
||||
for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) {
|
||||
for (int gout = that->gmin(gin); gout <= that->gmax(gin); gout++) {
|
||||
// Do the scattering matrix
|
||||
for (int l = 0; l < max_order; l++) {
|
||||
this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l];
|
||||
this_matrix(gin, gout, l) += scalars[i] * that_matrix(gin, gout, l);
|
||||
}
|
||||
|
||||
// Incorporate that's contribution to the multiplicity matrix data
|
||||
double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout];
|
||||
mult_numer[gin][gout] += scalars[i] * nuscatt;
|
||||
double nuscatt = that->scattxs(gin) * that->energy[gin][i_gout];
|
||||
mult_numer(gin, gout) += scalars[i] * nuscatt;
|
||||
if (that->mult[gin][i_gout] > 0.) {
|
||||
mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout];
|
||||
mult_denom(gin, gout) += scalars[i] * nuscatt / that->mult[gin][i_gout];
|
||||
} else {
|
||||
mult_denom[gin][gout] += scalars[i];
|
||||
mult_denom(gin, gout) += scalars[i];
|
||||
}
|
||||
i_gout++;
|
||||
}
|
||||
|
|
@ -107,16 +108,8 @@ ScattData::base_combine(int max_order,
|
|||
}
|
||||
|
||||
// Combine mult_numer and mult_denom into the combined multiplicity matrix
|
||||
double_2dvec this_mult(groups, double_1dvec(groups, 1.));
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int gout = 0; gout < groups; gout++) {
|
||||
if (mult_denom[gin][gout] > 0.) {
|
||||
this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout];
|
||||
}
|
||||
}
|
||||
}
|
||||
mult_numer.clear();
|
||||
mult_denom.clear();
|
||||
xt::xtensor<double, 2> this_mult({groups, groups}, 1.);
|
||||
this_mult = xt::nan_to_num(mult_numer / mult_denom);
|
||||
|
||||
// We have the data, now we need to convert to a jagged array and then use
|
||||
// the initialize function to store it on the object.
|
||||
|
|
@ -125,8 +118,8 @@ ScattData::base_combine(int max_order,
|
|||
int gmin_;
|
||||
for (gmin_ = 0; gmin_ < groups; gmin_++) {
|
||||
bool non_zero = false;
|
||||
for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) {
|
||||
if (this_matrix[gin][gmin_][l] != 0.) {
|
||||
for (int l = 0; l < this_matrix.shape()[2]; l++) {
|
||||
if (this_matrix(gin, gmin_, l) != 0.) {
|
||||
non_zero = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -136,8 +129,8 @@ ScattData::base_combine(int max_order,
|
|||
int gmax_;
|
||||
for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) {
|
||||
bool non_zero = false;
|
||||
for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) {
|
||||
if (this_matrix[gin][gmax_][l] != 0.) {
|
||||
for (int l = 0; l < this_matrix.shape()[2]; l++) {
|
||||
if (this_matrix(gin, gmax_, l) != 0.) {
|
||||
non_zero = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -160,8 +153,11 @@ ScattData::base_combine(int max_order,
|
|||
sparse_mult[gin].resize(gmax_ - gmin_ + 1);
|
||||
int i_gout = 0;
|
||||
for (int gout = gmin_; gout <= gmax_; gout++) {
|
||||
sparse_scatter[gin][i_gout] = this_matrix[gin][gout];
|
||||
sparse_mult[gin][i_gout] = this_mult[gin][gout];
|
||||
sparse_scatter[gin][i_gout].resize(this_matrix.shape()[2]);
|
||||
for (int l = 0; l < this_matrix.shape()[2]; l++) {
|
||||
sparse_scatter[gin][i_gout][l] = this_matrix(gin, gout, l);
|
||||
}
|
||||
sparse_mult[gin][i_gout] = this_mult(gin, gout);
|
||||
i_gout++;
|
||||
}
|
||||
}
|
||||
|
|
@ -241,21 +237,21 @@ ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu)
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs)
|
||||
ScattDataLegendre::init(const xt::xtensor<int, 1>& in_gmin,
|
||||
const xt::xtensor<int, 1>& in_gmax, const double_2dvec& in_mult,
|
||||
const double_3dvec& coeffs)
|
||||
{
|
||||
int groups = coeffs.size();
|
||||
int order = coeffs[0][0].size();
|
||||
size_t groups = coeffs.size();
|
||||
size_t order = coeffs[0][0].size();
|
||||
|
||||
// make a copy of coeffs that we can use to both extract data and normalize
|
||||
double_3dvec matrix = coeffs;
|
||||
|
||||
// Get the scattering cross section value by summing the un-normalized P0
|
||||
// coefficient in the variable matrix over all outgoing groups.
|
||||
scattxs.resize(groups);
|
||||
scattxs = xt::zeros<double>({groups});
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = in_gmax[gin] - in_gmin[gin] + 1;
|
||||
scattxs[gin] = 0.;
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
scattxs[gin] += matrix[gin][i_gout][0];
|
||||
}
|
||||
|
|
@ -301,7 +297,7 @@ ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
|||
void
|
||||
ScattDataLegendre::update_max_val()
|
||||
{
|
||||
int groups = max_val.size();
|
||||
size_t groups = max_val.size();
|
||||
// Step through the polynomial with fixed number of points to identify the
|
||||
// maximal value
|
||||
int Nmu = 1001;
|
||||
|
|
@ -384,25 +380,25 @@ ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt)
|
|||
|
||||
void
|
||||
ScattDataLegendre::combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars)
|
||||
const std::vector<double>& scalars)
|
||||
{
|
||||
// Find the max order in the data set and make sure we can combine the sets
|
||||
int max_order = 0;
|
||||
size_t max_order = 0;
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
// Lets also make sure these items are combineable
|
||||
ScattDataLegendre* that = dynamic_cast<ScattDataLegendre*>(those_scatts[i]);
|
||||
if (!that) {
|
||||
fatal_error("Cannot combine the ScattData objects!");
|
||||
}
|
||||
int that_order = that->get_order();
|
||||
size_t that_order = that->get_order();
|
||||
if (that_order > max_order) max_order = that_order;
|
||||
}
|
||||
max_order++; // Add one since this is a Legendre
|
||||
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
size_t groups = those_scatts[0] -> energy.size();
|
||||
|
||||
int_1dvec in_gmin(groups);
|
||||
int_1dvec in_gmax(groups);
|
||||
xt::xtensor<int, 1> in_gmin({groups}, 0);
|
||||
xt::xtensor<int, 1> in_gmax({groups}, 0);
|
||||
double_3dvec sparse_scatter(groups);
|
||||
double_2dvec sparse_mult(groups);
|
||||
|
||||
|
|
@ -418,20 +414,19 @@ ScattDataLegendre::combine(const std::vector<ScattData*>& those_scatts,
|
|||
|
||||
//==============================================================================
|
||||
|
||||
double_3dvec
|
||||
ScattDataLegendre::get_matrix(int max_order)
|
||||
xt::xtensor<double, 3>
|
||||
ScattDataLegendre::get_matrix(size_t max_order)
|
||||
{
|
||||
// Get the sizes and initialize the data to 0
|
||||
int groups = energy.size();
|
||||
int order_dim = max_order + 1;
|
||||
double_3dvec matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(order_dim, 0.)));
|
||||
size_t groups = energy.size();
|
||||
size_t order_dim = max_order + 1;
|
||||
xt::xtensor<double, 3> matrix({groups, groups, order_dim}, 0.);
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) {
|
||||
int gout = i_gout + gmin[gin];
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] *
|
||||
matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] *
|
||||
dist[gin][i_gout][l];
|
||||
}
|
||||
}
|
||||
|
|
@ -444,20 +439,20 @@ ScattDataLegendre::get_matrix(int max_order)
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs)
|
||||
ScattDataHistogram::init(const xt::xtensor<int, 1>& in_gmin,
|
||||
const xt::xtensor<int, 1>& in_gmax, const double_2dvec& in_mult,
|
||||
const double_3dvec& coeffs)
|
||||
{
|
||||
int groups = coeffs.size();
|
||||
int order = coeffs[0][0].size();
|
||||
size_t groups = coeffs.size();
|
||||
size_t order = coeffs[0][0].size();
|
||||
|
||||
// make a copy of coeffs that we can use to both extract data and normalize
|
||||
double_3dvec matrix = coeffs;
|
||||
|
||||
// Get the scattering cross section value by summing the distribution
|
||||
// over all the histogram bins in angle and outgoing energy groups
|
||||
scattxs.resize(groups);
|
||||
scattxs = xt::zeros<double>({groups});
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
scattxs[gin] = 0.;
|
||||
for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) {
|
||||
scattxs[gin] += std::accumulate(matrix[gin][i_gout].begin(),
|
||||
matrix[gin][i_gout].end(), 0.);
|
||||
|
|
@ -484,12 +479,8 @@ ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
|||
ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult);
|
||||
|
||||
// Build the angular distribution mu values
|
||||
mu = double_1dvec(order);
|
||||
mu = xt::linspace(-1., 1., order + 1);
|
||||
dmu = 2. / order;
|
||||
mu[0] = -1.;
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
mu[imu] = -1. + imu * dmu;
|
||||
}
|
||||
|
||||
// Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
fmu.resize(groups);
|
||||
|
|
@ -534,7 +525,7 @@ ScattDataHistogram::calc_f(int gin, int gout, double mu)
|
|||
int imu;
|
||||
if (mu == 1.) {
|
||||
// use size -2 to have the index one before the end
|
||||
imu = this->mu.size() - 2;
|
||||
imu = this->mu.shape()[0] - 2;
|
||||
} else {
|
||||
imu = std::floor((mu + 1.) / dmu + 1.) - 1;
|
||||
}
|
||||
|
|
@ -560,7 +551,6 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt)
|
|||
if (xi < dist[gin][i_gout][0]) {
|
||||
imu = 0;
|
||||
} else {
|
||||
// TODO lower_bound? + 1?
|
||||
imu = std::upper_bound(dist[gin][i_gout].begin(),
|
||||
dist[gin][i_gout].end(), xi) -
|
||||
dist[gin][i_gout].begin();
|
||||
|
|
@ -581,21 +571,20 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt)
|
|||
|
||||
//==============================================================================
|
||||
|
||||
double_3dvec
|
||||
ScattDataHistogram::get_matrix(int max_order)
|
||||
xt::xtensor<double, 3>
|
||||
ScattDataHistogram::get_matrix(size_t max_order)
|
||||
{
|
||||
// Get the sizes and initialize the data to 0
|
||||
int groups = energy.size();
|
||||
size_t groups = energy.size();
|
||||
// We ignore the requested order for Histogram and Tabular representations
|
||||
int order_dim = get_order();
|
||||
double_3dvec matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(order_dim, 0.)));
|
||||
size_t order_dim = get_order();
|
||||
xt::xtensor<double, 3> matrix({groups, groups, order_dim}, 0);
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) {
|
||||
int gout = i_gout + gmin[gin];
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] *
|
||||
matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] *
|
||||
fmu[gin][i_gout][l];
|
||||
}
|
||||
}
|
||||
|
|
@ -607,10 +596,10 @@ ScattDataHistogram::get_matrix(int max_order)
|
|||
|
||||
void
|
||||
ScattDataHistogram::combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars)
|
||||
const std::vector<double>& scalars)
|
||||
{
|
||||
// Find the max order in the data set and make sure we can combine the sets
|
||||
int max_order = those_scatts[0]->get_order();
|
||||
size_t max_order = those_scatts[0]->get_order();
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
// Lets also make sure these items are combineable
|
||||
ScattDataHistogram* that = dynamic_cast<ScattDataHistogram*>(those_scatts[i]);
|
||||
|
|
@ -622,10 +611,10 @@ ScattDataHistogram::combine(const std::vector<ScattData*>& those_scatts,
|
|||
}
|
||||
}
|
||||
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
size_t groups = those_scatts[0] -> energy.size();
|
||||
|
||||
int_1dvec in_gmin(groups);
|
||||
int_1dvec in_gmax(groups);
|
||||
xt::xtensor<int, 1> in_gmin({groups}, 0);
|
||||
xt::xtensor<int, 1> in_gmax({groups}, 0);
|
||||
double_3dvec sparse_scatter(groups);
|
||||
double_2dvec sparse_mult(groups);
|
||||
|
||||
|
|
@ -633,7 +622,7 @@ ScattDataHistogram::combine(const std::vector<ScattData*>& those_scatts,
|
|||
// so we use a base class method to sum up xs and create new energy and mult
|
||||
// matrices
|
||||
ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax,
|
||||
sparse_mult, sparse_scatter);
|
||||
sparse_mult, sparse_scatter);
|
||||
|
||||
// Got everything we need, store it.
|
||||
init(in_gmin, in_gmax, sparse_mult, sparse_scatter);
|
||||
|
|
@ -644,29 +633,24 @@ ScattDataHistogram::combine(const std::vector<ScattData*>& those_scatts,
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs)
|
||||
ScattDataTabular::init(const xt::xtensor<int, 1>& in_gmin,
|
||||
const xt::xtensor<int, 1>& in_gmax, const double_2dvec& in_mult,
|
||||
const double_3dvec& coeffs)
|
||||
{
|
||||
int groups = coeffs.size();
|
||||
int order = coeffs[0][0].size();
|
||||
size_t groups = coeffs.size();
|
||||
size_t order = coeffs[0][0].size();
|
||||
|
||||
// make a copy of coeffs that we can use to both extract data and normalize
|
||||
double_3dvec matrix = coeffs;
|
||||
|
||||
// Build the angular distribution mu values
|
||||
mu = double_1dvec(order);
|
||||
mu = xt::linspace(-1., 1., order);
|
||||
dmu = 2. / (order - 1);
|
||||
mu[0] = -1.;
|
||||
for (int imu = 1; imu < order - 1; imu++) {
|
||||
mu[imu] = -1. + imu * dmu;
|
||||
}
|
||||
mu[order - 1] = 1.;
|
||||
|
||||
// Get the scattering cross section value by integrating the distribution
|
||||
// over all mu points and then combining over all outgoing groups
|
||||
scattxs.resize(groups);
|
||||
scattxs = xt::zeros<double>({groups});
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
scattxs[gin] = 0.;
|
||||
for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) {
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
scattxs[gin] += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] +
|
||||
|
|
@ -743,7 +727,7 @@ ScattDataTabular::calc_f(int gin, int gout, double mu)
|
|||
int imu;
|
||||
if (mu == 1.) {
|
||||
// use size -2 to have the index one before the end
|
||||
imu = this->mu.size() - 2;
|
||||
imu = this->mu.shape()[0] - 2;
|
||||
} else {
|
||||
imu = std::floor((mu + 1.) / dmu + 1.) - 1;
|
||||
}
|
||||
|
|
@ -764,7 +748,7 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt)
|
|||
sample_energy(gin, gout, i_gout);
|
||||
|
||||
// Determine the outgoing cosine bin
|
||||
int NP = this->mu.size();
|
||||
int NP = this->mu.shape()[0];
|
||||
double xi = prn();
|
||||
|
||||
double c_k = dist[gin][i_gout][0];
|
||||
|
|
@ -804,21 +788,20 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt)
|
|||
|
||||
//==============================================================================
|
||||
|
||||
double_3dvec
|
||||
ScattDataTabular::get_matrix(int max_order)
|
||||
xt::xtensor<double, 3>
|
||||
ScattDataTabular::get_matrix(size_t max_order)
|
||||
{
|
||||
// Get the sizes and initialize the data to 0
|
||||
int groups = energy.size();
|
||||
size_t groups = energy.size();
|
||||
// We ignore the requested order for Histogram and Tabular representations
|
||||
int order_dim = get_order();
|
||||
double_3dvec matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(order_dim, 0.)));
|
||||
size_t order_dim = get_order();
|
||||
xt::xtensor<double, 3> matrix({groups, groups, order_dim}, 0.);
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) {
|
||||
int gout = i_gout + gmin[gin];
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] *
|
||||
matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] *
|
||||
fmu[gin][i_gout][l];
|
||||
}
|
||||
}
|
||||
|
|
@ -830,10 +813,10 @@ ScattDataTabular::get_matrix(int max_order)
|
|||
|
||||
void
|
||||
ScattDataTabular::combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars)
|
||||
const std::vector<double>& scalars)
|
||||
{
|
||||
// Find the max order in the data set and make sure we can combine the sets
|
||||
int max_order = those_scatts[0]->get_order();
|
||||
size_t max_order = those_scatts[0]->get_order();
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
// Lets also make sure these items are combineable
|
||||
ScattDataTabular* that = dynamic_cast<ScattDataTabular*>(those_scatts[i]);
|
||||
|
|
@ -845,10 +828,10 @@ ScattDataTabular::combine(const std::vector<ScattData*>& those_scatts,
|
|||
}
|
||||
}
|
||||
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
size_t groups = those_scatts[0] -> energy.size();
|
||||
|
||||
int_1dvec in_gmin(groups);
|
||||
int_1dvec in_gmax(groups);
|
||||
xt::xtensor<int, 1> in_gmin({groups}, 0);
|
||||
xt::xtensor<int, 1> in_gmax({groups}, 0);
|
||||
double_3dvec sparse_scatter(groups);
|
||||
double_2dvec sparse_mult(groups);
|
||||
|
||||
|
|
@ -856,7 +839,7 @@ ScattDataTabular::combine(const std::vector<ScattData*>& those_scatts,
|
|||
// so we use a base class method to sum up xs and create new energy and mult
|
||||
// matrices
|
||||
ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax,
|
||||
sparse_mult, sparse_scatter);
|
||||
sparse_mult, sparse_scatter);
|
||||
|
||||
// Got everything we need, store it.
|
||||
init(in_gmin, in_gmax, sparse_mult, sparse_scatter);
|
||||
|
|
@ -885,16 +868,11 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab,
|
|||
tab.scattxs = leg.scattxs;
|
||||
|
||||
// Build mu and dmu
|
||||
tab.mu = double_1dvec(n_mu);
|
||||
tab.mu = xt::linspace(-1., 1., n_mu);
|
||||
tab.dmu = 2. / (n_mu - 1);
|
||||
tab.mu[0] = -1.;
|
||||
for (int imu = 1; imu < n_mu - 1; imu++) {
|
||||
tab.mu[imu] = -1. + imu * tab.dmu;
|
||||
}
|
||||
tab.mu[n_mu - 1] = 1.;
|
||||
|
||||
// Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
int groups = tab.energy.size();
|
||||
size_t groups = tab.energy.size();
|
||||
tab.fmu.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = tab.gmax[gin] - tab.gmin[gin] + 1;
|
||||
|
|
|
|||
109
src/settings.F90
109
src/settings.F90
|
|
@ -9,105 +9,103 @@ module settings
|
|||
|
||||
! ============================================================================
|
||||
! ENERGY TREATMENT RELATED VARIABLES
|
||||
logical(C_BOOL) :: run_CE = .true. ! Run in CE mode?
|
||||
logical(C_BOOL), bind(C, name='run_CE') :: run_CE ! Run in CE mode?
|
||||
|
||||
! ============================================================================
|
||||
! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Unreoslved resonance probablity tables
|
||||
logical :: urr_ptables_on = .true.
|
||||
logical(C_BOOL), bind(C) :: urr_ptables_on
|
||||
|
||||
! Default temperature and method for choosing temperatures
|
||||
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(8) :: temperature_range(2) = [ZERO, ZERO]
|
||||
integer(C_INT), bind(C) :: temperature_method
|
||||
logical(C_BOOL), bind(C) :: temperature_multipole
|
||||
real(C_DOUBLE), bind(C) :: temperature_tolerance
|
||||
real(C_DOUBLE), bind(C) :: temperature_default
|
||||
real(C_DOUBLE), bind(C) :: temperature_range(2)
|
||||
|
||||
integer :: n_log_bins ! number of bins for logarithmic grid
|
||||
integer(C_INT), bind(C) :: n_log_bins ! number of bins for logarithmic grid
|
||||
|
||||
logical :: photon_transport = .false.
|
||||
integer :: electron_treatment = ELECTRON_TTB
|
||||
logical(C_BOOL), bind(C) :: photon_transport
|
||||
integer(C_INT), bind(C) :: electron_treatment
|
||||
|
||||
! ============================================================================
|
||||
! MULTI-GROUP CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Maximum Data Order
|
||||
integer(C_INT) :: max_order
|
||||
integer(C_INT), bind(C) :: max_order
|
||||
|
||||
! Whether or not to convert Legendres to tabulars
|
||||
logical :: legendre_to_tabular = .true.
|
||||
logical(C_BOOL), bind(C) :: legendre_to_tabular
|
||||
|
||||
! Number of points to use in the Legendre to tabular conversion
|
||||
integer(C_INT) :: legendre_to_tabular_points = C_NONE
|
||||
integer(C_INT), bind(C) :: legendre_to_tabular_points
|
||||
|
||||
! ============================================================================
|
||||
! SIMULATION VARIABLES
|
||||
|
||||
! Assume all tallies are spatially distinct
|
||||
logical :: assume_separate = .false.
|
||||
logical(C_BOOL), bind(C) :: assume_separate
|
||||
|
||||
! Use confidence intervals for results instead of standard deviations
|
||||
logical :: confidence_intervals = .false.
|
||||
logical(C_BOOL), bind(C) :: confidence_intervals
|
||||
|
||||
integer(C_INT64_T), bind(C) :: n_particles = 0 ! # of particles per generation
|
||||
integer(C_INT32_T), bind(C) :: n_batches ! # of batches
|
||||
integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches
|
||||
integer(C_INT32_T), bind(C) :: gen_per_batch = 1 ! # of generations per batch
|
||||
integer(C_INT64_T), bind(C) :: n_particles ! # of particles per generation
|
||||
integer(C_INT32_T), bind(C) :: n_batches ! # of batches
|
||||
integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches
|
||||
integer(C_INT32_T), bind(C) :: gen_per_batch ! # of generations per batch
|
||||
|
||||
integer :: n_max_batches ! max # of batches
|
||||
integer :: n_batch_interval = 1 ! batch interval for triggers
|
||||
logical :: pred_batches = .false. ! predict batches for triggers
|
||||
logical :: trigger_on = .false. ! flag for turning triggers on/off
|
||||
integer(C_INT), bind(C) :: n_max_batches ! max # of batches
|
||||
integer(C_INT), bind(C, name='trigger_batch_interval') :: n_batch_interval ! batch interval for triggers
|
||||
logical(C_BOOL), bind(C, name='trigger_predict') :: pred_batches ! predict batches for triggers
|
||||
logical(C_BOOL), bind(C) :: trigger_on ! flag for turning triggers on/off
|
||||
|
||||
logical :: entropy_on = .false.
|
||||
integer :: index_entropy_mesh = -1
|
||||
logical(C_BOOL), bind(C) :: entropy_on
|
||||
integer(C_INT32_T), bind(C) :: index_entropy_mesh
|
||||
|
||||
logical :: ufs = .false.
|
||||
integer :: index_ufs_mesh = -1
|
||||
logical(C_BOOL), bind(C, name='ufs_on') :: ufs
|
||||
integer(C_INT32_T), bind(C) :: index_ufs_mesh
|
||||
|
||||
! Write source at end of simulation
|
||||
logical :: source_separate = .false.
|
||||
logical :: source_write = .true.
|
||||
logical :: source_latest = .false.
|
||||
logical(C_BOOL), bind(C) :: source_separate
|
||||
logical(C_BOOL), bind(C) :: source_write
|
||||
logical(C_BOOL), bind(C) :: source_latest
|
||||
|
||||
! Variance reduction settins
|
||||
logical :: survival_biasing = .false.
|
||||
real(8) :: weight_cutoff = 0.25_8
|
||||
real(8) :: energy_cutoff(4) = [ZERO, 1000.0_8, ZERO, ZERO]
|
||||
real(8) :: weight_survive = ONE
|
||||
logical(C_BOOL), bind(C) :: survival_biasing
|
||||
real(C_DOUBLE), bind(C) :: weight_cutoff
|
||||
real(C_DOUBLE), bind(C) :: energy_cutoff(4)
|
||||
real(C_DOUBLE), bind(C) :: weight_survive
|
||||
|
||||
! Mode to run in (fixed source, eigenvalue, plotting, etc)
|
||||
integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE
|
||||
integer(C_INT), bind(C) :: run_mode
|
||||
|
||||
! Restart run
|
||||
logical(C_BOOL), bind(C, name='openmc_restart_run') :: restart_run = .false.
|
||||
logical(C_BOOL), bind(C) :: restart_run
|
||||
|
||||
! The verbosity controls how much information will be printed to the screen
|
||||
! and in logs
|
||||
integer(C_INT), bind(C, name='openmc_verbosity') :: verbosity = 7
|
||||
integer(C_INT), bind(C) :: verbosity
|
||||
|
||||
logical(C_BOOL), bind(C, name='openmc_check_overlaps') :: check_overlaps = .false.
|
||||
logical(C_BOOL), bind(C) :: check_overlaps
|
||||
|
||||
! Trace for single particle
|
||||
integer :: trace_batch
|
||||
integer :: trace_gen
|
||||
integer(8) :: trace_particle
|
||||
integer(C_INT), bind(C) :: trace_batch
|
||||
integer(C_INT), bind(C) :: trace_gen
|
||||
integer(C_INT64_T), bind(C) :: trace_particle
|
||||
|
||||
! Particle tracks
|
||||
logical(C_BOOL), bind(C, name='openmc_write_all_tracks') :: &
|
||||
write_all_tracks = .false.
|
||||
logical(C_BOOL), bind(C) :: write_all_tracks
|
||||
integer, allocatable :: track_identifiers(:,:)
|
||||
|
||||
! Particle restart run
|
||||
logical(C_BOOL), bind(C, name='openmc_particle_restart_run') :: &
|
||||
particle_restart_run = .false.
|
||||
logical(C_BOOL), bind(C) :: particle_restart_run
|
||||
|
||||
! Write out initial source
|
||||
logical :: write_initial_source = .false.
|
||||
logical(C_BOOL), bind(C) :: write_initial_source
|
||||
|
||||
! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE
|
||||
logical :: create_fission_neutrons = .true.
|
||||
logical(C_BOOL), bind(C) :: create_fission_neutrons
|
||||
|
||||
! Information about state points to be written
|
||||
integer :: n_state_points = 0
|
||||
|
|
@ -120,28 +118,27 @@ 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
|
||||
character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory
|
||||
|
||||
! Various output options
|
||||
logical :: output_summary = .true.
|
||||
logical :: output_tallies = .true.
|
||||
logical(C_BOOL), bind(C) :: output_summary
|
||||
logical(C_BOOL), bind(C) :: output_tallies
|
||||
|
||||
! Resonance scattering settings
|
||||
logical :: res_scat_on = .false. ! is resonance scattering treated?
|
||||
integer :: res_scat_method = RES_SCAT_ARES ! resonance scattering method
|
||||
real(8) :: res_scat_energy_min = 0.01_8
|
||||
real(8) :: res_scat_energy_max = 1000.0_8
|
||||
logical(C_BOOL), bind(C) :: res_scat_on ! is resonance scattering treated?
|
||||
integer(C_INT), bind(C) :: res_scat_method ! resonance scattering method
|
||||
real(C_DOUBLE), bind(C) :: res_scat_energy_min
|
||||
real(C_DOUBLE), bind(C) :: res_scat_energy_max
|
||||
character(10), allocatable :: res_scat_nuclides(:)
|
||||
|
||||
! Is CMFD active
|
||||
logical :: cmfd_run = .false.
|
||||
logical(C_BOOL), bind(C) :: cmfd_run
|
||||
|
||||
! No reduction at end of batch
|
||||
logical :: reduce_tallies = .true.
|
||||
logical(C_BOOL), bind(C) :: reduce_tallies
|
||||
|
||||
contains
|
||||
|
||||
|
|
|
|||
722
src/settings.cpp
722
src/settings.cpp
|
|
@ -1,8 +1,23 @@
|
|||
#include "openmc/settings.h"
|
||||
|
||||
#include <cmath> // for ceil, pow
|
||||
#include <limits> // for numeric_limits
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <omp.h>
|
||||
|
||||
#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/file_utils.h"
|
||||
#include "openmc/mesh.h"
|
||||
#include "openmc/output.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/string_utils.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
|
|
@ -12,57 +27,599 @@ namespace openmc {
|
|||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
char* openmc_path_input;
|
||||
char* openmc_path_statepoint;
|
||||
char* openmc_path_sourcepoint;
|
||||
char* openmc_path_particle_restart;
|
||||
namespace settings {
|
||||
|
||||
// Default values for boolean flags
|
||||
bool assume_separate {false};
|
||||
bool check_overlaps {false};
|
||||
bool cmfd_run {false};
|
||||
bool confidence_intervals {false};
|
||||
bool create_fission_neutrons {true};
|
||||
bool entropy_on {false};
|
||||
bool legendre_to_tabular {true};
|
||||
bool output_summary {true};
|
||||
bool output_tallies {true};
|
||||
bool particle_restart_run {false};
|
||||
bool photon_transport {false};
|
||||
bool reduce_tallies {true};
|
||||
bool res_scat_on {false};
|
||||
bool restart_run {false};
|
||||
bool run_CE {true};
|
||||
bool source_latest {false};
|
||||
bool source_separate {false};
|
||||
bool source_write {true};
|
||||
bool survival_biasing {false};
|
||||
bool temperature_multipole {false};
|
||||
bool trigger_on {false};
|
||||
bool trigger_predict {false};
|
||||
bool ufs_on {false};
|
||||
bool urr_ptables_on {true};
|
||||
bool write_all_tracks {false};
|
||||
bool write_initial_source {false};
|
||||
|
||||
std::string path_cross_sections;
|
||||
std::string path_input;
|
||||
std::string path_multipole;
|
||||
std::string path_output;
|
||||
std::string path_particle_restart;
|
||||
std::string path_source;
|
||||
std::string path_sourcepoint;
|
||||
std::string path_statepoint;
|
||||
|
||||
int32_t index_entropy_mesh {-1};
|
||||
int32_t index_ufs_mesh {-1};
|
||||
|
||||
int32_t n_batches;
|
||||
int32_t n_inactive {0};
|
||||
int32_t gen_per_batch {1};
|
||||
int64_t n_particles {-1};
|
||||
|
||||
int electron_treatment {ELECTRON_TTB};
|
||||
double energy_cutoff[4] {0.0, 1000.0, 0.0, 0.0};
|
||||
int legendre_to_tabular_points {C_NONE};
|
||||
int max_order {0};
|
||||
int n_log_bins {8000};
|
||||
int n_max_batches;
|
||||
int res_scat_method {RES_SCAT_ARES};
|
||||
double res_scat_energy_min {0.01};
|
||||
double res_scat_energy_max {1000.0};
|
||||
int run_mode {-1};
|
||||
int temperature_method {TEMPERATURE_NEAREST};
|
||||
bool temperature_multipole {false};
|
||||
double temperature_tolerance {10.0};
|
||||
double temperature_default {293.6};
|
||||
std::array<double, 2> temperature_range {0.0, 0.0};
|
||||
double temperature_range[2] {0.0, 0.0};
|
||||
int trace_batch;
|
||||
int trace_gen;
|
||||
int64_t trace_particle;
|
||||
int trigger_batch_interval {1};
|
||||
int verbosity {7};
|
||||
double weight_cutoff {0.25};
|
||||
double weight_survive {1.0};
|
||||
|
||||
// TODO: Move to separate file
|
||||
struct KTrigger {
|
||||
int type;
|
||||
double threshold;
|
||||
};
|
||||
extern "C" KTrigger keff_trigger;
|
||||
|
||||
} // namespace settings
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
//==============================================================================
|
||||
|
||||
void read_settings(pugi::xml_node* root)
|
||||
void get_run_parameters(pugi::xml_node node_base)
|
||||
{
|
||||
using namespace settings;
|
||||
using namespace pugi;
|
||||
|
||||
// Check number of particles
|
||||
if (!check_for_node(node_base, "particles")) {
|
||||
fatal_error("Need to specify number of particles.");
|
||||
}
|
||||
|
||||
// Get number of particles if it wasn't specified as a command-line argument
|
||||
if (n_particles == -1) {
|
||||
n_particles = std::stoll(get_node_value(node_base, "particles"));
|
||||
}
|
||||
|
||||
// Get number of basic batches
|
||||
if (check_for_node(node_base, "batches")) {
|
||||
n_batches = std::stoi(get_node_value(node_base, "batches"));
|
||||
}
|
||||
if (!trigger_on) n_max_batches = n_batches;
|
||||
|
||||
// Get number of inactive batches
|
||||
if (run_mode == RUN_MODE_EIGENVALUE) {
|
||||
if (check_for_node(node_base, "inactive")) {
|
||||
n_inactive = std::stoi(get_node_value(node_base, "inactive"));
|
||||
}
|
||||
if (check_for_node(node_base, "generations_per_batch")) {
|
||||
gen_per_batch = std::stoi(get_node_value(node_base, "generations_per_batch"));
|
||||
}
|
||||
|
||||
// TODO: Preallocate space for keff and entropy by generation
|
||||
|
||||
// Get the trigger information for keff
|
||||
if (check_for_node(node_base, "keff_trigger")) {
|
||||
xml_node node_keff_trigger = node_base.child("keff_trigger");
|
||||
|
||||
if (check_for_node(node_keff_trigger, "type")) {
|
||||
auto temp = get_node_value(node_keff_trigger, "type", true, true);
|
||||
if (temp == "std_dev") {
|
||||
keff_trigger.type = STANDARD_DEVIATION;
|
||||
} else if (temp == "variance") {
|
||||
keff_trigger.type = VARIANCE;
|
||||
} else if (temp == "rel_err") {
|
||||
keff_trigger.type = RELATIVE_ERROR;
|
||||
} else {
|
||||
fatal_error("Unrecognized keff trigger type " + temp);
|
||||
}
|
||||
} else {
|
||||
fatal_error("Specify keff trigger type in settings XML");
|
||||
}
|
||||
|
||||
if (check_for_node(node_keff_trigger, "threshold")) {
|
||||
keff_trigger.threshold = std::stod(get_node_value(
|
||||
node_keff_trigger, "threshold"));
|
||||
} else {
|
||||
fatal_error("Specify keff trigger threshold in settings XML");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read_settings_xml()
|
||||
{
|
||||
using namespace settings;
|
||||
using namespace pugi;
|
||||
|
||||
// Check if settings.xml exists
|
||||
std::string filename = std::string(path_input) + "settings.xml";
|
||||
if (!file_exists(filename)) {
|
||||
if (run_mode != RUN_MODE_PLOTTING) {
|
||||
std::stringstream msg;
|
||||
msg << "Settings XML file '" << filename << "' does not exist! In order "
|
||||
"to run OpenMC, you first need a set of input files; at a minimum, this "
|
||||
"includes settings.xml, geometry.xml, and materials.xml. Please consult "
|
||||
"the user's guide at http://openmc.readthedocs.io for further "
|
||||
"information.";
|
||||
fatal_error(msg);
|
||||
} else {
|
||||
// The settings.xml file is optional if we just want to make a plot.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse settings.xml file
|
||||
xml_document doc;
|
||||
auto result = doc.load_file("settings.xml");
|
||||
if (!result) {
|
||||
fatal_error("Error processing settings.xml file.");
|
||||
}
|
||||
|
||||
// Get root element
|
||||
xml_node root = doc.document_element();
|
||||
|
||||
// Verbosity
|
||||
if (check_for_node(root, "verbosity")) {
|
||||
verbosity = std::stoi(get_node_value(root, "verbosity"));
|
||||
}
|
||||
|
||||
// To this point, we haven't displayed any output since we didn't know what
|
||||
// the verbosity is. Now that we checked for it, show the title if necessary
|
||||
if (openmc_master) {
|
||||
if (verbosity >= 2) title();
|
||||
}
|
||||
write_message("Reading settings XML file...", 5);
|
||||
|
||||
// Find if a multi-group or continuous-energy simulation is desired
|
||||
if (check_for_node(root, "energy_mode")) {
|
||||
std::string temp_str = get_node_value(root, "energy_mode", true, true);
|
||||
if (temp_str == "mg" || temp_str == "multi-group") {
|
||||
run_CE = false;
|
||||
} else if (temp_str == "ce" || temp_str == "continuous-energy") {
|
||||
run_CE = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for deprecated cross_sections.xml file in settings.xml
|
||||
if (check_for_node(*root, "cross_sections")) {
|
||||
if (check_for_node(root, "cross_sections")) {
|
||||
warning("Setting cross_sections in settings.xml has been deprecated."
|
||||
" The cross_sections are now set in materials.xml and the "
|
||||
"cross_sections input to materials.xml and the OPENMC_CROSS_SECTIONS"
|
||||
" environment variable will take precendent over setting "
|
||||
"cross_sections in settings.xml.");
|
||||
path_cross_sections = get_node_value(*root, "cross_sections");
|
||||
path_cross_sections = get_node_value(root, "cross_sections");
|
||||
}
|
||||
|
||||
// Look for deprecated windowed_multipole file in settings.xml
|
||||
if (openmc_run_mode != RUN_MODE_PLOTTING) {
|
||||
if (check_for_node(*root, "multipole_library")) {
|
||||
if (run_mode != RUN_MODE_PLOTTING) {
|
||||
if (check_for_node(root, "multipole_library")) {
|
||||
warning("Setting multipole_library in settings.xml has been "
|
||||
"deprecated. The multipole_library is now set in materials.xml and"
|
||||
" the multipole_library input to materials.xml and the "
|
||||
"OPENMC_MULTIPOLE_LIBRARY environment variable will take "
|
||||
"precendent over setting multipole_library in settings.xml.");
|
||||
path_multipole = get_node_value(*root, "multipole_library");
|
||||
path_multipole = get_node_value(root, "multipole_library");
|
||||
}
|
||||
if (!ends_with(path_multipole, "/")) {
|
||||
path_multipole += "/";
|
||||
}
|
||||
}
|
||||
|
||||
// Check for output options
|
||||
if (check_for_node(*root, "output")) {
|
||||
if (!run_CE) {
|
||||
// Scattering Treatments
|
||||
if (check_for_node(root, "max_order")) {
|
||||
max_order = std::stoi(get_node_value(root, "max_order"));
|
||||
} else {
|
||||
// Set to default of largest int - 1, which means to use whatever is
|
||||
// contained in library. This is largest int - 1 because for legendre
|
||||
// scattering, a value of 1 is added to the order; adding 1 to the largest
|
||||
// int gets you the largest negative integer, which is not what we want.
|
||||
max_order = std::numeric_limits<int>::max() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a trigger node and get trigger information
|
||||
if (check_for_node(root, "trigger")) {
|
||||
xml_node node_trigger = root.child("trigger");
|
||||
|
||||
// Check if trigger(s) are to be turned on
|
||||
trigger_on = get_node_value_bool(node_trigger, "active");
|
||||
|
||||
if (trigger_on) {
|
||||
if (check_for_node(node_trigger, "max_batches") ){
|
||||
n_max_batches = std::stoi(get_node_value(node_trigger, "max_batches"));
|
||||
} else {
|
||||
fatal_error("<max_batches> must be specified with triggers");
|
||||
}
|
||||
|
||||
// Get the batch interval to check triggers
|
||||
if (!check_for_node(node_trigger, "batch_interval")){
|
||||
trigger_predict = true;
|
||||
} else {
|
||||
trigger_batch_interval = std::stoi(get_node_value(node_trigger, "batch_interval"));
|
||||
if (trigger_batch_interval <= 0) {
|
||||
fatal_error("Trigger batch interval must be greater than zero");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check run mode if it hasn't been set from the command line
|
||||
xml_node node_mode;
|
||||
if (run_mode == C_NONE) {
|
||||
if (check_for_node(root, "run_mode")) {
|
||||
std::string temp_str = get_node_value(root, "run_mode", true, true);
|
||||
if (temp_str == "eigenvalue") {
|
||||
run_mode = RUN_MODE_EIGENVALUE;
|
||||
} else if (temp_str == "fixed source") {
|
||||
run_mode = RUN_MODE_FIXEDSOURCE;
|
||||
} else if (temp_str == "plot") {
|
||||
run_mode = RUN_MODE_PLOTTING;
|
||||
} else if (temp_str == "particle restart") {
|
||||
run_mode = RUN_MODE_PARTICLE;
|
||||
} else if (temp_str == "volume") {
|
||||
run_mode = RUN_MODE_VOLUME;
|
||||
} else {
|
||||
fatal_error("Unrecognized run mode: " + temp_str);
|
||||
}
|
||||
|
||||
// Assume XML specifies <particles>, <batches>, etc. directly
|
||||
node_mode = root;
|
||||
} else {
|
||||
warning("<run_mode> should be specified.");
|
||||
|
||||
// Make sure that either eigenvalue or fixed source was specified
|
||||
node_mode = root.child("eigenvalue");
|
||||
if (node_mode) {
|
||||
run_mode = RUN_MODE_EIGENVALUE;
|
||||
} else {
|
||||
node_mode = root.child("fixed_source");
|
||||
if (node_mode) {
|
||||
run_mode = RUN_MODE_FIXEDSOURCE;
|
||||
} else {
|
||||
fatal_error("<eigenvalue> or <fixed_source> not specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (run_mode == RUN_MODE_EIGENVALUE || run_mode == RUN_MODE_FIXEDSOURCE) {
|
||||
// Read run parameters
|
||||
get_run_parameters(node_mode);
|
||||
|
||||
// Check number of active batches, inactive batches, and particles
|
||||
if (n_batches <= n_inactive) {
|
||||
fatal_error("Number of active batches must be greater than zero.");
|
||||
} else if (n_inactive < 0) {
|
||||
fatal_error("Number of inactive batches must be non-negative.");
|
||||
} else if (n_particles <= 0) {
|
||||
fatal_error("Number of particles must be greater than zero.");
|
||||
}
|
||||
}
|
||||
|
||||
// Copy random number seed if specified
|
||||
if (check_for_node(root, "seed")) {
|
||||
auto seed = std::stoll(get_node_value(root, "seed"));
|
||||
openmc_set_seed(seed);
|
||||
}
|
||||
|
||||
// Check for electron treatment
|
||||
if (check_for_node(root, "electron_treatment")) {
|
||||
auto temp_str = get_node_value(root, "electron_treatment", true, true);
|
||||
if (temp_str == "led") {
|
||||
electron_treatment = ELECTRON_LED;
|
||||
} else if (temp_str == "ttb") {
|
||||
electron_treatment = ELECTRON_TTB;
|
||||
} else {
|
||||
fatal_error("Unrecognized electron treatment: " + temp_str + ".");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for photon transport
|
||||
if (check_for_node(root, "photon_transport")) {
|
||||
photon_transport = get_node_value_bool(root, "photon_transport");
|
||||
|
||||
if (!run_CE && photon_transport) {
|
||||
fatal_error("Photon transport is not currently supported in "
|
||||
"multigroup mode");
|
||||
}
|
||||
}
|
||||
|
||||
// Number of bins for logarithmic grid
|
||||
if (check_for_node(root, "log_grid_bins")) {
|
||||
n_log_bins = std::stoi(get_node_value(root, "log_grid_bins"));
|
||||
if (n_log_bins < 1) {
|
||||
fatal_error("Number of bins for logarithmic grid must be greater "
|
||||
"than zero.");
|
||||
}
|
||||
}
|
||||
|
||||
// Number of OpenMP threads
|
||||
if (check_for_node(root, "threads")) {
|
||||
#ifdef _OPENMP
|
||||
if (openmc_n_threads == 0) {
|
||||
openmc_n_threads = std::stoi(get_node_value(root, "threads"));
|
||||
if (openmc_n_threads < 1) {
|
||||
std::stringstream msg;
|
||||
msg << "Invalid number of threads: " << openmc_n_threads;
|
||||
fatal_error(msg);
|
||||
}
|
||||
omp_set_num_threads(openmc_n_threads);
|
||||
}
|
||||
#else
|
||||
if (openmc_master) warning("OpenMC was not compiled with OpenMP support; "
|
||||
"ignoring number of threads.");
|
||||
#endif
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Check if we want to write out source
|
||||
if (check_for_node(root, "write_initial_source")) {
|
||||
write_initial_source = get_node_value_bool(root, "write_initial_source");
|
||||
}
|
||||
|
||||
// Survival biasing
|
||||
if (check_for_node(root, "survival_biasing")) {
|
||||
survival_biasing = get_node_value_bool(root, "survival_biasing");
|
||||
}
|
||||
|
||||
// Probability tables
|
||||
if (check_for_node(root, "ptables")) {
|
||||
urr_ptables_on = get_node_value_bool(root, "ptables");
|
||||
}
|
||||
|
||||
// Cutoffs
|
||||
if (check_for_node(root, "cutoff")) {
|
||||
xml_node node_cutoff = root.child("cutoff");
|
||||
if (check_for_node(node_cutoff, "weight")) {
|
||||
weight_cutoff = std::stod(get_node_value(node_cutoff, "weight"));
|
||||
}
|
||||
if (check_for_node(node_cutoff, "weight_avg")) {
|
||||
weight_survive = std::stod(get_node_value(node_cutoff, "weight_avg"));
|
||||
}
|
||||
if (check_for_node(node_cutoff, "energy_neutron")) {
|
||||
energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy_neutron"));
|
||||
} else if (check_for_node(node_cutoff, "energy")) {
|
||||
warning("The use of an <energy> cutoff is deprecated and should "
|
||||
"be replaced by <energy_neutron>.");
|
||||
energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy"));
|
||||
}
|
||||
if (check_for_node(node_cutoff, "energy_photon")) {
|
||||
energy_cutoff[1] = std::stod(get_node_value(node_cutoff, "energy_photon"));
|
||||
}
|
||||
if (check_for_node(node_cutoff, "energy_electron")) {
|
||||
energy_cutoff[2] = std::stof(get_node_value(node_cutoff, "energy_electron"));
|
||||
}
|
||||
if (check_for_node(node_cutoff, "energy_positron")) {
|
||||
energy_cutoff[3] = std::stod(get_node_value(node_cutoff, "energy_positron"));
|
||||
}
|
||||
}
|
||||
|
||||
// Particle trace
|
||||
if (check_for_node(root, "trace")) {
|
||||
auto temp = get_node_array<int64_t>(root, "trace");
|
||||
if (temp.size() != 3) {
|
||||
fatal_error("Must provide 3 integers for <trace> that specify the "
|
||||
"batch, generation, and particle number.");
|
||||
}
|
||||
trace_batch = temp.at(0);
|
||||
trace_gen = temp.at(1);
|
||||
trace_particle = temp.at(2);
|
||||
}
|
||||
|
||||
// Particle tracks
|
||||
if (check_for_node(root, "track")) {
|
||||
// Get values and make sure there are three per particle
|
||||
auto temp = get_node_array<int64_t>(root, "track");
|
||||
if (temp.size() % 3 != 0) {
|
||||
fatal_error("Number of integers specified in 'track' is not "
|
||||
"divisible by 3. Please provide 3 integers per particle to be "
|
||||
"tracked.");
|
||||
}
|
||||
|
||||
// Reshape into track_identifiers
|
||||
//allocate(track_identifiers(3, n_tracks/3))
|
||||
//track_identifiers = reshape(temp_int_array, [3, n_tracks/3])
|
||||
}
|
||||
|
||||
// Read meshes
|
||||
read_meshes(&root);
|
||||
|
||||
// Shannon Entropy mesh
|
||||
if (check_for_node(root, "entropy_mesh")) {
|
||||
int temp = std::stoi(get_node_value(root, "entropy_mesh"));
|
||||
if (mesh_map.find(temp) == mesh_map.end()) {
|
||||
std::stringstream msg;
|
||||
msg << "Mesh " << temp << " specified for Shannon entropy does not exist.";
|
||||
fatal_error(msg);
|
||||
}
|
||||
index_entropy_mesh = mesh_map.at(temp);
|
||||
|
||||
} else if (check_for_node(root, "entropy")) {
|
||||
warning("Specifying a Shannon entropy mesh via the <entropy> element "
|
||||
"is deprecated. Please create a mesh using <mesh> and then reference "
|
||||
"it by specifying its ID in an <entropy_mesh> element.");
|
||||
|
||||
// Read entropy mesh from <entropy>
|
||||
auto node_entropy = root.child("entropy");
|
||||
meshes.emplace_back(new RegularMesh{node_entropy});
|
||||
|
||||
// Set entropy mesh index
|
||||
index_entropy_mesh = meshes.size() - 1;
|
||||
|
||||
// Assign ID and set mapping
|
||||
meshes.back()->id_ = 10000;
|
||||
mesh_map[10000] = index_entropy_mesh;
|
||||
}
|
||||
|
||||
if (index_entropy_mesh >= 0) {
|
||||
auto& m = *meshes[index_entropy_mesh];
|
||||
if (m.shape_.dimension() == 0) {
|
||||
// If the user did not specify how many mesh cells are to be used in
|
||||
// each direction, we automatically determine an appropriate number of
|
||||
// cells
|
||||
int n = std::ceil(std::pow(settings::n_particles / 20.0, 1.0/3.0));
|
||||
m.shape_ = {n, n, n};
|
||||
m.n_dimension_ = 3;
|
||||
|
||||
// Calculate width
|
||||
m.width_ = (m.upper_right_ - m.lower_left_) / m.shape_;
|
||||
}
|
||||
|
||||
// Turn on Shannon entropy calculation
|
||||
settings::entropy_on = true;
|
||||
}
|
||||
|
||||
// Uniform fission source weighting mesh
|
||||
if (check_for_node(root, "ufs_mesh")) {
|
||||
auto temp = std::stoi(get_node_value(root, "ufs_mesh"));
|
||||
if (mesh_map.find(temp) == mesh_map.end()) {
|
||||
std::stringstream msg;
|
||||
msg << "Mesh " << temp << " specified for uniform fission site method "
|
||||
"does not exist.";
|
||||
fatal_error(msg);
|
||||
}
|
||||
index_ufs_mesh = mesh_map.at(temp);
|
||||
|
||||
} else if (check_for_node(root, "uniform_fs")) {
|
||||
warning("Specifying a UFS mesh via the <uniform_fs> element "
|
||||
"is deprecated. Please create a mesh using <mesh> and then reference "
|
||||
"it by specifying its ID in a <ufs_mesh> element.");
|
||||
|
||||
// Read entropy mesh from <entropy>
|
||||
auto node_ufs = root.child("uniform_fs");
|
||||
meshes.emplace_back(new RegularMesh{node_ufs});
|
||||
|
||||
// Set entropy mesh index
|
||||
index_ufs_mesh = meshes.size() - 1;
|
||||
|
||||
// Assign ID and set mapping
|
||||
meshes.back()->id_ = 10001;
|
||||
mesh_map[10001] = index_entropy_mesh;
|
||||
}
|
||||
|
||||
if (index_ufs_mesh >= 0) {
|
||||
// Turn on uniform fission source weighting
|
||||
settings::ufs_on = true;
|
||||
}
|
||||
|
||||
// TODO: Read <state_point>
|
||||
|
||||
|
||||
// Check if the user has specified to write source points
|
||||
if (check_for_node(root, "source_point")) {
|
||||
// Get source_point node
|
||||
xml_node node_sp = root.child("source_point");
|
||||
|
||||
// TODO: Read source point batches
|
||||
|
||||
// Check if the user has specified to write binary source file
|
||||
if (check_for_node(node_sp, "separate")) {
|
||||
source_separate = get_node_value_bool(node_sp, "separate");
|
||||
}
|
||||
if (check_for_node(node_sp, "write")) {
|
||||
source_write = get_node_value_bool(node_sp, "write");
|
||||
}
|
||||
if (check_for_node(node_sp, "overwrite_latest")) {
|
||||
source_latest = get_node_value_bool(node_sp, "overwrite_latest");
|
||||
source_separate = source_latest;
|
||||
}
|
||||
} else {
|
||||
// If no <source_point> tag was present, by default we keep source bank in
|
||||
// statepoint file and write it out at statepoints intervals
|
||||
source_separate = false;
|
||||
// TODO: add defaults
|
||||
}
|
||||
|
||||
// TODO: Check source points are subset
|
||||
|
||||
// Check if the user has specified to not reduce tallies at the end of every
|
||||
// batch
|
||||
if (check_for_node(root, "no_reduce")) {
|
||||
reduce_tallies = get_node_value_bool(root, "no_reduce");
|
||||
}
|
||||
|
||||
// Check if the user has specified to use confidence intervals for
|
||||
// uncertainties rather than standard deviations
|
||||
if (check_for_node(root, "confidence_intervals")) {
|
||||
confidence_intervals = get_node_value_bool(root, "confidence_intervals");
|
||||
}
|
||||
|
||||
// Check for output options
|
||||
if (check_for_node(root, "output")) {
|
||||
// Get pointer to output node
|
||||
pugi::xml_node node_output = root->child("output");
|
||||
pugi::xml_node node_output = root.child("output");
|
||||
|
||||
// Check for summary option
|
||||
if (check_for_node(node_output, "summary")) {
|
||||
output_summary = get_node_value_bool(node_output, "summary");
|
||||
}
|
||||
|
||||
// Check for ASCII tallies output option
|
||||
if (check_for_node(node_output, "tallies")) {
|
||||
output_tallies = get_node_value_bool(node_output, "tallies");
|
||||
}
|
||||
|
||||
// Set output directory if a path has been specified
|
||||
if (check_for_node(node_output, "path")) {
|
||||
|
|
@ -73,30 +630,133 @@ void read_settings(pugi::xml_node* root)
|
|||
}
|
||||
}
|
||||
|
||||
// Get temperature settings
|
||||
if (check_for_node(*root, "temperature_default")) {
|
||||
temperature_default = std::stod(get_node_value(*root, "temperature_default"));
|
||||
// Check for cmfd run
|
||||
if (check_for_node(root, "run_cmfd")) {
|
||||
cmfd_run = get_node_value_bool(root, "run_cmfd");
|
||||
}
|
||||
if (check_for_node(*root, "temperature_method")) {
|
||||
auto temp_str = get_node_value(*root, "temperature_method", true, true);
|
||||
if (temp_str == "nearest") {
|
||||
|
||||
// Resonance scattering parameters
|
||||
if (check_for_node(root, "resonance_scattering")) {
|
||||
xml_node node_res_scat = root.child("resonance_scattering");
|
||||
|
||||
// See if resonance scattering is enabled
|
||||
if (check_for_node(node_res_scat, "enable")) {
|
||||
res_scat_on = get_node_value_bool(node_res_scat, "enable");
|
||||
} else {
|
||||
res_scat_on = true;
|
||||
}
|
||||
|
||||
// Determine what method is used
|
||||
if (check_for_node(node_res_scat, "method")) {
|
||||
auto temp = get_node_value(node_res_scat, "method", true, true);
|
||||
if (temp == "ares") {
|
||||
res_scat_method = RES_SCAT_ARES;
|
||||
} else if (temp == "dbrc") {
|
||||
res_scat_method = RES_SCAT_DBRC;
|
||||
} else if (temp == "wcm") {
|
||||
res_scat_method = RES_SCAT_WCM;
|
||||
} else {
|
||||
fatal_error("Unrecognized resonance elastic scattering method: "
|
||||
+ temp + ".");
|
||||
}
|
||||
}
|
||||
|
||||
// Minimum energy for resonance scattering
|
||||
if (check_for_node(node_res_scat, "energy_min")) {
|
||||
res_scat_energy_min = std::stod(get_node_value(node_res_scat, "energy_min"));
|
||||
}
|
||||
if (res_scat_energy_min < 0.0) {
|
||||
fatal_error("Lower resonance scattering energy bound is negative");
|
||||
}
|
||||
|
||||
// Maximum energy for resonance scattering
|
||||
if (check_for_node(node_res_scat, "energy_max")) {
|
||||
res_scat_energy_max = std::stod(get_node_value(node_res_scat, "energy_max"));
|
||||
}
|
||||
if (res_scat_energy_max < res_scat_energy_min) {
|
||||
fatal_error("Upper resonance scattering energy bound is below the "
|
||||
"lower resonance scattering energy bound.");
|
||||
}
|
||||
|
||||
// TODO: Get resonance scattering nuclides
|
||||
}
|
||||
|
||||
// TODO: Get volume calculations
|
||||
|
||||
// Get temperature settings
|
||||
if (check_for_node(root, "temperature_default")) {
|
||||
temperature_default = std::stod(get_node_value(root, "temperature_default"));
|
||||
}
|
||||
if (check_for_node(root, "temperature_method")) {
|
||||
auto temp = get_node_value(root, "temperature_method", true, true);
|
||||
if (temp == "nearest") {
|
||||
temperature_method = TEMPERATURE_NEAREST;
|
||||
} else if (temp_str == "interpolation") {
|
||||
} else if (temp == "interpolation") {
|
||||
temperature_method = TEMPERATURE_INTERPOLATION;
|
||||
} else {
|
||||
fatal_error("Unknown temperature method: " + temp_str);
|
||||
fatal_error("Unknown temperature method: " + temp);
|
||||
}
|
||||
}
|
||||
if (check_for_node(*root, "temperature_tolerance")) {
|
||||
temperature_tolerance = std::stod(get_node_value(*root, "temperature_tolerance"));
|
||||
if (check_for_node(root, "temperature_tolerance")) {
|
||||
temperature_tolerance = std::stod(get_node_value(root, "temperature_tolerance"));
|
||||
}
|
||||
if (check_for_node(*root, "temperature_multipole")) {
|
||||
temperature_multipole = get_node_value_bool(*root, "temperature_multipole");
|
||||
if (check_for_node(root, "temperature_multipole")) {
|
||||
temperature_multipole = get_node_value_bool(root, "temperature_multipole");
|
||||
}
|
||||
if (check_for_node(*root, "temperature_range")) {
|
||||
auto range = get_node_array<double>(*root, "temperature_range");
|
||||
temperature_range[0] = range[0];
|
||||
temperature_range[1] = range[1];
|
||||
if (check_for_node(root, "temperature_range")) {
|
||||
auto range = get_node_array<double>(root, "temperature_range");
|
||||
temperature_range[0] = range.at(0);
|
||||
temperature_range[1] = range.at(1);
|
||||
}
|
||||
|
||||
// Check for tabular_legendre options
|
||||
if (check_for_node(root, "tabular_legendre")) {
|
||||
// Get pointer to tabular_legendre node
|
||||
xml_node node_tab_leg = root.child("tabular_legendre");
|
||||
|
||||
// Check for enable option
|
||||
if (check_for_node(node_tab_leg, "enable")) {
|
||||
legendre_to_tabular = get_node_value_bool(node_tab_leg, "enable");
|
||||
}
|
||||
|
||||
// Check for the number of points
|
||||
if (check_for_node(node_tab_leg, "num_points")) {
|
||||
legendre_to_tabular_points = std::stoi(get_node_value(
|
||||
node_tab_leg, "num_points"));
|
||||
if (legendre_to_tabular_points <= 1 && !run_CE) {
|
||||
fatal_error("The 'num_points' subelement/attribute of the "
|
||||
"<tabular_legendre> element must contain a value greater than 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether create fission sites
|
||||
if (run_mode == RUN_MODE_FIXEDSOURCE) {
|
||||
if (check_for_node(root, "create_fission_neutrons")) {
|
||||
create_fission_neutrons = get_node_value_bool(root, "create_fission_neutrons");
|
||||
}
|
||||
}
|
||||
|
||||
// Read remaining settings from Fortran side
|
||||
read_settings_xml_f(root.internal_object());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Fortran compatibility functions
|
||||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
const char* openmc_path_input() {
|
||||
return settings::path_input.c_str();
|
||||
}
|
||||
const char* openmc_path_statepoint() {
|
||||
return settings::path_statepoint.c_str();
|
||||
}
|
||||
const char* openmc_path_sourcepoint() {
|
||||
return settings::path_sourcepoint.c_str();
|
||||
}
|
||||
const char* openmc_path_particle_restart() {
|
||||
return settings::path_particle_restart.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ module simulation
|
|||
use cmfd_execute, only: cmfd_init_batch, cmfd_tally_init, execute_cmfd
|
||||
use cmfd_header, only: cmfd_on
|
||||
use constants, only: ZERO
|
||||
use eigenvalue, only: count_source_for_ufs, calculate_average_keff, &
|
||||
calculate_generation_keff, shannon_entropy, &
|
||||
use eigenvalue, only: calculate_average_keff, calculate_generation_keff, &
|
||||
synchronize_bank, keff_generation, k_sum
|
||||
#ifdef _OPENMP
|
||||
use eigenvalue, only: join_bank_from_threads
|
||||
|
|
@ -24,13 +23,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 +50,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
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -222,12 +233,17 @@ contains
|
|||
|
||||
subroutine initialize_generation()
|
||||
|
||||
interface
|
||||
subroutine ufs_count_sites() bind(C)
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
! Reset number of fission bank sites
|
||||
n_bank = 0
|
||||
|
||||
! Count source sites if using uniform fission source weighting
|
||||
if (ufs) call count_source_for_ufs()
|
||||
if (ufs) call ufs_count_sites()
|
||||
|
||||
! Store current value of tracklength k
|
||||
keff_generation = global_tallies(RESULT_VALUE, K_TRACKLENGTH)
|
||||
|
|
@ -241,7 +257,13 @@ contains
|
|||
|
||||
subroutine finalize_generation()
|
||||
|
||||
integer(8) :: i
|
||||
interface
|
||||
subroutine fill_source_bank_fixedsource() bind(C)
|
||||
end subroutine
|
||||
|
||||
subroutine shannon_entropy() bind(C)
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
! Update global tallies with the omp private accumulation variables
|
||||
!$omp parallel
|
||||
|
|
@ -294,13 +316,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
|
||||
|
|
@ -420,16 +436,14 @@ contains
|
|||
|
||||
integer :: i
|
||||
|
||||
interface
|
||||
subroutine openmc_simulation_init_c() bind(C)
|
||||
end subroutine openmc_simulation_init_c
|
||||
end interface
|
||||
|
||||
err = 0
|
||||
|
||||
! 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()
|
||||
|
||||
|
|
@ -455,13 +469,19 @@ contains
|
|||
! Allocate array for microscopic cross section cache
|
||||
allocate(micro_xs(n_nuclides))
|
||||
allocate(micro_photon_xs(n_elements))
|
||||
|
||||
! Allocate array for matching filter bins
|
||||
allocate(filter_matches(n_filters))
|
||||
do i = 1, n_filters
|
||||
filter_matches(i) % ptr = filter_match_pointer(i - 1)
|
||||
end do
|
||||
!$omp end parallel
|
||||
|
||||
! Reset global variables -- this is done before loading state point (as that
|
||||
! will potentially populate k_generation and entropy)
|
||||
current_batch = 0
|
||||
call k_generation % clear()
|
||||
call entropy % clear()
|
||||
call entropy_clear()
|
||||
need_depletion_rx = .false.
|
||||
|
||||
! If this is a restart run, load the state point data and binary source
|
||||
|
|
@ -495,16 +515,6 @@ contains
|
|||
end if
|
||||
end if
|
||||
|
||||
call openmc_simulation_init_c()
|
||||
|
||||
!$omp parallel
|
||||
! Allocate array for matching filter bins
|
||||
allocate(filter_matches(n_filters))
|
||||
do i = 1, n_filters
|
||||
filter_matches(i) % ptr = filter_match_pointer(i - 1)
|
||||
end do
|
||||
!$omp end parallel
|
||||
|
||||
! Set flag indicating initialization is done
|
||||
simulation_initialized = .true.
|
||||
|
||||
|
|
@ -523,7 +533,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
|
||||
|
|
@ -535,6 +544,9 @@ contains
|
|||
interface
|
||||
subroutine openmc_simulation_finalize_c() bind(C)
|
||||
end subroutine openmc_simulation_finalize_c
|
||||
|
||||
subroutine print_overlap_check() bind(C)
|
||||
end subroutine print_overlap_check
|
||||
end interface
|
||||
|
||||
err = 0
|
||||
|
|
@ -589,12 +601,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
|
||||
|
|
@ -615,8 +621,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,8 @@
|
|||
#include "openmc/simulation.h"
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/tallies/tally_filter.h"
|
||||
|
||||
// OPENMC_RUN encompasses all the main logic where iterations are performed
|
||||
|
|
@ -21,15 +25,52 @@ int openmc_run()
|
|||
|
||||
namespace openmc {
|
||||
|
||||
extern "C" void
|
||||
openmc_simulation_init_c()
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
std::vector<int64_t> work_index;
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
//==============================================================================
|
||||
|
||||
void openmc_simulation_init_c()
|
||||
{
|
||||
// Determine how much work each process should do
|
||||
calculate_work();
|
||||
|
||||
// Allocate array for matching filter bins
|
||||
#pragma omp parallel
|
||||
{
|
||||
filter_matches.resize(n_filters);
|
||||
}
|
||||
}
|
||||
|
||||
void calculate_work()
|
||||
{
|
||||
// Determine minimum amount of particles to simulate on each processor
|
||||
int64_t min_work = settings::n_particles / mpi::n_procs;
|
||||
|
||||
// Determine number of processors that have one extra particle
|
||||
int64_t remainder = settings::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);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
openmc_simulation_finalize_c()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
@ -47,13 +47,6 @@ module simulation_header
|
|||
real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength
|
||||
real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength
|
||||
|
||||
! Shannon entropy
|
||||
type(VectorReal) :: entropy ! shannon entropy at each generation
|
||||
real(8), allocatable :: entropy_p(:,:) ! % of source sites in each cell
|
||||
|
||||
! Uniform fission source weighting
|
||||
real(8), allocatable :: source_frac(:,:)
|
||||
|
||||
! ============================================================================
|
||||
! PARALLEL PROCESSING VARIABLES
|
||||
|
||||
|
|
@ -67,21 +60,24 @@ 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)
|
||||
|
||||
interface
|
||||
subroutine entropy_clear() bind(C)
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
|
||||
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,15 +86,12 @@ 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)
|
||||
|
||||
call k_generation % clear()
|
||||
call k_generation % shrink_to_fit()
|
||||
call entropy % clear()
|
||||
call entropy % shrink_to_fit()
|
||||
call entropy_clear()
|
||||
end subroutine free_memory_simulation
|
||||
|
||||
end module simulation_header
|
||||
|
|
|
|||
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
|
||||
379
src/source.cpp
Normal file
379
src/source.cpp
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
#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;
|
||||
settings::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
|
||||
settings::path_source = get_node_value(node, "file", false, true);
|
||||
|
||||
// Check if source file exists
|
||||
if (!file_exists(settings::path_source)) {
|
||||
std::stringstream msg;
|
||||
msg << "Source file '" << settings::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 (settings::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 " << settings::path_source << "...";
|
||||
write_message(msg, 6);
|
||||
|
||||
// Open the binary file
|
||||
hid_t file_id = file_open(settings::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*settings::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 (settings::write_initial_source) {
|
||||
write_message("Writing out initial source...", 5);
|
||||
std::string filename = settings::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 (!settings::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 (settings::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()) *
|
||||
settings::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
|
||||
|
|
@ -20,7 +20,6 @@ module state_point
|
|||
use endf, only: reaction_name
|
||||
use error, only: fatal_error, warning, write_message
|
||||
use hdf5_interface
|
||||
use mesh_header, only: RegularMesh, meshes, n_meshes
|
||||
use message_passing
|
||||
use mgxs_interface
|
||||
use nuclide_header, only: nuclides
|
||||
|
|
@ -68,7 +67,7 @@ contains
|
|||
integer :: i_xs
|
||||
integer, allocatable :: id_array(:)
|
||||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: cmfd_group, tallies_group, tally_group, meshes_group, &
|
||||
integer(HID_T) :: cmfd_group, tallies_group, tally_group, &
|
||||
filters_group, filter_group, derivs_group, &
|
||||
deriv_group, runtime_group
|
||||
integer(C_INT) :: ignored_err
|
||||
|
|
@ -79,6 +78,17 @@ contains
|
|||
character(MAX_WORD_LEN, kind=C_CHAR) :: temp_name
|
||||
logical :: parallel
|
||||
|
||||
interface
|
||||
subroutine meshes_to_hdf5(group) bind(C)
|
||||
import HID_T
|
||||
integer(HID_T), value :: group
|
||||
end subroutine
|
||||
subroutine entropy_to_hdf5(group) bind(C)
|
||||
import HID_T
|
||||
integer(HID_T), value :: group
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
err = 0
|
||||
|
||||
! Set the filename
|
||||
|
|
@ -163,9 +173,7 @@ contains
|
|||
call write_dataset(file_id, "generations_per_batch", gen_per_batch)
|
||||
k = k_generation % size()
|
||||
call write_dataset(file_id, "k_generation", k_generation % data(1:k))
|
||||
if (entropy_on) then
|
||||
call write_dataset(file_id, "entropy", entropy % data(1:k))
|
||||
end if
|
||||
call entropy_to_hdf5(file_id)
|
||||
call write_dataset(file_id, "k_col_abs", k_col_abs)
|
||||
call write_dataset(file_id, "k_col_tra", k_col_tra)
|
||||
call write_dataset(file_id, "k_abs_tra", k_abs_tra)
|
||||
|
|
@ -192,26 +200,8 @@ contains
|
|||
|
||||
tallies_group = create_group(file_id, "tallies")
|
||||
|
||||
! Write number of meshes
|
||||
meshes_group = create_group(tallies_group, "meshes")
|
||||
call write_attribute(meshes_group, "n_meshes", n_meshes)
|
||||
|
||||
if (n_meshes > 0) then
|
||||
! Write IDs of meshes
|
||||
allocate(id_array(n_meshes))
|
||||
do i = 1, n_meshes
|
||||
id_array(i) = meshes(i) % id
|
||||
end do
|
||||
call write_attribute(meshes_group, "ids", id_array)
|
||||
deallocate(id_array)
|
||||
|
||||
! Write information for meshes
|
||||
MESH_LOOP: do i = 1, n_meshes
|
||||
call meshes(i) % to_hdf5(meshes_group)
|
||||
end do MESH_LOOP
|
||||
end if
|
||||
|
||||
call close_group(meshes_group)
|
||||
! Write meshes
|
||||
call meshes_to_hdf5(tallies_group)
|
||||
|
||||
! Write information for derivatives.
|
||||
if (size(tally_derivs) > 0) then
|
||||
|
|
@ -641,6 +631,11 @@ contains
|
|||
logical :: source_present
|
||||
character(MAX_WORD_LEN) :: word
|
||||
|
||||
interface
|
||||
subroutine entropy_from_hdf5() bind(C)
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
! Write message
|
||||
call write_message("Loading state point " // trim(path_state_point) &
|
||||
// "...", 5)
|
||||
|
|
@ -722,10 +717,7 @@ contains
|
|||
call k_generation % resize(n)
|
||||
call read_dataset(k_generation % data(1:n), file_id, "k_generation")
|
||||
|
||||
if (entropy_on) then
|
||||
call entropy % resize(n)
|
||||
call read_dataset(entropy % data(1:n), file_id, "entropy")
|
||||
end if
|
||||
call entropy_from_hdf5()
|
||||
call read_dataset(k_col_abs, file_id, "k_col_abs")
|
||||
call read_dataset(k_col_tra, file_id, "k_col_tra")
|
||||
call read_dataset(k_abs_tra, file_id, "k_abs_tra")
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "openmc/capi.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/message_passing.h"
|
||||
#include "openmc/settings.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ write_source_bank(hid_t group_id, int64_t* work_index, Bank* source_bank)
|
|||
|
||||
#ifdef PHDF5
|
||||
// Set size of total dataspace for all procs and rank
|
||||
hsize_t dims[] {static_cast<hsize_t>(n_particles)};
|
||||
hsize_t dims[] {static_cast<hsize_t>(settings::n_particles)};
|
||||
hid_t dspace = H5Screate_simple(1, dims, nullptr);
|
||||
hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace,
|
||||
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
|
|
@ -69,7 +70,7 @@ write_source_bank(hid_t group_id, int64_t* work_index, Bank* source_bank)
|
|||
|
||||
if (openmc_master) {
|
||||
// Create dataset big enough to hold all source sites
|
||||
hsize_t dims[] {static_cast<hsize_t>(n_particles)};
|
||||
hsize_t dims[] {static_cast<hsize_t>(settings::n_particles)};
|
||||
hid_t dspace = H5Screate_simple(1, dims, nullptr);
|
||||
hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace,
|
||||
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ module stl_vector
|
|||
!
|
||||
! size -- Returns the number of elements in the vector.
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
implicit none
|
||||
private
|
||||
|
||||
|
|
@ -521,4 +523,28 @@ contains
|
|||
size = this%size_
|
||||
end function size_char
|
||||
|
||||
!===============================================================================
|
||||
! Procedures to be called from C++
|
||||
!===============================================================================
|
||||
|
||||
subroutine vector_int_push_back(ptr, val) bind(C)
|
||||
type(C_PTR), value :: ptr
|
||||
integer(C_INT), value :: val
|
||||
|
||||
type(VectorInt), pointer :: vec
|
||||
|
||||
call C_F_POINTER(ptr, vec)
|
||||
call vec % push_back(val)
|
||||
end subroutine
|
||||
|
||||
subroutine vector_real_push_back(ptr, val) bind(C)
|
||||
type(C_PTR), value :: ptr
|
||||
real(C_DOUBLE), value :: val
|
||||
|
||||
type(VectorReal), pointer :: vec
|
||||
|
||||
call C_F_POINTER(ptr, vec)
|
||||
call vec % push_back(val)
|
||||
end subroutine
|
||||
|
||||
end module stl_vector
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
158
src/summary.F90
158
src/summary.F90
|
|
@ -6,7 +6,6 @@ module summary
|
|||
use geometry_header
|
||||
use hdf5_interface
|
||||
use material_header, only: Material, n_materials, openmc_material_get_volume
|
||||
use mesh_header, only: RegularMesh
|
||||
use message_passing
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
|
|
@ -29,6 +28,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 +160,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();
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue