2020-03-31 18:11:31 -05:00
|
|
|
from collections.abc import Iterable
|
2020-02-21 09:34:51 -05:00
|
|
|
import math
|
2020-03-31 18:11:31 -05:00
|
|
|
|
2018-08-17 15:00:39 -05:00
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
2018-08-23 11:50:12 -05:00
|
|
|
def legendre_from_expcoef(coef, domain=(-1, 1)):
|
2018-08-21 10:16:06 -05:00
|
|
|
"""Return a Legendre series object based on expansion coefficients.
|
2018-08-17 16:39:56 -05:00
|
|
|
|
|
|
|
|
Given a list of coefficients from FET tally and a array of down, return
|
|
|
|
|
the numpy Legendre object.
|
2018-08-17 15:00:39 -05:00
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
coef : Iterable of float
|
|
|
|
|
A list of coefficients of each term in Legendre polynomials
|
2018-08-17 15:27:51 -05:00
|
|
|
domain : (2,) List of float
|
|
|
|
|
Domain of the Legendre polynomial
|
2018-08-17 15:00:39 -05:00
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2018-08-21 10:16:06 -05:00
|
|
|
numpy.polynomial.Legendre
|
|
|
|
|
A numpy Legendre series class
|
2018-08-17 15:00:39 -05:00
|
|
|
|
|
|
|
|
"""
|
2018-08-17 16:39:56 -05:00
|
|
|
|
|
|
|
|
n = np.arange(len(coef))
|
2018-08-17 15:00:39 -05:00
|
|
|
c = (2*n + 1) * np.asarray(coef) / (domain[1] - domain[0])
|
|
|
|
|
return np.polynomial.Legendre(c, domain)
|
|
|
|
|
|
|
|
|
|
|
2020-03-19 15:21:15 -05:00
|
|
|
class Polynomial:
|
2018-08-17 15:00:39 -05:00
|
|
|
"""Abstract Polynomial Class for creating polynomials.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, coef):
|
|
|
|
|
self.coef = np.asarray(coef)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ZernikeRadial(Polynomial):
|
2018-08-21 10:16:06 -05:00
|
|
|
"""Create radial only Zernike polynomials given coefficients and domain.
|
2018-08-17 15:00:39 -05:00
|
|
|
|
|
|
|
|
The radial only Zernike polynomials are defined as in
|
|
|
|
|
:class:`ZernikeRadialFilter`.
|
|
|
|
|
|
2020-04-10 21:52:43 -05:00
|
|
|
.. versionadded:: 0.12
|
|
|
|
|
|
2018-08-17 15:00:39 -05:00
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
coef : Iterable of float
|
|
|
|
|
A list of coefficients of each term in radial only Zernike polynomials
|
|
|
|
|
radius : float
|
|
|
|
|
Domain of Zernike polynomials to be applied on. Default is 1.
|
|
|
|
|
|
|
|
|
|
Attributes
|
|
|
|
|
----------
|
|
|
|
|
order : int
|
|
|
|
|
The maximum (even) order of Zernike polynomials.
|
|
|
|
|
radius : float
|
|
|
|
|
Domain of Zernike polynomials to be applied on. Default is 1.
|
|
|
|
|
norm_coef : iterable of float
|
|
|
|
|
The list of coefficients of each term in the polynomials after
|
2022-02-10 00:20:58 +00:00
|
|
|
normalization.
|
2018-08-17 15:00:39 -05:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, coef, radius=1):
|
|
|
|
|
super().__init__(coef)
|
2018-08-17 15:27:51 -05:00
|
|
|
self._order = 2 * (len(self.coef) - 1)
|
2018-08-17 15:00:39 -05:00
|
|
|
self.radius = radius
|
2020-02-21 09:34:51 -05:00
|
|
|
norm_vec = (2 * np.arange(len(self.coef)) + 1) / (math.pi * radius**2)
|
2018-08-17 15:00:39 -05:00
|
|
|
self._norm_coef = norm_vec * self.coef
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def order(self):
|
|
|
|
|
return self._order
|
|
|
|
|
|
|
|
|
|
def __call__(self, r):
|
2019-09-05 07:31:13 -05:00
|
|
|
import openmc.lib as lib
|
2018-08-23 11:50:12 -05:00
|
|
|
if isinstance(r, Iterable):
|
2020-01-30 17:24:37 -05:00
|
|
|
return [np.sum(self._norm_coef * lib.calc_zn_rad(self.order, r_i / self.radius))
|
2018-08-23 11:50:12 -05:00
|
|
|
for r_i in r]
|
|
|
|
|
else:
|
2020-01-30 17:24:37 -05:00
|
|
|
return np.sum(self._norm_coef * lib.calc_zn_rad(self.order, r / self.radius))
|
|
|
|
|
|
|
|
|
|
|
2020-01-30 17:25:21 -05:00
|
|
|
class Zernike(Polynomial):
|
2020-02-21 09:34:51 -05:00
|
|
|
r"""Create Zernike polynomials given coefficients and domain.
|
2020-03-19 15:21:15 -05:00
|
|
|
|
2020-02-21 09:34:51 -05:00
|
|
|
The azimuthal Zernike polynomials are defined as in :class:`ZernikeFilter`.
|
2020-03-19 15:21:15 -05:00
|
|
|
|
2020-04-10 21:52:43 -05:00
|
|
|
.. versionadded:: 0.12
|
|
|
|
|
|
2020-01-30 17:25:21 -05:00
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
coef : Iterable of float
|
2025-01-10 13:18:03 -06:00
|
|
|
A list of coefficients of each term in Zernike polynomials
|
2020-01-30 17:25:21 -05:00
|
|
|
radius : float
|
|
|
|
|
Domain of Zernike polynomials to be applied on. Default is 1.
|
2020-03-19 15:21:15 -05:00
|
|
|
|
2020-01-30 17:25:21 -05:00
|
|
|
Attributes
|
|
|
|
|
----------
|
|
|
|
|
order : int
|
|
|
|
|
The maximum (even) order of Zernike polynomials.
|
|
|
|
|
radius : float
|
|
|
|
|
Domain of Zernike polynomials to be applied on. Default is 1.
|
2020-03-19 15:21:15 -05:00
|
|
|
theta : float
|
|
|
|
|
Azimuthal of Zernike polynomial to be applied on. Default is 0.
|
2020-01-30 17:25:21 -05:00
|
|
|
norm_coef : iterable of float
|
|
|
|
|
The list of coefficients of each term in the polynomials after
|
2022-02-10 00:20:58 +00:00
|
|
|
normalization.
|
2020-01-30 17:25:21 -05:00
|
|
|
"""
|
|
|
|
|
def __init__(self, coef, radius=1):
|
|
|
|
|
super().__init__(coef)
|
2020-03-17 15:41:17 -04:00
|
|
|
# Solve order from number of coefficients
|
|
|
|
|
# N = (order + 1)(order + 2) / 2
|
2020-02-21 09:34:51 -05:00
|
|
|
self._order = int((math.sqrt(8 * len(self.coef) + 1) - 3) / 2)
|
2020-01-30 17:25:21 -05:00
|
|
|
self.radius = radius
|
2020-02-21 09:34:51 -05:00
|
|
|
norm_vec = np.ones(len(self.coef))
|
2020-01-30 17:25:21 -05:00
|
|
|
for n in range(self._order + 1):
|
2020-02-05 23:25:50 -05:00
|
|
|
for m in range(-n, n + 1, 2):
|
2020-02-21 09:34:51 -05:00
|
|
|
j = int((n*(n + 2) + m)/2)
|
|
|
|
|
if m == 0:
|
2020-03-19 15:21:15 -05:00
|
|
|
norm_vec[j] = n + 1
|
2020-01-30 17:25:21 -05:00
|
|
|
else:
|
2020-02-21 09:34:51 -05:00
|
|
|
norm_vec[j] = 2*n + 2
|
|
|
|
|
norm_vec /= (math.pi * radius**2)
|
2020-01-30 17:25:21 -05:00
|
|
|
self._norm_coef = norm_vec * self.coef
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def order(self):
|
|
|
|
|
return self._order
|
|
|
|
|
|
|
|
|
|
def __call__(self, r, theta=0.0):
|
|
|
|
|
import openmc.lib as lib
|
|
|
|
|
if isinstance(r, Iterable) and isinstance(theta, Iterable):
|
2020-02-05 23:25:50 -05:00
|
|
|
return [[np.sum(self._norm_coef * lib.calc_zn(self.order, r_i / self.radius, theta_i))
|
2020-01-30 17:25:21 -05:00
|
|
|
for r_i in r] for theta_i in theta]
|
|
|
|
|
elif isinstance(r, Iterable) and not isinstance(theta, Iterable):
|
2020-02-05 23:25:50 -05:00
|
|
|
return [np.sum(self._norm_coef * lib.calc_zn(self.order, r_i / self.radius, theta))
|
2020-01-30 17:25:21 -05:00
|
|
|
for r_i in r]
|
|
|
|
|
elif not isinstance(r, Iterable) and isinstance(theta, Iterable):
|
2020-02-05 23:25:50 -05:00
|
|
|
return [np.sum(self._norm_coef * lib.calc_zn(self.order, r / self.radius, theta_i))
|
2020-01-30 17:25:21 -05:00
|
|
|
for theta_i in theta]
|
|
|
|
|
else:
|
2020-02-05 23:25:50 -05:00
|
|
|
return np.sum(self._norm_coef * lib.calc_zn(self.order, r / self.radius, theta))
|