mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Merge remote-tracking branch 'upstream/develop' into capi_sourcepoint
This commit is contained in:
commit
ec67e25111
29 changed files with 981 additions and 551 deletions
|
|
@ -395,6 +395,7 @@ add_library(libopenmc SHARED
|
|||
src/mgxs_interface.cpp
|
||||
src/particle.cpp
|
||||
src/plot.cpp
|
||||
src/position.cpp
|
||||
src/pugixml/pugixml_c.cpp
|
||||
src/random_lcg.cpp
|
||||
src/scattdata.cpp
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ Constructing Tallies
|
|||
openmc.SpatialLegendreFilter
|
||||
openmc.SphericalHarmonicsFilter
|
||||
openmc.ZernikeFilter
|
||||
openmc.ZernikeRadialFilter
|
||||
openmc.ParticleFilter
|
||||
openmc.Mesh
|
||||
openmc.Trigger
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ __all__ = ['Filter', 'AzimuthalFilter', 'CellFilter',
|
|||
'EnergyFunctionFilter', 'LegendreFilter', 'MaterialFilter', 'MeshFilter',
|
||||
'MeshSurfaceFilter', 'MuFilter', 'PolarFilter', 'SphericalHarmonicsFilter',
|
||||
'SpatialLegendreFilter', 'SurfaceFilter',
|
||||
'UniverseFilter', 'ZernikeFilter', 'filters']
|
||||
'UniverseFilter', 'ZernikeFilter', 'ZernikeRadialFilter', 'filters']
|
||||
|
||||
# Tally functions
|
||||
_dll.openmc_cell_filter_get_bins.argtypes = [
|
||||
|
|
@ -360,6 +360,10 @@ class ZernikeFilter(Filter):
|
|||
_dll.openmc_zernike_filter_set_order(self._index, order)
|
||||
|
||||
|
||||
class ZernikeRadialFilter(ZernikeFilter):
|
||||
filter_type = 'zernikeradial'
|
||||
|
||||
|
||||
_FILTER_TYPE_MAP = {
|
||||
'azimuthal': AzimuthalFilter,
|
||||
'cell': CellFilter,
|
||||
|
|
@ -380,7 +384,8 @@ _FILTER_TYPE_MAP = {
|
|||
'spatiallegendre': SpatialLegendreFilter,
|
||||
'surface': SurfaceFilter,
|
||||
'universe': UniverseFilter,
|
||||
'zernike': ZernikeFilter
|
||||
'zernike': ZernikeFilter,
|
||||
'zernikeradial': ZernikeRadialFilter
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ _dll.calc_rn_c.argtypes = [c_int, ndpointer(c_double), ndpointer(c_double)]
|
|||
_dll.calc_zn_c.restype = None
|
||||
_dll.calc_zn_c.argtypes = [c_int, c_double, c_double, ndpointer(c_double)]
|
||||
|
||||
_dll.calc_zn_rad_c.restype = None
|
||||
_dll.calc_zn_rad_c.argtypes = [c_int, c_double, ndpointer(c_double)]
|
||||
|
||||
_dll.rotate_angle_c.restype = None
|
||||
_dll.rotate_angle_c.argtypes = [ndpointer(c_double), c_double,
|
||||
POINTER(c_double)]
|
||||
|
|
@ -155,6 +158,32 @@ def calc_zn(n, rho, phi):
|
|||
return zn
|
||||
|
||||
|
||||
def calc_zn_rad(n, rho):
|
||||
""" Calculate the even orders in n-th order modified Zernike polynomial
|
||||
moment with no azimuthal dependency (m=0) for a given radial location in
|
||||
the unit disk. The normalization of the polynomials is such that the
|
||||
integral of Z_pq*Z_pq over the unit disk is exactly pi.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : int
|
||||
Maximum order
|
||||
rho : float
|
||||
Radial location in the unit disk
|
||||
|
||||
Returns
|
||||
-------
|
||||
numpy.ndarray
|
||||
Corresponding resulting list of coefficients
|
||||
|
||||
"""
|
||||
|
||||
num_bins = n // 2 + 1
|
||||
zn_rad = np.zeros(num_bins, dtype=np.float64)
|
||||
_dll.calc_zn_rad_c(n, rho, zn_rad)
|
||||
return zn_rad
|
||||
|
||||
|
||||
def rotate_angle(uvw0, mu, phi=None):
|
||||
""" Rotates direction cosines through a polar angle whose cosine is
|
||||
mu and through an azimuthal angle sampled uniformly.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ _FILTER_TYPES = (
|
|||
'universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy',
|
||||
'energyout', 'mu', 'polar', 'azimuthal', 'distribcell', 'delayedgroup',
|
||||
'energyfunction', 'cellfrom', 'legendre', 'spatiallegendre',
|
||||
'sphericalharmonics', 'zernike', 'particle'
|
||||
'sphericalharmonics', 'zernike', 'zernikeradial', 'particle'
|
||||
)
|
||||
|
||||
_CURRENT_NAMES = (
|
||||
|
|
|
|||
|
|
@ -234,8 +234,8 @@ class SphericalHarmonicsFilter(ExpansionFilter):
|
|||
r"""Score spherical harmonic expansion moments up to specified order.
|
||||
|
||||
This filter allows you to obtain real spherical harmonic moments of either
|
||||
the particle's direction or the cosine of the scattering angle. Specifying a
|
||||
filter with order :math:`\ell` tallies moments for all orders from 0 to
|
||||
the particle's direction or the cosine of the scattering angle. Specifying
|
||||
a filter with order :math:`\ell` tallies moments for all orders from 0 to
|
||||
:math:`\ell`.
|
||||
|
||||
Parameters
|
||||
|
|
@ -342,11 +342,11 @@ 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 :math:`\epsilon_m` is
|
||||
2 if :math:`m` equals 0 and 1 otherwise.
|
||||
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 to
|
||||
N and each value of :math:`m`. The ordering of the Zernike polynomial
|
||||
Specifying a filter with order N tallies moments for all :math:`n` from 0
|
||||
to N and each value of :math:`m`. The ordering of the Zernike polynomial
|
||||
moments follows the ANSI Z80.28 standard, where the one-dimensional index
|
||||
:math:`j` corresponds to the :math:`n` and :math:`m` by
|
||||
|
||||
|
|
@ -463,3 +463,63 @@ class ZernikeFilter(ExpansionFilter):
|
|||
subelement.text = str(self.r)
|
||||
|
||||
return element
|
||||
|
||||
|
||||
class ZernikeRadialFilter(ZernikeFilter):
|
||||
r"""Score the :math:`m = 0` (radial variation only) Zernike moments up to
|
||||
specified order.
|
||||
|
||||
The Zernike polynomials are defined the same as in :class:`ZernikeFilter`.
|
||||
|
||||
.. math::
|
||||
|
||||
Z_n^{0}(\rho, \theta) = R_n^{0}(\rho)
|
||||
|
||||
where the radial polynomials are
|
||||
|
||||
.. math::
|
||||
R_n^{0}(\rho) = \sum\limits_{k=0}^{n/2} \frac{(-1)^k (n-k)!}{k! ((
|
||||
\frac{n}{2} - k)!)^{2}} \rho^{n-2k}.
|
||||
|
||||
With this definition, the integral of :math:`(Z_n^0)^2` over the unit disk
|
||||
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)
|
||||
= 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
|
||||
lowest even order (0) to highest even order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
order : int
|
||||
Maximum radial Zernike polynomial order
|
||||
x : float
|
||||
x-coordinate of center of circle for normalization
|
||||
y : float
|
||||
y-coordinate of center of circle for normalization
|
||||
r : int or None
|
||||
Radius of circle for normalization
|
||||
|
||||
Attributes
|
||||
----------
|
||||
order : int
|
||||
Maximum radial Zernike polynomial order
|
||||
x : float
|
||||
x-coordinate of center of circle for normalization
|
||||
y : float
|
||||
y-coordinate of center of circle for normalization
|
||||
r : int or None
|
||||
Radius of circle for normalization
|
||||
id : int
|
||||
Unique identifier for the filter
|
||||
num_bins : int
|
||||
The number of filter bins
|
||||
|
||||
"""
|
||||
|
||||
@ExpansionFilter.order.setter
|
||||
def order(self, order):
|
||||
ExpansionFilter.order.__set__(self, order)
|
||||
self.bins = ['Z{},0'.format(n) for n in range(0, order+1, 2)]
|
||||
|
|
|
|||
34
src/cell.cpp
34
src/cell.cpp
|
|
@ -279,33 +279,31 @@ Cell::Cell(pugi::xml_node cell_node)
|
|||
//==============================================================================
|
||||
|
||||
bool
|
||||
Cell::contains(const double xyz[3], const double uvw[3],
|
||||
int32_t on_surface) const
|
||||
Cell::contains(Position r, Direction u, int32_t on_surface) const
|
||||
{
|
||||
if (simple) {
|
||||
return contains_simple(xyz, uvw, on_surface);
|
||||
return contains_simple(r, u, on_surface);
|
||||
} else {
|
||||
return contains_complex(xyz, uvw, on_surface);
|
||||
return contains_complex(r, u, on_surface);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
std::pair<double, int32_t>
|
||||
Cell::distance(const double xyz[3], const double uvw[3],
|
||||
int32_t on_surface) const
|
||||
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) {
|
||||
// Ignore this token if it corresponds to an operator rather than a region.
|
||||
if (token >= OP_UNION) {continue;}
|
||||
if (token >= OP_UNION) continue;
|
||||
|
||||
// Calculate the distance to this surface.
|
||||
// Note the off-by-one indexing
|
||||
bool coincident {token == on_surface};
|
||||
double d {surfaces_c[abs(token)-1]->distance(xyz, uvw, coincident)};
|
||||
double d {surfaces_c[abs(token)-1]->distance(r, u, coincident)};
|
||||
|
||||
// Check if this distance is the new minimum.
|
||||
if (d < min_dist) {
|
||||
|
|
@ -356,8 +354,7 @@ Cell::to_hdf5(hid_t cell_group) const
|
|||
//==============================================================================
|
||||
|
||||
bool
|
||||
Cell::contains_simple(const double xyz[3], const double uvw[3],
|
||||
int32_t on_surface) const
|
||||
Cell::contains_simple(Position r, Direction u, int32_t on_surface) const
|
||||
{
|
||||
for (int32_t token : rpn) {
|
||||
if (token < OP_UNION) {
|
||||
|
|
@ -370,7 +367,7 @@ Cell::contains_simple(const double xyz[3], const double uvw[3],
|
|||
return false;
|
||||
} else {
|
||||
// Note the off-by-one indexing
|
||||
bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);
|
||||
bool sense = surfaces_c[abs(token)-1]->sense(r, u);
|
||||
if (sense != (token > 0)) {return false;}
|
||||
}
|
||||
}
|
||||
|
|
@ -381,8 +378,7 @@ Cell::contains_simple(const double xyz[3], const double uvw[3],
|
|||
//==============================================================================
|
||||
|
||||
bool
|
||||
Cell::contains_complex(const double xyz[3], const double uvw[3],
|
||||
int32_t on_surface) const
|
||||
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.
|
||||
|
|
@ -413,7 +409,7 @@ Cell::contains_complex(const double xyz[3], const double uvw[3],
|
|||
stack[i_stack] = false;
|
||||
} else {
|
||||
// Note the off-by-one indexing
|
||||
bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);;
|
||||
bool sense = surfaces_c[abs(token)-1]->sense(r, u);;
|
||||
stack[i_stack] = (sense == (token > 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -494,12 +490,18 @@ extern "C" {
|
|||
bool cell_simple(Cell *c) {return c->simple;}
|
||||
|
||||
bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface)
|
||||
{return c->contains(xyz, uvw, on_surface);}
|
||||
{
|
||||
Position r {xyz};
|
||||
Direction u {uvw};
|
||||
return c->contains(r, u, on_surface);
|
||||
}
|
||||
|
||||
void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface,
|
||||
double *min_dist, int32_t *i_surf)
|
||||
{
|
||||
std::pair<double, int32_t> out = c->distance(xyz, uvw, on_surface);
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
26
src/cell.h
26
src/cell.h
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef CELL_H
|
||||
#define CELL_H
|
||||
#ifndef OPENMC_CELL_H
|
||||
#define OPENMC_CELL_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
|
@ -9,6 +9,8 @@
|
|||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "position.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
|
|
@ -90,29 +92,27 @@ public:
|
|||
//! provides a performance benefit for the common case. In
|
||||
//! contains_complex, we evaluate the RPN expression using a stack, similar to
|
||||
//! how a RPN calculator would work.
|
||||
//! @param xyz[3] The 3D Cartesian coordinate to check.
|
||||
//! @param uvw[3] A direction used to "break ties" the coordinates are very
|
||||
//! \param r The 3D Cartesian coordinate to check.
|
||||
//! \param u A direction used to "break ties" the coordinates are very
|
||||
//! close to a surface.
|
||||
//! @param on_surface The signed index of a surface that the coordinate is
|
||||
//! \param on_surface The signed index of a surface that the coordinate is
|
||||
//! known to be on. This index takes precedence over surface sense
|
||||
//! calculations.
|
||||
bool
|
||||
contains(const double xyz[3], const double uvw[3], int32_t on_surface) const;
|
||||
contains(Position r, Direction u, int32_t on_surface) const;
|
||||
|
||||
//! Find the oncoming boundary of this cell.
|
||||
std::pair<double, int32_t>
|
||||
distance(const double xyz[3], const double uvw[3], int32_t on_surface) const;
|
||||
distance(Position r, Direction u, int32_t on_surface) const;
|
||||
|
||||
//! \brief Write cell information to an HDF5 group.
|
||||
//! @param group_id An HDF5 group id.
|
||||
//! \param group_id An HDF5 group id.
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
protected:
|
||||
bool contains_simple(const double xyz[3], const double uvw[3],
|
||||
int32_t on_surface) const;
|
||||
bool contains_complex(const double xyz[3], const double uvw[3],
|
||||
int32_t on_surface) const;
|
||||
bool contains_simple(Position r, Direction u, int32_t on_surface) const;
|
||||
bool contains_complex(Position r, Direction u, int32_t on_surface) const;
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
#endif // CELL_H
|
||||
#endif // OPENMC_CELL_H
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ module constants
|
|||
integer, parameter :: NO_BIN_FOUND = -1
|
||||
|
||||
! Tally filter and map types
|
||||
integer, parameter :: N_FILTER_TYPES = 21
|
||||
integer, parameter :: N_FILTER_TYPES = 22
|
||||
integer, parameter :: &
|
||||
FILTER_UNIVERSE = 1, &
|
||||
FILTER_MATERIAL = 2, &
|
||||
|
|
@ -379,7 +379,9 @@ module constants
|
|||
FILTER_SPH_HARMONICS = 18, &
|
||||
FILTER_SPTL_LEGENDRE = 19, &
|
||||
FILTER_ZERNIKE = 20, &
|
||||
FILTER_PARTICLE = 21
|
||||
FILTER_ZERNIKE_RADIAL = 21, &
|
||||
FILTER_PARTICLE = 22
|
||||
|
||||
|
||||
! Mesh types
|
||||
integer, parameter :: &
|
||||
|
|
|
|||
|
|
@ -380,7 +380,11 @@ contains
|
|||
|
||||
! Determine overall generation and number of active generations
|
||||
i = overall_generation()
|
||||
n = i - n_inactive*gen_per_batch
|
||||
if (current_batch > n_inactive) then
|
||||
n = gen_per_batch*n_realizations + current_gen
|
||||
else
|
||||
n = 0
|
||||
end if
|
||||
|
||||
if (n <= 0) then
|
||||
! For inactive generations, use current generation k as estimate for next
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
#ifndef GEOMETRY_H
|
||||
#define GEOMETRY_H
|
||||
#ifndef OPENMC_GEOMETRY_H
|
||||
#define OPENMC_GEOMETRY_H
|
||||
|
||||
namespace openmc {
|
||||
|
||||
extern "C" int openmc_root_universe;
|
||||
|
||||
#endif // GEOMETRY_H
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_GEOMETRY_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef HDF5_INTERFACE_H
|
||||
#define HDF5_INTERFACE_H
|
||||
#ifndef OPENMC_HDF5_INTERFACE_H
|
||||
#define OPENMC_HDF5_INTERFACE_H
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "hdf5_hl.h"
|
||||
|
|
@ -11,6 +11,8 @@
|
|||
#include <vector>
|
||||
#include <complex.h>
|
||||
|
||||
#include "position.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
|
|
@ -181,5 +183,12 @@ 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);
|
||||
}
|
||||
|
||||
inline void
|
||||
write_dataset(hid_t obj_id, const char* name, Position r)
|
||||
{
|
||||
std::array<double, 3> buffer {r.x, r.y, r.z};
|
||||
write_dataset(obj_id, name, buffer);
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
#endif //HDF5_INTERFACE_H
|
||||
#endif // OPENMC_HDF5_INTERFACE_H
|
||||
|
|
|
|||
158
src/lattice.cpp
158
src/lattice.cpp
|
|
@ -223,26 +223,23 @@ RectLattice::are_valid_indices(const int i_xyz[3]) const
|
|||
//==============================================================================
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
RectLattice::distance(const double xyz[3], const double uvw[3],
|
||||
const int i_xyz[3]) const
|
||||
RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
||||
{
|
||||
// Get short aliases to the coordinates.
|
||||
double x {xyz[0]};
|
||||
double y {xyz[1]};
|
||||
double z {xyz[2]};
|
||||
double u {uvw[0]};
|
||||
double v {uvw[1]};
|
||||
double x = r.x;
|
||||
double y = r.y;
|
||||
double z = r.z;
|
||||
|
||||
// Determine the oncoming edge.
|
||||
double x0 {copysign(0.5 * pitch[0], u)};
|
||||
double y0 {copysign(0.5 * pitch[1], v)};
|
||||
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};
|
||||
std::array<int, 3> lattice_trans;
|
||||
if ((std::abs(x - x0) > FP_PRECISION) && u != 0) {
|
||||
d = (x0 - x) / u;
|
||||
if (u > 0) {
|
||||
if ((std::abs(x - x0) > FP_PRECISION) && u.x != 0) {
|
||||
d = (x0 - x) / u.x;
|
||||
if (u.x > 0) {
|
||||
lattice_trans = {1, 0, 0};
|
||||
} else {
|
||||
lattice_trans = {-1, 0, 0};
|
||||
|
|
@ -250,11 +247,11 @@ RectLattice::distance(const double xyz[3], const double uvw[3],
|
|||
}
|
||||
|
||||
// Front and back sides
|
||||
if ((std::abs(y - y0) > FP_PRECISION) && v != 0) {
|
||||
double this_d = (y0 - y) / v;
|
||||
if ((std::abs(y - y0) > FP_PRECISION) && u.y != 0) {
|
||||
double this_d = (y0 - y) / u.y;
|
||||
if (this_d < d) {
|
||||
d = this_d;
|
||||
if (v > 0) {
|
||||
if (u.y > 0) {
|
||||
lattice_trans = {0, 1, 0};
|
||||
} else {
|
||||
lattice_trans = {0, -1, 0};
|
||||
|
|
@ -264,13 +261,12 @@ RectLattice::distance(const double xyz[3], const double uvw[3],
|
|||
|
||||
// Top and bottom sides
|
||||
if (is_3d) {
|
||||
double w {uvw[2]};
|
||||
double z0 {copysign(0.5 * pitch[2], w)};
|
||||
if ((std::abs(z - z0) > FP_PRECISION) && w != 0) {
|
||||
double this_d = (z0 - z) / w;
|
||||
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) {
|
||||
d = this_d;
|
||||
if (w > 0) {
|
||||
if (u.z > 0) {
|
||||
lattice_trans = {0, 0, 1};
|
||||
} else {
|
||||
lattice_trans = {0, 0, -1};
|
||||
|
|
@ -285,13 +281,13 @@ RectLattice::distance(const double xyz[3], const double uvw[3],
|
|||
//==============================================================================
|
||||
|
||||
std::array<int, 3>
|
||||
RectLattice::get_indices(const double xyz[3]) const
|
||||
RectLattice::get_indices(Position r) const
|
||||
{
|
||||
int ix {static_cast<int>(std::ceil((xyz[0] - lower_left[0]) / pitch[0]))-1};
|
||||
int iy {static_cast<int>(std::ceil((xyz[1] - lower_left[1]) / pitch[1]))-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((xyz[2] - lower_left[2]) / pitch[2]))-1;
|
||||
iz = static_cast<int>(std::ceil((r.z - lower_left.z) / pitch.z))-1;
|
||||
} else {
|
||||
iz = 0;
|
||||
}
|
||||
|
|
@ -300,18 +296,15 @@ RectLattice::get_indices(const double xyz[3]) const
|
|||
|
||||
//==============================================================================
|
||||
|
||||
std::array<double, 3>
|
||||
RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const
|
||||
Position
|
||||
RectLattice::get_local_position(Position r, const int i_xyz[3]) const
|
||||
{
|
||||
std::array<double, 3> local_xyz;
|
||||
local_xyz[0] = global_xyz[0] - (lower_left[0] + (i_xyz[0] + 0.5)*pitch[0]);
|
||||
local_xyz[1] = global_xyz[1] - (lower_left[1] + (i_xyz[1] + 0.5)*pitch[1]);
|
||||
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) {
|
||||
local_xyz[2] = global_xyz[2] - (lower_left[2] + (i_xyz[2] + 0.5)*pitch[2]);
|
||||
} else {
|
||||
local_xyz[2] = global_xyz[2];
|
||||
r.z -= (lower_left.z + (i_xyz[2] + 0.5)*pitch.z);
|
||||
}
|
||||
return local_xyz;
|
||||
return r;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -583,12 +576,11 @@ HexLattice::are_valid_indices(const int i_xyz[3]) const
|
|||
//==============================================================================
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
HexLattice::distance(const double xyz[3], const double uvw[3],
|
||||
const int i_xyz[3]) const
|
||||
HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const
|
||||
{
|
||||
// Compute the direction on the hexagonal basis.
|
||||
double beta_dir = uvw[0] * std::sqrt(3.0) / 2.0 + uvw[1] / 2.0;
|
||||
double gamma_dir = uvw[0] * std::sqrt(3.0) / 2.0 - uvw[1] / 2.0;
|
||||
double beta_dir = u.x * std::sqrt(3.0) / 2.0 + u.y / 2.0;
|
||||
double gamma_dir = u.x * std::sqrt(3.0) / 2.0 - u.y / 2.0;
|
||||
|
||||
// Note that hexagonal lattice distance calculations are performed
|
||||
// using the particle's coordinates relative to the neighbor lattice
|
||||
|
|
@ -600,15 +592,15 @@ HexLattice::distance(const double xyz[3], const double uvw[3],
|
|||
double d {INFTY};
|
||||
std::array<int, 3> lattice_trans;
|
||||
double edge = -copysign(0.5*pitch[0], beta_dir); // Oncoming edge
|
||||
std::array<double, 3> xyz_t;
|
||||
Position r_t;
|
||||
if (beta_dir > 0) {
|
||||
const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1], i_xyz[2]};
|
||||
xyz_t = get_local_xyz(xyz, i_xyz_t);
|
||||
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]};
|
||||
xyz_t = get_local_xyz(xyz, i_xyz_t);
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
}
|
||||
double beta = xyz_t[0] * std::sqrt(3.0) / 2.0 + xyz_t[1] / 2.0;
|
||||
double beta = r_t.x * std::sqrt(3.0) / 2.0 + r_t.y / 2.0;
|
||||
if ((std::abs(beta - edge) > FP_PRECISION) && beta_dir != 0) {
|
||||
d = (edge - beta) / beta_dir;
|
||||
if (beta_dir > 0) {
|
||||
|
|
@ -622,12 +614,12 @@ HexLattice::distance(const double xyz[3], const double uvw[3],
|
|||
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]};
|
||||
xyz_t = get_local_xyz(xyz, i_xyz_t);
|
||||
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]};
|
||||
xyz_t = get_local_xyz(xyz, i_xyz_t);
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
}
|
||||
double gamma = xyz_t[0] * std::sqrt(3.0) / 2.0 - xyz_t[1] / 2.0;
|
||||
double gamma = r_t.x * std::sqrt(3.0) / 2.0 - r_t.y / 2.0;
|
||||
if ((std::abs(gamma - edge) > FP_PRECISION) && gamma_dir != 0) {
|
||||
double this_d = (edge - gamma) / gamma_dir;
|
||||
if (this_d < d) {
|
||||
|
|
@ -641,18 +633,18 @@ HexLattice::distance(const double xyz[3], const double uvw[3],
|
|||
}
|
||||
|
||||
// Upper and lower sides.
|
||||
edge = -copysign(0.5*pitch[0], uvw[1]);
|
||||
if (uvw[1] > 0) {
|
||||
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]};
|
||||
xyz_t = get_local_xyz(xyz, i_xyz_t);
|
||||
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]};
|
||||
xyz_t = get_local_xyz(xyz, i_xyz_t);
|
||||
r_t = get_local_position(r, i_xyz_t);
|
||||
}
|
||||
if ((std::abs(xyz_t[1] - edge) > FP_PRECISION) && uvw[1] != 0) {
|
||||
double this_d = (edge - xyz_t[1]) / uvw[1];
|
||||
if ((std::abs(r_t.y - edge) > FP_PRECISION) && u.y != 0) {
|
||||
double this_d = (edge - r_t.y) / u.y;
|
||||
if (this_d < d) {
|
||||
if (uvw[1] > 0) {
|
||||
if (u.y > 0) {
|
||||
lattice_trans = {0, 1, 0};
|
||||
} else {
|
||||
lattice_trans = {0, -1, 0};
|
||||
|
|
@ -663,14 +655,13 @@ HexLattice::distance(const double xyz[3], const double uvw[3],
|
|||
|
||||
// Top and bottom sides
|
||||
if (is_3d) {
|
||||
double z {xyz[2]};
|
||||
double w {uvw[2]};
|
||||
double z0 {copysign(0.5 * pitch[1], w)};
|
||||
if ((std::abs(z - z0) > FP_PRECISION) && w != 0) {
|
||||
double this_d = (z0 - z) / w;
|
||||
double z = r.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) {
|
||||
d = this_d;
|
||||
if (w > 0) {
|
||||
if (u.z > 0) {
|
||||
lattice_trans = {0, 0, 1};
|
||||
} else {
|
||||
lattice_trans = {0, 0, -1};
|
||||
|
|
@ -686,24 +677,24 @@ HexLattice::distance(const double xyz[3], const double uvw[3],
|
|||
//==============================================================================
|
||||
|
||||
std::array<int, 3>
|
||||
HexLattice::get_indices(const double xyz[3]) const
|
||||
HexLattice::get_indices(Position r) const
|
||||
{
|
||||
// Offset the xyz by the lattice center.
|
||||
double xyz_o[3] {xyz[0] - center[0], xyz[1] - center[1], xyz[2]};
|
||||
if (is_3d) {xyz_o[2] -= center[2];}
|
||||
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(xyz_o[2] / pitch[1] + 0.5 * n_axial))-1;
|
||||
out[2] = static_cast<int>(std::ceil(r_o.z / pitch[1] + 0.5 * n_axial))-1;
|
||||
} else {
|
||||
out[2] = 0;
|
||||
}
|
||||
|
||||
// Convert coordinates into skewed bases. The (x, alpha) basis is used to
|
||||
// find the index of the global coordinates to within 4 cells.
|
||||
double alpha = xyz_o[1] - xyz_o[0] / std::sqrt(3.0);
|
||||
out[0] = static_cast<int>(std::floor(xyz_o[0]
|
||||
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]));
|
||||
|
||||
|
|
@ -725,8 +716,8 @@ HexLattice::get_indices(const double xyz[3]) const
|
|||
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};
|
||||
std::array<double, 3> xyz_t = get_local_xyz(xyz, i_xyz);
|
||||
double d = xyz_t[0]*xyz_t[0] + xyz_t[1]*xyz_t[1];
|
||||
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) {
|
||||
d_min = d;
|
||||
k_min = k;
|
||||
|
|
@ -751,26 +742,19 @@ HexLattice::get_indices(const double xyz[3]) const
|
|||
|
||||
//==============================================================================
|
||||
|
||||
std::array<double, 3>
|
||||
HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const
|
||||
Position
|
||||
HexLattice::get_local_position(Position r, const int i_xyz[3]) const
|
||||
{
|
||||
std::array<double, 3> local_xyz;
|
||||
|
||||
// x_l = x_g - (center + pitch_x*cos(30)*index_x)
|
||||
local_xyz[0] = global_xyz[0] - (center[0]
|
||||
+ 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)
|
||||
local_xyz[1] = global_xyz[1] - (center[1]
|
||||
+ (i_xyz[1] - n_rings + 1) * pitch[0]
|
||||
+ (i_xyz[0] - n_rings + 1) * pitch[0] / 2.0);
|
||||
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) {
|
||||
local_xyz[2] = global_xyz[2] - center[2]
|
||||
+ (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1];
|
||||
} else {
|
||||
local_xyz[2] = global_xyz[2];
|
||||
r.z -= center.z - (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1];
|
||||
}
|
||||
|
||||
return local_xyz;
|
||||
return r;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -908,7 +892,9 @@ extern "C" {
|
|||
void lattice_distance(Lattice *lat, const double xyz[3], const double uvw[3],
|
||||
const int i_xyz[3], double *d, int lattice_trans[3])
|
||||
{
|
||||
std::pair<double, std::array<int, 3>> ld {lat->distance(xyz, uvw, i_xyz)};
|
||||
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];
|
||||
|
|
@ -917,7 +903,8 @@ extern "C" {
|
|||
|
||||
void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3])
|
||||
{
|
||||
std::array<int, 3> inds = lat->get_indices(xyz);
|
||||
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];
|
||||
|
|
@ -926,10 +913,11 @@ extern "C" {
|
|||
void lattice_get_local_xyz(Lattice *lat, const double global_xyz[3],
|
||||
const int i_xyz[3], double local_xyz[3])
|
||||
{
|
||||
std::array<double, 3> xyz = lat->get_local_xyz(global_xyz, i_xyz);
|
||||
local_xyz[0] = xyz[0];
|
||||
local_xyz[1] = xyz[1];
|
||||
local_xyz[2] = xyz[2];
|
||||
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])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef LATTICE_H
|
||||
#define LATTICE_H
|
||||
#ifndef OPENMC_LATTICE_H
|
||||
#define OPENMC_LATTICE_H
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
|
@ -7,10 +7,12 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "constants.h"
|
||||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "constants.h"
|
||||
#include "position.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
|
|
@ -69,54 +71,54 @@ public:
|
|||
int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map);
|
||||
|
||||
//! \brief Check lattice indices.
|
||||
//! @param i_xyz[3] The indices for a lattice tile.
|
||||
//! @return true if the given indices fit within the lattice bounds. False
|
||||
//! \param i_xyz[3] The indices for a lattice tile.
|
||||
//! \return true if the given indices fit within the lattice bounds. False
|
||||
//! otherwise.
|
||||
virtual bool are_valid_indices(const int i_xyz[3]) const = 0;
|
||||
|
||||
//! \brief Find the next lattice surface crossing
|
||||
//! @param xyz[3] A 3D Cartesian coordinate.
|
||||
//! @param uvw[3] A 3D Cartesian direction.
|
||||
//! @param i_xyz[3] The indices for a lattice tile.
|
||||
//! @return The distance to the next crossing and an array indicating how the
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \param u A 3D Cartesian direction.
|
||||
//! \param i_xyz[3] 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(const double xyz[3], const double uvw[3], const int i_xyz[3]) const
|
||||
distance(Position r, Direction u, const int i_xyz[3]) const
|
||||
= 0;
|
||||
|
||||
//! \brief Find the lattice tile indices for a given point.
|
||||
//! @param xyz[3] A 3D Cartesian coordinate.
|
||||
//! @return An array containing the indices of a lattice tile.
|
||||
virtual std::array<int, 3> get_indices(const double xyz[3]) const = 0;
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \return An array containing the indices of a lattice tile.
|
||||
virtual std::array<int, 3> get_indices(Position r) const = 0;
|
||||
|
||||
//! \brief Get coordinates local to a lattice tile.
|
||||
//! @param global_xyz[3] A 3D Cartesian coordinate.
|
||||
//! @param i_xyz[3] The indices for a lattice tile.
|
||||
//! @return Local 3D Cartesian coordinates.
|
||||
virtual std::array<double, 3>
|
||||
get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const = 0;
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \param i_xyz[3] 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;
|
||||
|
||||
//! \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
|
||||
//! \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());}
|
||||
|
||||
//! \brief Get the distribcell offset for a lattice tile.
|
||||
//! @param The map index for the target cell.
|
||||
//! @param i_xyz[3] The indices for a lattice tile.
|
||||
//! @return Distribcell offset i.e. the largest instance number for the target
|
||||
//! \param The map index for the target cell.
|
||||
//! \param i_xyz[3] The indices for a lattice tile.
|
||||
//! \return Distribcell offset i.e. the largest instance number for the target
|
||||
//! cell found in the geometry tree under this lattice tile.
|
||||
virtual int32_t& offset(int map, const int i_xyz[3]) = 0;
|
||||
|
||||
//! \brief Convert an array index to a useful human-readable string.
|
||||
//! @param indx The index for a lattice tile.
|
||||
//! @return A string representing the lattice tile.
|
||||
//! \param indx The index for a lattice tile.
|
||||
//! \return A string representing the lattice tile.
|
||||
virtual std::string index_to_string(int indx) const = 0;
|
||||
|
||||
//! \brief Write lattice information to an HDF5 group.
|
||||
//! @param group_id An HDF5 group id.
|
||||
//! \param group_id An HDF5 group id.
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
protected:
|
||||
|
|
@ -193,12 +195,12 @@ public:
|
|||
bool are_valid_indices(const int i_xyz[3]) const;
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const;
|
||||
distance(Position r, Direction u, const int i_xyz[3]) const;
|
||||
|
||||
std::array<int, 3> get_indices(const double xyz[3]) const;
|
||||
std::array<int, 3> get_indices(Position r) const;
|
||||
|
||||
std::array<double, 3>
|
||||
get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const;
|
||||
Position
|
||||
get_local_position(Position r, const int i_xyz[3]) const;
|
||||
|
||||
int32_t& offset(int map, const int i_xyz[3]);
|
||||
|
||||
|
|
@ -207,9 +209,9 @@ public:
|
|||
void to_hdf5_inner(hid_t group_id) const;
|
||||
|
||||
private:
|
||||
std::array<int, 3> n_cells; //!< Number of cells along each axis
|
||||
std::array<double, 3> lower_left; //!< Global lower-left corner of the lattice
|
||||
std::array<double, 3> 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]};
|
||||
|
|
@ -233,12 +235,12 @@ public:
|
|||
bool are_valid_indices(const int i_xyz[3]) const;
|
||||
|
||||
std::pair<double, std::array<int, 3>>
|
||||
distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const;
|
||||
distance(Position r, Direction u, const int i_xyz[3]) const;
|
||||
|
||||
std::array<int, 3> get_indices(const double xyz[3]) const;
|
||||
std::array<int, 3> get_indices(Position r) const;
|
||||
|
||||
std::array<double, 3>
|
||||
get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const;
|
||||
Position
|
||||
get_local_position(Position r, const int i_xyz[3]) const;
|
||||
|
||||
bool is_valid_index(int indx) const;
|
||||
|
||||
|
|
@ -251,9 +253,9 @@ public:
|
|||
private:
|
||||
int n_rings; //!< Number of radial tile positions
|
||||
int n_axial; //!< Number of axial tile positions
|
||||
std::array<double, 3> center; //!< Global center of lattice
|
||||
Position center; //!< Global center of lattice
|
||||
std::array<double, 2> pitch; //!< Lattice tile width and height
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
#endif // LATTICE_H
|
||||
#endif // OPENMC_LATTICE_H
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module math
|
|||
public :: calc_pn
|
||||
public :: calc_rn
|
||||
public :: calc_zn
|
||||
public :: calc_zn_rad
|
||||
public :: evaluate_legendre
|
||||
public :: rotate_angle
|
||||
public :: maxwell_spectrum
|
||||
|
|
@ -68,6 +69,14 @@ module math
|
|||
real(C_DOUBLE), intent(out) :: zn(((n + 1) * (n + 2)) / 2)
|
||||
end subroutine calc_zn
|
||||
|
||||
pure subroutine calc_zn_rad(n, rho, zn_rad) bind(C, name='calc_zn_rad_c')
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: n
|
||||
real(C_DOUBLE), value, intent(in) :: rho
|
||||
real(C_DOUBLE), intent(out) :: zn_rad((n / 2) + 1)
|
||||
end subroutine calc_zn_rad
|
||||
|
||||
subroutine rotate_angle_c_intfc(uvw, mu, phi) bind(C, name='rotate_angle_c')
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
|
|
|
|||
|
|
@ -587,6 +587,33 @@ void calc_zn_c(int n, double rho, double phi, double zn[]) {
|
|||
|
||||
}
|
||||
|
||||
void calc_zn_rad_c(int n, double rho, double zn_rad[]) {
|
||||
// Calculate R_p0(rho) as Zn_p0(rho)
|
||||
// Set up the array of the coefficients
|
||||
|
||||
double q = 0;
|
||||
|
||||
// R_00 is always 1
|
||||
zn_rad[0] = 1;
|
||||
|
||||
// Fill in the rest of the array (Eq 3.8 and Eq 3.10 in Chong)
|
||||
for (int p = 2; p <= n; p += 2) {
|
||||
int index = int(p/2);
|
||||
if (p == 2) {
|
||||
// Setting up R_22 to calculate R_20 (Eq 3.10 in Chong)
|
||||
double R_22 = rho * rho;
|
||||
zn_rad[index] = 2 * R_22 - zn_rad[0];
|
||||
} else {
|
||||
double k1 = ((p + q) * (p - q) * (p - 2)) / 2.;
|
||||
double k2 = 2 * p * (p - 1) * (p - 2);
|
||||
double k3 = -q * q * (p - 1) - p * (p - 1) * (p - 2);
|
||||
double k4 = (-p * (p + q - 2) * (p - q - 2)) / 2.;
|
||||
zn_rad[index] =
|
||||
((k2 * rho * rho + k3) * zn_rad[index-1] + k4 * zn_rad[index-2]) / k1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rotate_angle_c(double uvw[3], double mu, double* phi) {
|
||||
// Copy original directional cosines
|
||||
|
|
|
|||
|
|
@ -91,6 +91,24 @@ extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]);
|
|||
|
||||
extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]);
|
||||
|
||||
//==============================================================================
|
||||
//! Calculate only the even order components of n-th order modified Zernike
|
||||
//! polynomial moment with azimuthal dependency m = 0 for a given radial (rho)
|
||||
//! location on the unit disk.
|
||||
//!
|
||||
//! Since m = 0, n could only be even orders. Z_q0 = R_q0
|
||||
//!
|
||||
//! See calc_zn_c for methodology.
|
||||
//!
|
||||
//! @param n The maximum order requested
|
||||
//! @param rho The radial parameter to specify location on the unit disk
|
||||
//! @param phi The angle parameter to specify location on the unit disk
|
||||
//! @param zn_rad The requested moments of order 0 to n (inclusive)
|
||||
//! evaluated at rho and phi when m = 0.
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void calc_zn_rad_c(int n, double rho, double zn_rad[]);
|
||||
|
||||
//==============================================================================
|
||||
//! Rotate the direction cosines through a polar angle whose cosine is mu and
|
||||
//! through an azimuthal angle sampled uniformly.
|
||||
|
|
|
|||
|
|
@ -324,7 +324,11 @@ contains
|
|||
|
||||
! Determine overall generation and number of active generations
|
||||
i = overall_generation()
|
||||
n = i - n_inactive*gen_per_batch
|
||||
if (current_batch > n_inactive) then
|
||||
n = gen_per_batch*n_realizations + current_gen
|
||||
else
|
||||
n = 0
|
||||
end if
|
||||
|
||||
! write out information about batch and generation
|
||||
write(UNIT=OUTPUT_UNIT, FMT='(2X,A9)', ADVANCE='NO') &
|
||||
|
|
@ -357,7 +361,7 @@ contains
|
|||
|
||||
! Determine overall generation and number of active generations
|
||||
i = current_batch*gen_per_batch
|
||||
n = i - n_inactive*gen_per_batch
|
||||
n = n_realizations*gen_per_batch
|
||||
|
||||
! write out information batch and option independent output
|
||||
write(UNIT=OUTPUT_UNIT, FMT='(2X,A9)', ADVANCE='NO') &
|
||||
|
|
|
|||
63
src/position.cpp
Normal file
63
src/position.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#include "position.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Position implementation
|
||||
//==============================================================================
|
||||
|
||||
Position&
|
||||
Position::operator+=(Position other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Position&
|
||||
Position::operator+=(double v)
|
||||
{
|
||||
x += v;
|
||||
y += v;
|
||||
z += v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Position&
|
||||
Position::operator-=(Position other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Position&
|
||||
Position::operator-=(double v)
|
||||
{
|
||||
x -= v;
|
||||
y -= v;
|
||||
z -= v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Position&
|
||||
Position::operator*=(Position other)
|
||||
{
|
||||
x *= other.x;
|
||||
y *= other.y;
|
||||
z *= other.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Position&
|
||||
Position::operator*=(double v)
|
||||
{
|
||||
x *= v;
|
||||
y *= v;
|
||||
z *= v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
74
src/position.h
Normal file
74
src/position.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef OPENMC_POSITION_H
|
||||
#define OPENMC_POSITION_H
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
//! Type representing a position in Cartesian coordinates
|
||||
//==============================================================================
|
||||
|
||||
struct Position {
|
||||
// Constructors
|
||||
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]} { };
|
||||
|
||||
// Unary operators
|
||||
Position& operator+=(Position);
|
||||
Position& operator+=(double);
|
||||
Position& operator-=(Position);
|
||||
Position& operator-=(double);
|
||||
Position& operator*=(Position);
|
||||
Position& operator*=(double);
|
||||
const double& operator[](int i) const {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
}
|
||||
}
|
||||
double& operator[](int i) {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
}
|
||||
}
|
||||
|
||||
// Other member functions
|
||||
|
||||
//! Dot product of two vectors
|
||||
//! \param[in] other Vector to take dot product with
|
||||
//! \result Resulting dot product
|
||||
inline double dot(Position other) {
|
||||
return x*other.x + y*other.y + z*other.z;
|
||||
}
|
||||
|
||||
// Data members
|
||||
double x = 0.;
|
||||
double y = 0.;
|
||||
double z = 0.;
|
||||
};
|
||||
|
||||
// Binary operators
|
||||
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 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 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; }
|
||||
|
||||
//==============================================================================
|
||||
//! Type representing a vector direction in Cartesian coordinates
|
||||
//==============================================================================
|
||||
|
||||
using Direction = Position;
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_POSITION_H
|
||||
|
|
@ -397,6 +397,13 @@ contains
|
|||
end do
|
||||
end if
|
||||
|
||||
! Increment n_realizations as would ordinarily be done in finalize_batch
|
||||
if (reduce_tallies) then
|
||||
n_realizations = n_realizations + 1
|
||||
else
|
||||
n_realizations = n_realizations + n_procs
|
||||
end if
|
||||
|
||||
! Write message at end
|
||||
if (current_batch == restart_batch) then
|
||||
call write_message("Resuming simulation...", 6)
|
||||
|
|
@ -460,6 +467,19 @@ contains
|
|||
call initialize_source()
|
||||
end if
|
||||
|
||||
! In restart, set the batch to begin from in order to reproduce the correct
|
||||
! average keff (used in sampling the fission bank). Use n_realizations from
|
||||
! the statepoint rather than n_inactive in case openmc_reset was called in
|
||||
! the previous run.
|
||||
if (restart_run) then
|
||||
if (reduce_tallies) then
|
||||
current_batch = restart_batch - n_realizations
|
||||
else
|
||||
current_batch = restart_batch - n_realizations*n_procs
|
||||
end if
|
||||
n_realizations = 0
|
||||
end if
|
||||
|
||||
! Display header
|
||||
if (master) then
|
||||
if (run_mode == MODE_FIXEDSOURCE) then
|
||||
|
|
|
|||
|
|
@ -754,6 +754,9 @@ contains
|
|||
end if
|
||||
end if
|
||||
|
||||
! Read number of realizations for global tallies
|
||||
call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.)
|
||||
|
||||
! Check to make sure source bank is present
|
||||
if (path_source_point == path_state_point .and. .not. source_present) then
|
||||
call fatal_error("Source bank must be contained in statepoint restart &
|
||||
|
|
@ -767,10 +770,6 @@ contains
|
|||
#else
|
||||
if (master) then
|
||||
#endif
|
||||
|
||||
! Read number of realizations for global tallies
|
||||
call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.)
|
||||
|
||||
! Read global tally data
|
||||
call read_dataset(global_tallies, file_id, "global_tallies")
|
||||
|
||||
|
|
|
|||
483
src/surface.cpp
483
src/surface.cpp
|
|
@ -3,6 +3,7 @@
|
|||
#include <array>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "error.h"
|
||||
#include "hdf5_interface.h"
|
||||
|
|
@ -177,38 +178,33 @@ Surface::Surface(pugi::xml_node surf_node)
|
|||
}
|
||||
|
||||
bool
|
||||
Surface::sense(const double xyz[3], const double uvw[3]) const
|
||||
Surface::sense(Position r, Direction u) const
|
||||
{
|
||||
// Evaluate the surface equation at the particle's coordinates to determine
|
||||
// which side the particle is on.
|
||||
const double f = evaluate(xyz);
|
||||
const double f = evaluate(r);
|
||||
|
||||
// Check which side of surface the point is on.
|
||||
if (std::abs(f) < FP_COINCIDENT) {
|
||||
// Particle may be coincident with this surface. To determine the sense, we
|
||||
// look at the direction of the particle relative to the surface normal (by
|
||||
// default in the positive direction) via their dot product.
|
||||
double norm[3];
|
||||
normal(xyz, norm);
|
||||
return uvw[0] * norm[0] + uvw[1] * norm[1] + uvw[2] * norm[2] > 0.0;
|
||||
return u.dot(normal(r)) > 0.0;
|
||||
}
|
||||
return f > 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
Surface::reflect(const double xyz[3], double uvw[3]) const
|
||||
Direction
|
||||
Surface::reflect(Position r, Direction u) const
|
||||
{
|
||||
// Determine projection of direction onto normal and squared magnitude of
|
||||
// normal.
|
||||
double norm[3];
|
||||
normal(xyz, norm);
|
||||
const double projection = norm[0]*uvw[0] + norm[1]*uvw[1] + norm[2]*uvw[2];
|
||||
const double magnitude = norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2];
|
||||
Direction n = normal(r);
|
||||
const double projection = n.dot(u);
|
||||
const double magnitude = n.dot(n);
|
||||
|
||||
// Reflect direction according to normal.
|
||||
uvw[0] -= 2.0 * projection / magnitude * norm[0];
|
||||
uvw[1] -= 2.0 * projection / magnitude * norm[1];
|
||||
uvw[2] -= 2.0 * projection / magnitude * norm[2];
|
||||
return u -= (2.0 * projection / magnitude) * n;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -261,33 +257,15 @@ PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node)
|
|||
|
||||
// The template parameter indicates the axis normal to the plane.
|
||||
template<int i> double
|
||||
axis_aligned_plane_evaluate(const double xyz[3], double offset)
|
||||
axis_aligned_plane_distance(Position r, Direction u, bool coincident, double offset)
|
||||
{
|
||||
return xyz[i] - offset;
|
||||
}
|
||||
|
||||
// The template parameter indicates the axis normal to the plane.
|
||||
template<int i> double
|
||||
axis_aligned_plane_distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident, double offset)
|
||||
{
|
||||
const double f = offset - xyz[i];
|
||||
if (coincident or std::abs(f) < FP_COINCIDENT or uvw[i] == 0.0) return INFTY;
|
||||
const double d = f / uvw[i];
|
||||
const double f = offset - r[i];
|
||||
if (coincident or std::abs(f) < FP_COINCIDENT or u[i] == 0.0) return INFTY;
|
||||
const double d = f / u[i];
|
||||
if (d < 0.0) return INFTY;
|
||||
return d;
|
||||
}
|
||||
|
||||
// The first template parameter indicates the axis normal to the plane. The
|
||||
// other two parameters indicate the other two axes.
|
||||
template<int i1, int i2, int i3> void
|
||||
axis_aligned_plane_normal(const double xyz[3], double uvw[3])
|
||||
{
|
||||
uvw[i1] = 1.0;
|
||||
uvw[i2] = 0.0;
|
||||
uvw[i3] = 0.0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// SurfaceXPlane implementation
|
||||
//==============================================================================
|
||||
|
|
@ -298,20 +276,19 @@ SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node)
|
|||
read_coeffs(surf_node, id, x0);
|
||||
}
|
||||
|
||||
inline double SurfaceXPlane::evaluate(const double xyz[3]) const
|
||||
double SurfaceXPlane::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_plane_evaluate<0>(xyz, x0);
|
||||
return r.x - x0;
|
||||
}
|
||||
|
||||
inline double SurfaceXPlane::distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const
|
||||
double SurfaceXPlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_plane_distance<0>(xyz, uvw, coincident, x0);
|
||||
return axis_aligned_plane_distance<0>(r, u, coincident, x0);
|
||||
}
|
||||
|
||||
inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceXPlane::normal(Position r) const
|
||||
{
|
||||
axis_aligned_plane_normal<0, 1, 2>(xyz, uvw);
|
||||
return {1., 0., 0.};
|
||||
}
|
||||
|
||||
void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const
|
||||
|
|
@ -321,26 +298,24 @@ void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const
|
|||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
||||
double uvw[3]) const
|
||||
bool SurfaceXPlane::periodic_translate(const PeriodicSurface *other, Position& r,
|
||||
Direction& u) const
|
||||
{
|
||||
double other_norm[3];
|
||||
other->normal(xyz, other_norm);
|
||||
if (other_norm[0] == 1 and other_norm[1] == 0 and other_norm[2] == 0) {
|
||||
xyz[0] = x0;
|
||||
Direction other_n = other->normal(r);
|
||||
if (other_n.x == 1 and other_n.y == 0 and other_n.z == 0) {
|
||||
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 xyz and uvw for rotational
|
||||
// evaluate function to find y0, then adjust position/Direction for rotational
|
||||
// symmetry.
|
||||
double xyz_test[3] {0, 0, 0};
|
||||
double y0 = -other->evaluate(xyz_test);
|
||||
xyz[1] = xyz[0] - x0 + y0;
|
||||
xyz[0] = x0;
|
||||
double y0 = -other->evaluate({0., 0., 0.});
|
||||
r.y = r.x - x0 + y0;
|
||||
r.x = x0;
|
||||
|
||||
double u = uvw[0];
|
||||
uvw[0] = -uvw[1];
|
||||
uvw[1] = u;
|
||||
double ux = u.x;
|
||||
u.x = -u.y;
|
||||
u.y = ux;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -349,8 +324,7 @@ bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
|||
BoundingBox
|
||||
SurfaceXPlane::bounding_box() const
|
||||
{
|
||||
BoundingBox out {x0, x0, -INFTY, INFTY, -INFTY, INFTY};
|
||||
return out;
|
||||
return {x0, x0, -INFTY, INFTY, -INFTY, INFTY};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -363,20 +337,19 @@ SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node)
|
|||
read_coeffs(surf_node, id, y0);
|
||||
}
|
||||
|
||||
inline double SurfaceYPlane::evaluate(const double xyz[3]) const
|
||||
double SurfaceYPlane::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_plane_evaluate<1>(xyz, y0);
|
||||
return r.y - y0;
|
||||
}
|
||||
|
||||
inline double SurfaceYPlane::distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const
|
||||
double SurfaceYPlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_plane_distance<1>(xyz, uvw, coincident, y0);
|
||||
return axis_aligned_plane_distance<1>(r, u, coincident, y0);
|
||||
}
|
||||
|
||||
inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceYPlane::normal(Position r) const
|
||||
{
|
||||
axis_aligned_plane_normal<1, 0, 2>(xyz, uvw);
|
||||
return {0., 1., 0.};
|
||||
}
|
||||
|
||||
void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const
|
||||
|
|
@ -386,27 +359,25 @@ void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const
|
|||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
||||
double uvw[3]) const
|
||||
bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other, Position& r,
|
||||
Direction& u) const
|
||||
{
|
||||
double other_norm[3];
|
||||
other->normal(xyz, other_norm);
|
||||
if (other_norm[0] == 0 and other_norm[1] == 1 and other_norm[2] == 0) {
|
||||
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.
|
||||
xyz[1] = 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 xyz and uvw for rotational
|
||||
// evaluate function to find x0, then adjust position/Direction for rotational
|
||||
// symmetry.
|
||||
double xyz_test[3] {0, 0, 0};
|
||||
double x0 = -other->evaluate(xyz_test);
|
||||
xyz[0] = xyz[1] - y0 + x0;
|
||||
xyz[1] = y0;
|
||||
double x0 = -other->evaluate({0., 0., 0.});
|
||||
r.x = r.y - y0 + x0;
|
||||
r.y = y0;
|
||||
|
||||
double u = uvw[0];
|
||||
uvw[0] = uvw[1];
|
||||
uvw[1] = -u;
|
||||
double ux = u.x;
|
||||
u.x = u.y;
|
||||
u.y = -ux;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -415,8 +386,7 @@ bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
|||
BoundingBox
|
||||
SurfaceYPlane::bounding_box() const
|
||||
{
|
||||
BoundingBox out {-INFTY, INFTY, y0, y0, -INFTY, INFTY};
|
||||
return out;
|
||||
return {-INFTY, INFTY, y0, y0, -INFTY, INFTY};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -429,20 +399,19 @@ SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node)
|
|||
read_coeffs(surf_node, id, z0);
|
||||
}
|
||||
|
||||
inline double SurfaceZPlane::evaluate(const double xyz[3]) const
|
||||
double SurfaceZPlane::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_plane_evaluate<2>(xyz, z0);
|
||||
return r.z - z0;
|
||||
}
|
||||
|
||||
inline double SurfaceZPlane::distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const
|
||||
double SurfaceZPlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_plane_distance<2>(xyz, uvw, coincident, z0);
|
||||
return axis_aligned_plane_distance<2>(r, u, coincident, z0);
|
||||
}
|
||||
|
||||
inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceZPlane::normal(Position r) const
|
||||
{
|
||||
axis_aligned_plane_normal<2, 0, 1>(xyz, uvw);
|
||||
return {0., 0., 1.};
|
||||
}
|
||||
|
||||
void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const
|
||||
|
|
@ -452,19 +421,18 @@ void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const
|
|||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
||||
double uvw[3]) const
|
||||
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.
|
||||
xyz[2] = z0;
|
||||
r.z = z0;
|
||||
return false;
|
||||
}
|
||||
|
||||
BoundingBox
|
||||
SurfaceZPlane::bounding_box() const
|
||||
{
|
||||
BoundingBox out {-INFTY, INFTY, -INFTY, INFTY, z0, z0};
|
||||
return out;
|
||||
return {-INFTY, INFTY, -INFTY, INFTY, z0, z0};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -478,17 +446,16 @@ SurfacePlane::SurfacePlane(pugi::xml_node surf_node)
|
|||
}
|
||||
|
||||
double
|
||||
SurfacePlane::evaluate(const double xyz[3]) const
|
||||
SurfacePlane::evaluate(Position r) const
|
||||
{
|
||||
return A*xyz[0] + B*xyz[1] + C*xyz[2] - D;
|
||||
return A*r.x + B*r.y + C*r.z - D;
|
||||
}
|
||||
|
||||
double
|
||||
SurfacePlane::distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const
|
||||
SurfacePlane::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
const double f = A*xyz[0] + B*xyz[1] + C*xyz[2] - D;
|
||||
const double projection = A*uvw[0] + B*uvw[1] + C*uvw[2];
|
||||
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 {
|
||||
|
|
@ -498,12 +465,10 @@ SurfacePlane::distance(const double xyz[3], const double uvw[3],
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SurfacePlane::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction
|
||||
SurfacePlane::normal(Position r) const
|
||||
{
|
||||
uvw[0] = A;
|
||||
uvw[1] = B;
|
||||
uvw[2] = C;
|
||||
return {A, B, C};
|
||||
}
|
||||
|
||||
void SurfacePlane::to_hdf5_inner(hid_t group_id) const
|
||||
|
|
@ -513,18 +478,18 @@ void SurfacePlane::to_hdf5_inner(hid_t group_id) const
|
|||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
||||
double uvw[3]) const
|
||||
bool SurfacePlane::periodic_translate(const PeriodicSurface *other, Position& r,
|
||||
Direction& u) const
|
||||
{
|
||||
// This function assumes the other plane shares this plane's normal direction.
|
||||
|
||||
// Determine the distance to intersection.
|
||||
double d = evaluate(xyz) / (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.
|
||||
xyz[0] -= d * A;
|
||||
xyz[1] -= d * B;
|
||||
xyz[2] -= d * C;
|
||||
r.x -= d * A;
|
||||
r.y -= d * B;
|
||||
r.z -= d * C;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -532,8 +497,7 @@ bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3],
|
|||
BoundingBox
|
||||
SurfacePlane::bounding_box() const
|
||||
{
|
||||
BoundingBox out {-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY};
|
||||
return out;
|
||||
return {-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -544,28 +508,28 @@ SurfacePlane::bounding_box() const
|
|||
// cylinder. offset1 and offset2 should correspond with i1 and i2,
|
||||
// respectively.
|
||||
template<int i1, int i2> double
|
||||
axis_aligned_cylinder_evaluate(const double xyz[3], double offset1,
|
||||
axis_aligned_cylinder_evaluate(Position r, double offset1,
|
||||
double offset2, double radius)
|
||||
{
|
||||
const double xyz1 = xyz[i1] - offset1;
|
||||
const double xyz2 = xyz[i2] - offset2;
|
||||
return xyz1*xyz1 + xyz2*xyz2 - radius*radius;
|
||||
const double r1 = r[i1] - offset1;
|
||||
const double r2 = r[i2] - offset2;
|
||||
return r1*r1 + r2*r2 - radius*radius;
|
||||
}
|
||||
|
||||
// The first template parameter indicates which axis the cylinder is aligned to.
|
||||
// The other two parameters indicate the other two axes. offset1 and offset2
|
||||
// should correspond with i2 and i3, respectively.
|
||||
template<int i1, int i2, int i3> double
|
||||
axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3],
|
||||
axis_aligned_cylinder_distance(Position r, Direction u,
|
||||
bool coincident, double offset1, double offset2, double radius)
|
||||
{
|
||||
const double a = 1.0 - uvw[i1]*uvw[i1]; // u^2 + v^2
|
||||
const double a = 1.0 - u[i1]*u[i1]; // u^2 + v^2
|
||||
if (a == 0.0) return INFTY;
|
||||
|
||||
const double xyz2 = xyz[i2] - offset1;
|
||||
const double xyz3 = xyz[i3] - offset2;
|
||||
const double k = xyz2 * uvw[i2] + xyz3 * uvw[i3];
|
||||
const double c = xyz2*xyz2 + xyz3*xyz3 - radius*radius;
|
||||
const double r2 = r[i2] - offset1;
|
||||
const double r3 = r[i3] - offset2;
|
||||
const double k = r2 * u[i2] + r3 * u[i3];
|
||||
const double c = r2*r2 + r3*r3 - radius*radius;
|
||||
const double quad = k*k - a*c;
|
||||
|
||||
if (quad < 0.0) {
|
||||
|
|
@ -601,13 +565,14 @@ axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3],
|
|||
// The first template parameter indicates which axis the cylinder is aligned to.
|
||||
// The other two parameters indicate the other two axes. offset1 and offset2
|
||||
// should correspond with i2 and i3, respectively.
|
||||
template<int i1, int i2, int i3> void
|
||||
axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1,
|
||||
double offset2)
|
||||
template<int i1, int i2, int i3> Direction
|
||||
axis_aligned_cylinder_normal(Position r, double offset1, double offset2)
|
||||
{
|
||||
uvw[i2] = 2.0 * (xyz[i2] - offset1);
|
||||
uvw[i3] = 2.0 * (xyz[i3] - offset2);
|
||||
uvw[i1] = 0.0;
|
||||
Direction u;
|
||||
u[i2] = 2.0 * (r[i2] - offset1);
|
||||
u[i3] = 2.0 * (r[i3] - offset2);
|
||||
u[i1] = 0.0;
|
||||
return u;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -617,31 +582,30 @@ axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1,
|
|||
SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, y0, z0, r);
|
||||
read_coeffs(surf_node, id, y0, z0, radius);
|
||||
}
|
||||
|
||||
inline double SurfaceXCylinder::evaluate(const double xyz[3]) const
|
||||
double SurfaceXCylinder::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_evaluate<1, 2>(xyz, y0, z0, r);
|
||||
return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, radius);
|
||||
}
|
||||
|
||||
inline double SurfaceXCylinder::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
double SurfaceXCylinder::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cylinder_distance<0, 1, 2>(xyz, uvw, coincident, y0, z0,
|
||||
r);
|
||||
return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0, z0,
|
||||
radius);
|
||||
}
|
||||
|
||||
inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceXCylinder::normal(Position r) const
|
||||
{
|
||||
axis_aligned_cylinder_normal<0, 1, 2>(xyz, uvw, 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, r}};
|
||||
std::array<double, 3> coeffs {{y0, z0, radius}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -652,30 +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, r);
|
||||
read_coeffs(surf_node, id, x0, z0, radius);
|
||||
}
|
||||
|
||||
inline double SurfaceYCylinder::evaluate(const double xyz[3]) const
|
||||
double SurfaceYCylinder::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_evaluate<0, 2>(xyz, x0, z0, r);
|
||||
return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, radius);
|
||||
}
|
||||
|
||||
inline double SurfaceYCylinder::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
double SurfaceYCylinder::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cylinder_distance<1, 0, 2>(xyz, uvw, coincident, x0, z0,
|
||||
r);
|
||||
return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0, z0,
|
||||
radius);
|
||||
}
|
||||
|
||||
inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceYCylinder::normal(Position r) const
|
||||
{
|
||||
axis_aligned_cylinder_normal<1, 0, 2>(xyz, uvw, 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, r}};
|
||||
std::array<double, 3> coeffs {{x0, z0, radius}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -686,30 +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, r);
|
||||
read_coeffs(surf_node, id, x0, y0, radius);
|
||||
}
|
||||
|
||||
inline double SurfaceZCylinder::evaluate(const double xyz[3]) const
|
||||
double SurfaceZCylinder::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cylinder_evaluate<0, 1>(xyz, x0, y0, r);
|
||||
return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, radius);
|
||||
}
|
||||
|
||||
inline double SurfaceZCylinder::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
double SurfaceZCylinder::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cylinder_distance<2, 0, 1>(xyz, uvw, coincident, x0, y0,
|
||||
r);
|
||||
return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0, y0,
|
||||
radius);
|
||||
}
|
||||
|
||||
inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceZCylinder::normal(Position r) const
|
||||
{
|
||||
axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, 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, r}};
|
||||
std::array<double, 3> coeffs {{x0, y0, radius}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -720,25 +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, r);
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius);
|
||||
}
|
||||
|
||||
double SurfaceSphere::evaluate(const double xyz[3]) const
|
||||
double SurfaceSphere::evaluate(Position r) const
|
||||
{
|
||||
const double x = xyz[0] - x0;
|
||||
const double y = xyz[1] - y0;
|
||||
const double z = xyz[2] - z0;
|
||||
return x*x + y*y + z*z - r*r;
|
||||
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(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const
|
||||
double SurfaceSphere::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
const double x = xyz[0] - x0;
|
||||
const double y = xyz[1] - y0;
|
||||
const double z = xyz[2] - z0;
|
||||
const double k = x*uvw[0] + y*uvw[1] + z*uvw[2];
|
||||
const double c = x*x + y*y + z*z - r*r;
|
||||
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 quad = k*k - c;
|
||||
|
||||
if (quad < 0.0) {
|
||||
|
|
@ -770,17 +731,15 @@ double SurfaceSphere::distance(const double xyz[3], const double uvw[3],
|
|||
}
|
||||
}
|
||||
|
||||
inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceSphere::normal(Position r) const
|
||||
{
|
||||
uvw[0] = 2.0 * (xyz[0] - x0);
|
||||
uvw[1] = 2.0 * (xyz[1] - y0);
|
||||
uvw[2] = 2.0 * (xyz[2] - 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, r}};
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -792,30 +751,30 @@ void SurfaceSphere::to_hdf5_inner(hid_t group_id) const
|
|||
// The other two parameters indicate the other two axes. offset1, offset2,
|
||||
// and offset3 should correspond with i1, i2, and i3, respectively.
|
||||
template<int i1, int i2, int i3> double
|
||||
axis_aligned_cone_evaluate(const double xyz[3], double offset1,
|
||||
axis_aligned_cone_evaluate(Position r, double offset1,
|
||||
double offset2, double offset3, double radius_sq)
|
||||
{
|
||||
const double xyz1 = xyz[i1] - offset1;
|
||||
const double xyz2 = xyz[i2] - offset2;
|
||||
const double xyz3 = xyz[i3] - offset3;
|
||||
return xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1;
|
||||
const double r1 = r[i1] - offset1;
|
||||
const double r2 = r[i2] - offset2;
|
||||
const double r3 = r[i3] - offset3;
|
||||
return r2*r2 + r3*r3 - radius_sq*r1*r1;
|
||||
}
|
||||
|
||||
// The first template parameter indicates which axis the cone is aligned to.
|
||||
// The other two parameters indicate the other two axes. offset1, offset2,
|
||||
// and offset3 should correspond with i1, i2, and i3, respectively.
|
||||
template<int i1, int i2, int i3> double
|
||||
axis_aligned_cone_distance(const double xyz[3], const double uvw[3],
|
||||
axis_aligned_cone_distance(Position r, Direction u,
|
||||
bool coincident, double offset1, double offset2, double offset3,
|
||||
double radius_sq)
|
||||
{
|
||||
const double xyz1 = xyz[i1] - offset1;
|
||||
const double xyz2 = xyz[i2] - offset2;
|
||||
const double xyz3 = xyz[i3] - offset3;
|
||||
const double a = uvw[i2]*uvw[i2] + uvw[i3]*uvw[i3]
|
||||
- radius_sq*uvw[i1]*uvw[i1];
|
||||
const double k = xyz2*uvw[i2] + xyz3*uvw[i3] - radius_sq*xyz1*uvw[i1];
|
||||
const double c = xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1;
|
||||
const double r1 = r[i1] - offset1;
|
||||
const double r2 = r[i2] - offset2;
|
||||
const double r3 = r[i3] - offset3;
|
||||
const double a = u[i2]*u[i2] + u[i3]*u[i3]
|
||||
- radius_sq*u[i1]*u[i1];
|
||||
const double k = r2*u[i2] + r3*u[i3] - radius_sq*r1*u[i1];
|
||||
const double c = r2*r2 + r3*r3 - radius_sq*r1*r1;
|
||||
double quad = k*k - a*c;
|
||||
|
||||
double d;
|
||||
|
|
@ -858,13 +817,15 @@ axis_aligned_cone_distance(const double xyz[3], const double uvw[3],
|
|||
// The first template parameter indicates which axis the cone is aligned to.
|
||||
// The other two parameters indicate the other two axes. offset1, offset2,
|
||||
// and offset3 should correspond with i1, i2, and i3, respectively.
|
||||
template<int i1, int i2, int i3> void
|
||||
axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1,
|
||||
double offset2, double offset3, double radius_sq)
|
||||
template<int i1, int i2, int i3> Direction
|
||||
axis_aligned_cone_normal(Position r, double offset1, double offset2,
|
||||
double offset3, double radius_sq)
|
||||
{
|
||||
uvw[i1] = -2.0 * radius_sq * (xyz[i1] - offset1);
|
||||
uvw[i2] = 2.0 * (xyz[i2] - offset2);
|
||||
uvw[i3] = 2.0 * (xyz[i3] - offset3);
|
||||
Direction u;
|
||||
u[i1] = -2.0 * radius_sq * (r[i1] - offset1);
|
||||
u[i2] = 2.0 * (r[i2] - offset2);
|
||||
u[i3] = 2.0 * (r[i3] - offset3);
|
||||
return u;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -874,30 +835,29 @@ axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1,
|
|||
SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node)
|
||||
: Surface(surf_node)
|
||||
{
|
||||
read_coeffs(surf_node, id, x0, y0, z0, r_sq);
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius_sq);
|
||||
}
|
||||
|
||||
inline double SurfaceXCone::evaluate(const double xyz[3]) const
|
||||
double SurfaceXCone::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_evaluate<0, 1, 2>(xyz, x0, y0, z0, r_sq);
|
||||
return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, radius_sq);
|
||||
}
|
||||
|
||||
inline double SurfaceXCone::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
double SurfaceXCone::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cone_distance<0, 1, 2>(xyz, uvw, coincident, x0, y0, z0,
|
||||
r_sq);
|
||||
return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0, y0, z0,
|
||||
radius_sq);
|
||||
}
|
||||
|
||||
inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceXCone::normal(Position r) const
|
||||
{
|
||||
axis_aligned_cone_normal<0, 1, 2>(xyz, uvw, x0, y0, z0, r_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, r_sq}};
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius_sq}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -908,30 +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, r_sq);
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius_sq);
|
||||
}
|
||||
|
||||
inline double SurfaceYCone::evaluate(const double xyz[3]) const
|
||||
double SurfaceYCone::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_evaluate<1, 0, 2>(xyz, y0, x0, z0, r_sq);
|
||||
return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, radius_sq);
|
||||
}
|
||||
|
||||
inline double SurfaceYCone::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
double SurfaceYCone::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cone_distance<1, 0, 2>(xyz, uvw, coincident, y0, x0, z0,
|
||||
r_sq);
|
||||
return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0, x0, z0,
|
||||
radius_sq);
|
||||
}
|
||||
|
||||
inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceYCone::normal(Position r) const
|
||||
{
|
||||
axis_aligned_cone_normal<1, 0, 2>(xyz, uvw, y0, x0, z0, r_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, r_sq}};
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius_sq}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -942,30 +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, r_sq);
|
||||
read_coeffs(surf_node, id, x0, y0, z0, radius_sq);
|
||||
}
|
||||
|
||||
inline double SurfaceZCone::evaluate(const double xyz[3]) const
|
||||
double SurfaceZCone::evaluate(Position r) const
|
||||
{
|
||||
return axis_aligned_cone_evaluate<2, 0, 1>(xyz, z0, x0, y0, r_sq);
|
||||
return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, radius_sq);
|
||||
}
|
||||
|
||||
inline double SurfaceZCone::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
double SurfaceZCone::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
return axis_aligned_cone_distance<2, 0, 1>(xyz, uvw, coincident, z0, x0, y0,
|
||||
r_sq);
|
||||
return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0, x0, y0,
|
||||
radius_sq);
|
||||
}
|
||||
|
||||
inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction SurfaceZCone::normal(Position r) const
|
||||
{
|
||||
axis_aligned_cone_normal<2, 0, 1>(xyz, uvw, z0, x0, y0, r_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, r_sq}};
|
||||
std::array<double, 4> coeffs {{x0, y0, z0, radius_sq}};
|
||||
write_dataset(group_id, "coefficients", coeffs);
|
||||
}
|
||||
|
||||
|
|
@ -980,26 +938,25 @@ SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node)
|
|||
}
|
||||
|
||||
double
|
||||
SurfaceQuadric::evaluate(const double xyz[3]) const
|
||||
SurfaceQuadric::evaluate(Position r) const
|
||||
{
|
||||
const double &x = xyz[0];
|
||||
const double &y = xyz[1];
|
||||
const double &z = xyz[2];
|
||||
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;
|
||||
}
|
||||
|
||||
double
|
||||
SurfaceQuadric::distance(const double xyz[3],
|
||||
const double uvw[3], bool coincident) const
|
||||
SurfaceQuadric::distance(Position r, Direction ang, bool coincident) const
|
||||
{
|
||||
const double &x = xyz[0];
|
||||
const double &y = xyz[1];
|
||||
const double &z = xyz[2];
|
||||
const double &u = uvw[0];
|
||||
const double &v = uvw[1];
|
||||
const double &w = uvw[2];
|
||||
const double &x = r.x;
|
||||
const double &y = r.y;
|
||||
const double &z = r.z;
|
||||
const double &u = ang.x;
|
||||
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) +
|
||||
|
|
@ -1045,15 +1002,15 @@ SurfaceQuadric::distance(const double xyz[3],
|
|||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const
|
||||
Direction
|
||||
SurfaceQuadric::normal(Position r) const
|
||||
{
|
||||
const double &x = xyz[0];
|
||||
const double &y = xyz[1];
|
||||
const double &z = xyz[2];
|
||||
uvw[0] = 2.0*A*x + D*y + F*z + G;
|
||||
uvw[1] = 2.0*B*y + D*x + E*z + H;
|
||||
uvw[2] = 2.0*C*z + E*y + F*x + J;
|
||||
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};
|
||||
}
|
||||
|
||||
void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const
|
||||
|
|
@ -1263,10 +1220,24 @@ extern "C" {
|
|||
int surface_bc(Surface *surf) {return surf->bc;}
|
||||
|
||||
void surface_reflect(Surface *surf, double xyz[3], double uvw[3])
|
||||
{surf->reflect(xyz, uvw);}
|
||||
{
|
||||
Position r {xyz};
|
||||
Direction u {uvw};
|
||||
u = surf->reflect(r, u);
|
||||
|
||||
uvw[0] = u.x;
|
||||
uvw[1] = u.y;
|
||||
uvw[2] = u.z;
|
||||
}
|
||||
|
||||
void surface_normal(Surface *surf, double xyz[3], double uvw[3])
|
||||
{return surf->normal(xyz, uvw);}
|
||||
{
|
||||
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);}
|
||||
|
||||
|
|
@ -1275,7 +1246,21 @@ extern "C" {
|
|||
bool
|
||||
surface_periodic(PeriodicSurface *surf, PeriodicSurface *other, double xyz[3],
|
||||
double uvw[3])
|
||||
{return surf->periodic_translate(other, xyz, uvw);}
|
||||
{
|
||||
Position r {xyz};
|
||||
Direction u {uvw};
|
||||
bool rotational = surf->periodic_translate(other, r, u);
|
||||
|
||||
// Copy back to arrays
|
||||
xyz[0] = r.x;
|
||||
xyz[1] = r.y;
|
||||
xyz[2] = r.z;
|
||||
uvw[0] = u.x;
|
||||
uvw[1] = u.y;
|
||||
uvw[2] = u.z;
|
||||
|
||||
return rotational;
|
||||
}
|
||||
|
||||
void free_memory_surfaces_c()
|
||||
{
|
||||
|
|
|
|||
189
src/surface.h
189
src/surface.h
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef SURFACE_H
|
||||
#define SURFACE_H
|
||||
#ifndef OPENMC_SURFACE_H
|
||||
#define OPENMC_SURFACE_H
|
||||
|
||||
#include <map>
|
||||
#include <limits> // For numeric_limits
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include "pugixml.hpp"
|
||||
|
||||
#include "constants.h"
|
||||
#include "position.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -65,42 +66,40 @@ public:
|
|||
virtual ~Surface() {}
|
||||
|
||||
//! Determine which side of a surface a point lies on.
|
||||
//! @param xyz[3] The 3D Cartesian coordinate of a point.
|
||||
//! @param uvw[3] A direction used to "break ties" and pick a sense when the
|
||||
//! \param r The 3D Cartesian coordinate of a point.
|
||||
//! \param u A direction used to "break ties" and pick a sense when the
|
||||
//! point is very close to the surface.
|
||||
//! @return true if the point is on the "positive" side of the surface and
|
||||
//! \return true if the point is on the "positive" side of the surface and
|
||||
//! false otherwise.
|
||||
bool sense(const double xyz[3], const double uvw[3]) const;
|
||||
bool sense(Position r, Direction u) const;
|
||||
|
||||
//! Determine the direction of a ray reflected from the surface.
|
||||
//! @param xyz[3] The point at which the ray is incident.
|
||||
//! @param uvw[3] A direction. This is both an input and an output parameter.
|
||||
//! It specifies the icident direction on input and the reflected direction
|
||||
//! on output.
|
||||
void reflect(const double xyz[3], double uvw[3]) const;
|
||||
//! \param[in] r The point at which the ray is incident.
|
||||
//! \param[in] u Incident direction of the ray
|
||||
//! \return Outgoing direction of the ray
|
||||
Direction reflect(Position r, Direction u) const;
|
||||
|
||||
//! Evaluate the equation describing the surface.
|
||||
//!
|
||||
//! Surfaces can be described by some function f(x, y, z) = 0. This member
|
||||
//! function evaluates that mathematical function.
|
||||
//! @param xyz[3] A 3D Cartesian coordinate.
|
||||
virtual double evaluate(const double xyz[3]) const = 0;
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
virtual double evaluate(Position r) const = 0;
|
||||
|
||||
//! Compute the distance between a point and the surface along a ray.
|
||||
//! @param xyz[3] A 3D Cartesian coordinate.
|
||||
//! @param uvw[3] The direction of the ray.
|
||||
//! @param coincident A hint to the code that the given point should lie
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \param u The direction of the ray.
|
||||
//! \param coincident A hint to the code that the given point should lie
|
||||
//! exactly on the surface.
|
||||
virtual double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const = 0;
|
||||
virtual double distance(Position r, Direction u, bool coincident) const = 0;
|
||||
|
||||
//! Compute the local outward normal direction of the surface.
|
||||
//! @param xyz[3] A 3D Cartesian coordinate.
|
||||
//! @param uvw[3] This output argument provides the normal.
|
||||
virtual void normal(const double xyz[3], double uvw[3]) const = 0;
|
||||
//! \param r A 3D Cartesian coordinate.
|
||||
//! \return Normal direction
|
||||
virtual Direction normal(Position r) const = 0;
|
||||
|
||||
//! Write all information needed to reconstruct the surface to an HDF5 group.
|
||||
//! @param group_id An HDF5 group id.
|
||||
//! \param group_id An HDF5 group id.
|
||||
//TODO: this probably needs to include i_periodic for PeriodicSurface
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
|
|
@ -124,15 +123,15 @@ public:
|
|||
explicit PeriodicSurface(pugi::xml_node surf_node);
|
||||
|
||||
//! Translate a particle onto this surface from a periodic partner surface.
|
||||
//! @param other A pointer to the partner surface in this periodic BC.
|
||||
//! @param xyz[3] A point on the partner surface that will be translated onto
|
||||
//! \param other A pointer to the partner surface in this periodic BC.
|
||||
//! \param r A point on the partner surface that will be translated onto
|
||||
//! this surface.
|
||||
//! @param uvw[3] A direction that will be rotated for systems with rotational
|
||||
//! \param u A direction that will be rotated for systems with rotational
|
||||
//! periodicity.
|
||||
//! @return true if this surface and its partner make a rotationally-periodic
|
||||
//! \return true if this surface and its partner make a rotationally-periodic
|
||||
//! boundary condition.
|
||||
virtual bool periodic_translate(PeriodicSurface *other, double xyz[3],
|
||||
double uvw[3]) const = 0;
|
||||
virtual bool periodic_translate(const PeriodicSurface *other, Position& r,
|
||||
Direction& u) const = 0;
|
||||
|
||||
//! Get the bounding box for this surface.
|
||||
virtual BoundingBox bounding_box() const = 0;
|
||||
|
|
@ -149,12 +148,11 @@ class SurfaceXPlane : public PeriodicSurface
|
|||
double x0;
|
||||
public:
|
||||
explicit SurfaceXPlane(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3], bool coincident)
|
||||
const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3])
|
||||
bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u)
|
||||
const;
|
||||
BoundingBox bounding_box() const;
|
||||
};
|
||||
|
|
@ -170,12 +168,11 @@ class SurfaceYPlane : public PeriodicSurface
|
|||
double y0;
|
||||
public:
|
||||
explicit SurfaceYPlane(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3])
|
||||
bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u)
|
||||
const;
|
||||
BoundingBox bounding_box() const;
|
||||
};
|
||||
|
|
@ -191,12 +188,11 @@ class SurfaceZPlane : public PeriodicSurface
|
|||
double z0;
|
||||
public:
|
||||
explicit SurfaceZPlane(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3])
|
||||
bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u)
|
||||
const;
|
||||
BoundingBox bounding_box() const;
|
||||
};
|
||||
|
|
@ -212,12 +208,11 @@ class SurfacePlane : public PeriodicSurface
|
|||
double A, B, C, D;
|
||||
public:
|
||||
explicit SurfacePlane(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3], bool coincident)
|
||||
const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3])
|
||||
bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u)
|
||||
const;
|
||||
BoundingBox bounding_box() const;
|
||||
};
|
||||
|
|
@ -231,13 +226,12 @@ public:
|
|||
|
||||
class SurfaceXCylinder : public Surface
|
||||
{
|
||||
double y0, z0, r;
|
||||
double y0, z0, radius;
|
||||
public:
|
||||
explicit SurfaceXCylinder(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -250,13 +244,12 @@ public:
|
|||
|
||||
class SurfaceYCylinder : public Surface
|
||||
{
|
||||
double x0, z0, r;
|
||||
double x0, z0, radius;
|
||||
public:
|
||||
explicit SurfaceYCylinder(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -269,13 +262,12 @@ public:
|
|||
|
||||
class SurfaceZCylinder : public Surface
|
||||
{
|
||||
double x0, y0, r;
|
||||
double x0, y0, radius;
|
||||
public:
|
||||
explicit SurfaceZCylinder(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -288,13 +280,12 @@ public:
|
|||
|
||||
class SurfaceSphere : public Surface
|
||||
{
|
||||
double x0, y0, z0, r;
|
||||
double x0, y0, z0, radius;
|
||||
public:
|
||||
explicit SurfaceSphere(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -307,13 +298,12 @@ public:
|
|||
|
||||
class SurfaceXCone : public Surface
|
||||
{
|
||||
double x0, y0, z0, r_sq;
|
||||
double x0, y0, z0, radius_sq;
|
||||
public:
|
||||
explicit SurfaceXCone(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -326,13 +316,12 @@ public:
|
|||
|
||||
class SurfaceYCone : public Surface
|
||||
{
|
||||
double x0, y0, z0, r_sq;
|
||||
double x0, y0, z0, radius_sq;
|
||||
public:
|
||||
explicit SurfaceYCone(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -345,13 +334,12 @@ public:
|
|||
|
||||
class SurfaceZCone : public Surface
|
||||
{
|
||||
double x0, y0, z0, r_sq;
|
||||
double x0, y0, z0, radius_sq;
|
||||
public:
|
||||
explicit SurfaceZCone(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -367,10 +355,9 @@ class SurfaceQuadric : public Surface
|
|||
double A, B, C, D, E, F, G, H, J, K;
|
||||
public:
|
||||
explicit SurfaceQuadric(pugi::xml_node surf_node);
|
||||
double evaluate(const double xyz[3]) const;
|
||||
double distance(const double xyz[3], const double uvw[3],
|
||||
bool coincident) const;
|
||||
void normal(const double xyz[3], double uvw[3]) const;
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
void to_hdf5_inner(hid_t group_id) const;
|
||||
};
|
||||
|
||||
|
|
@ -379,20 +366,20 @@ public:
|
|||
//==============================================================================
|
||||
|
||||
extern "C" {
|
||||
Surface* surface_pointer(int surf_ind);
|
||||
int surface_id(Surface *surf);
|
||||
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]);
|
||||
void free_memory_surfaces_c();
|
||||
Surface* surface_pointer(int surf_ind);
|
||||
int surface_id(Surface *surf);
|
||||
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]);
|
||||
void free_memory_surfaces_c();
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
#endif // SURFACE_H
|
||||
#endif // OPENMC_SURFACE_H
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ contains
|
|||
type_ = 'zernike'
|
||||
type is (ParticleFilter)
|
||||
type_ = 'particle'
|
||||
type is (ZernikeRadialFilter)
|
||||
type_ = 'zernikeradial'
|
||||
end select
|
||||
|
||||
! Convert Fortran string to null-terminated C string. We assume the
|
||||
|
|
@ -164,6 +166,8 @@ contains
|
|||
allocate(UniverseFilter :: filters(index) % obj)
|
||||
case ('zernike')
|
||||
allocate(ZernikeFilter :: filters(index) % obj)
|
||||
case ('zernikeradial')
|
||||
allocate(ZernikeRadialFilter :: filters(index) % obj)
|
||||
case default
|
||||
err = E_UNASSIGNED
|
||||
call set_errmsg("Unknown filter type: " // trim(type_))
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module tally_filter_zernike
|
|||
use constants
|
||||
use error
|
||||
use hdf5_interface
|
||||
use math, only: calc_zn
|
||||
use math, only: calc_zn, calc_zn_rad
|
||||
use particle_header, only: Particle
|
||||
use string, only: to_str
|
||||
use tally_filter_header
|
||||
|
|
@ -13,6 +13,10 @@ module tally_filter_zernike
|
|||
|
||||
implicit none
|
||||
private
|
||||
public :: openmc_zernike_filter_get_order
|
||||
public :: openmc_zernike_filter_get_params
|
||||
public :: openmc_zernike_filter_set_order
|
||||
public :: openmc_zernike_filter_set_params
|
||||
|
||||
!===============================================================================
|
||||
! ZERNIKEFILTER gives Zernike polynomial moments of a particle's position
|
||||
|
|
@ -24,19 +28,43 @@ module tally_filter_zernike
|
|||
real(8) :: y
|
||||
real(8) :: r
|
||||
contains
|
||||
procedure :: from_xml
|
||||
procedure :: get_all_bins
|
||||
procedure :: to_statepoint
|
||||
procedure :: text_label
|
||||
procedure :: calc_n_bins => calc_n_bins_zn
|
||||
procedure :: from_xml => from_xml_zn
|
||||
procedure :: get_all_bins => get_all_bins_zn
|
||||
procedure :: to_statepoint => to_statepoint_zn
|
||||
procedure :: text_label => text_label_zn
|
||||
end type ZernikeFilter
|
||||
|
||||
!===============================================================================
|
||||
! ZERNIKERADIALFILTER gives even order radial Zernike polynomial moments of a
|
||||
! particle's position
|
||||
!===============================================================================
|
||||
|
||||
type, public, extends(ZernikeFilter) :: ZernikeRadialFilter
|
||||
contains
|
||||
procedure :: calc_n_bins => calc_n_bins_zn_rad
|
||||
! Inherit from_xml from ZernikeFilter
|
||||
procedure :: get_all_bins => get_all_bins_zn_rad
|
||||
procedure :: to_statepoint => to_statepoint_zn_rad
|
||||
procedure :: text_label => text_label_zn_rad
|
||||
end type ZernikeRadialFilter
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! ZernikeFilter methods
|
||||
!===============================================================================
|
||||
|
||||
subroutine from_xml(this, node)
|
||||
function calc_n_bins_zn(this) result(n_bins)
|
||||
class(ZernikeFilter), intent(in) :: this
|
||||
integer :: n
|
||||
integer :: n_bins
|
||||
|
||||
n = this % order
|
||||
n_bins = ((n+1) * (n+2))/2
|
||||
end function calc_n_bins_zn
|
||||
|
||||
subroutine from_xml_zn(this, node)
|
||||
class(ZernikeFilter), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
|
|
@ -50,10 +78,10 @@ contains
|
|||
! Get specified order
|
||||
call get_node_value(node, "order", n)
|
||||
this % order = n
|
||||
this % n_bins = ((n + 1)*(n + 2))/2
|
||||
end subroutine from_xml
|
||||
this % n_bins = this % calc_n_bins()
|
||||
end subroutine from_xml_zn
|
||||
|
||||
subroutine get_all_bins(this, p, estimator, match)
|
||||
subroutine get_all_bins_zn(this, p, estimator, match)
|
||||
class(ZernikeFilter), intent(in) :: this
|
||||
type(Particle), intent(in) :: p
|
||||
integer, intent(in) :: estimator
|
||||
|
|
@ -67,18 +95,20 @@ contains
|
|||
x = p % coord(1) % xyz(1) - this % x
|
||||
y = p % coord(1) % xyz(2) - this % y
|
||||
r = sqrt(x*x + y*y)/this % r
|
||||
theta = atan2(y, x)
|
||||
if (r <= ONE) then
|
||||
theta = atan2(y, x)
|
||||
|
||||
! Get moments for Zernike polynomial orders 0..n
|
||||
call calc_zn(this % order, r, theta, zn)
|
||||
|
||||
! Get moments for Zernike polynomial orders 0..n
|
||||
call calc_zn(this % order, r, theta, zn)
|
||||
do i = 1, this % n_bins
|
||||
call match % bins % push_back(i)
|
||||
call match % weights % push_back(zn(i))
|
||||
end do
|
||||
endif
|
||||
end subroutine get_all_bins_zn
|
||||
|
||||
do i = 1, this % n_bins
|
||||
call match % bins % push_back(i)
|
||||
call match % weights % push_back(zn(i))
|
||||
end do
|
||||
end subroutine get_all_bins
|
||||
|
||||
subroutine to_statepoint(this, filter_group)
|
||||
subroutine to_statepoint_zn(this, filter_group)
|
||||
class(ZernikeFilter), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: filter_group
|
||||
|
||||
|
|
@ -88,9 +118,9 @@ contains
|
|||
call write_dataset(filter_group, "x", this % x)
|
||||
call write_dataset(filter_group, "y", this % y)
|
||||
call write_dataset(filter_group, "r", this % r)
|
||||
end subroutine to_statepoint
|
||||
end subroutine to_statepoint_zn
|
||||
|
||||
function text_label(this, bin) result(label)
|
||||
function text_label_zn(this, bin) result(label)
|
||||
class(ZernikeFilter), intent(in) :: this
|
||||
integer, intent(in) :: bin
|
||||
character(MAX_LINE_LEN) :: label
|
||||
|
|
@ -108,7 +138,66 @@ contains
|
|||
exit
|
||||
end if
|
||||
end do
|
||||
end function text_label
|
||||
end function text_label_zn
|
||||
|
||||
!===============================================================================
|
||||
! ZernikeRadialFilter methods
|
||||
!===============================================================================
|
||||
|
||||
function calc_n_bins_zn_rad(this) result(num_n_bins)
|
||||
class(ZernikeRadialFilter), intent(in) :: this
|
||||
integer :: n
|
||||
integer :: num_n_bins
|
||||
|
||||
n = this % order
|
||||
num_n_bins = n/2 + 1
|
||||
end function calc_n_bins_zn_rad
|
||||
|
||||
subroutine get_all_bins_zn_rad(this, p, estimator, match)
|
||||
class(ZernikeRadialFilter), intent(in) :: this
|
||||
type(Particle), intent(in) :: p
|
||||
integer, intent(in) :: estimator
|
||||
type(TallyFilterMatch), intent(inout) :: match
|
||||
|
||||
integer :: i
|
||||
real(8) :: x, y, r
|
||||
real(C_DOUBLE) :: zn_rad(this % n_bins)
|
||||
|
||||
! Determine normalized (r,theta) positions
|
||||
x = p % coord(1) % xyz(1) - this % x
|
||||
y = p % coord(1) % xyz(2) - this % y
|
||||
r = sqrt(x*x + y*y)/this % r
|
||||
if (r <= ONE) then
|
||||
|
||||
! Get moments for even order Zernike polynomial orders 0..n
|
||||
call calc_zn_rad(this % order, r, zn_rad)
|
||||
|
||||
do i = 1, this % n_bins
|
||||
call match % bins % push_back(i)
|
||||
call match % weights % push_back(zn_rad(i))
|
||||
end do
|
||||
endif
|
||||
end subroutine get_all_bins_zn_rad
|
||||
|
||||
subroutine to_statepoint_zn_rad(this, filter_group)
|
||||
class(ZernikeRadialFilter), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: filter_group
|
||||
|
||||
call write_dataset(filter_group, "type", "zernikeradial")
|
||||
call write_dataset(filter_group, "n_bins", this % n_bins)
|
||||
call write_dataset(filter_group, "order", this % order)
|
||||
call write_dataset(filter_group, "x", this % x)
|
||||
call write_dataset(filter_group, "y", this % y)
|
||||
call write_dataset(filter_group, "r", this % r)
|
||||
end subroutine to_statepoint_zn_rad
|
||||
|
||||
function text_label_zn_rad(this, bin) result(label)
|
||||
class(ZernikeRadialFilter), intent(in) :: this
|
||||
integer, intent(in) :: bin
|
||||
character(MAX_LINE_LEN) :: label
|
||||
|
||||
label = "Zernike expansion, Z" // trim(to_str(2*(bin-1))) // ",0"
|
||||
end function text_label_zn_rad
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
|
|
@ -125,6 +214,8 @@ contains
|
|||
select type (f => filters(index) % obj)
|
||||
type is (ZernikeFilter)
|
||||
order = f % order
|
||||
type is (ZernikeRadialFilter)
|
||||
order = f % order
|
||||
class default
|
||||
err = E_INVALID_TYPE
|
||||
call set_errmsg("Not a Zernike filter.")
|
||||
|
|
@ -144,7 +235,7 @@ contains
|
|||
err = verify_filter(index)
|
||||
if (err == 0) then
|
||||
select type (f => filters(index) % obj)
|
||||
type is (ZernikeFilter)
|
||||
class is (ZernikeFilter)
|
||||
x = f % x
|
||||
y = f % y
|
||||
r = f % r
|
||||
|
|
@ -168,6 +259,9 @@ contains
|
|||
type is (ZernikeFilter)
|
||||
f % order = order
|
||||
f % n_bins = ((order + 1)*(order + 2))/2
|
||||
type is (ZernikeRadialFilter)
|
||||
f % order = order
|
||||
f % n_bins = order/2 + 1
|
||||
class default
|
||||
err = E_INVALID_TYPE
|
||||
call set_errmsg("Not a Zernike filter.")
|
||||
|
|
@ -187,7 +281,7 @@ contains
|
|||
err = verify_filter(index)
|
||||
if (err == 0) then
|
||||
select type (f => filters(index) % obj)
|
||||
type is (ZernikeFilter)
|
||||
class is (ZernikeFilter)
|
||||
if (present(x)) f % x = x
|
||||
if (present(y)) f % y = y
|
||||
if (present(r)) f % r = r
|
||||
|
|
|
|||
|
|
@ -340,6 +340,9 @@ contains
|
|||
type is (ZernikeFilter)
|
||||
j = FILTER_ZERNIKE
|
||||
this % estimator = ESTIMATOR_COLLISION
|
||||
type is (ZernikeRadialFilter)
|
||||
j = FILTER_ZERNIKE_RADIAL
|
||||
this % estimator = ESTIMATOR_COLLISION
|
||||
type is (ParticleFilter)
|
||||
j = FILTER_PARTICLE
|
||||
end select
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ contains
|
|||
|
||||
! Get value of text node/attribute
|
||||
str = node_value_string(node, name)
|
||||
call whitespace_to_blanks(str)
|
||||
|
||||
! Read numbers into array
|
||||
read(UNIT=str, FMT=*, IOSTAT=stat) array
|
||||
|
|
@ -283,6 +284,7 @@ contains
|
|||
|
||||
! Get value of text node/attribute
|
||||
str = node_value_string(node, name)
|
||||
call whitespace_to_blanks(str)
|
||||
|
||||
! Read numbers into array
|
||||
read(UNIT=str, FMT=*, IOSTAT=stat) array
|
||||
|
|
@ -333,4 +335,21 @@ contains
|
|||
end if
|
||||
end subroutine get_node_array_string
|
||||
|
||||
!===============================================================================
|
||||
! WHITESPACE_TO_BLANKS converts all whitespace to blanks
|
||||
!===============================================================================
|
||||
|
||||
subroutine whitespace_to_blanks(str)
|
||||
character(len=*, kind=C_CHAR), intent(inout) :: str
|
||||
|
||||
integer :: i
|
||||
|
||||
do i = 1, len(str)
|
||||
select case (str(i:i))
|
||||
case (C_NEW_LINE, C_HORIZONTAL_TAB, C_CARRIAGE_RETURN)
|
||||
str(i:i) = ' '
|
||||
end select
|
||||
end do
|
||||
end subroutine
|
||||
|
||||
end module xml_interface
|
||||
|
|
|
|||
|
|
@ -100,6 +100,23 @@ def test_zernike():
|
|||
assert elem.attrib['type'] == 'zernike'
|
||||
assert elem.find('order').text == str(n)
|
||||
|
||||
def test_zernike_radial():
|
||||
n = 4
|
||||
f = openmc.ZernikeRadialFilter(n, 0., 0., 1.)
|
||||
assert f.order == n
|
||||
assert f.bins[0] == 'Z0,0'
|
||||
assert f.bins[-1] == 'Z{},0'.format(n)
|
||||
assert len(f.bins) == n//2 + 1
|
||||
|
||||
# Make sure __repr__ works
|
||||
repr(f)
|
||||
|
||||
# to_xml_element()
|
||||
elem = f.to_xml_element()
|
||||
assert elem.tag == 'filter'
|
||||
assert elem.attrib['type'] == 'zernikeradial'
|
||||
assert elem.find('order').text == str(n)
|
||||
|
||||
|
||||
def test_first_moment(run_in_tmpdir, box_model):
|
||||
plain_tally = openmc.Tally()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue