23 const double eps = 2e-16;
32 : m_E((_Vhig - _Vlow) / 2), m_R((_Vhig + _Vlow) / 2)
35 throw std::invalid_argument(
"At least one edge has zero length");
46 #ifdef POLYHEDRAL_DIAGNOSTIC
47 if (diagnosis.debmsg >= 5)
48 std::cout <<
std::scientific << std::showpos << std::setprecision(16) <<
"contrib: u=" << u
49 <<
" v1=" << v1 <<
" v2=" << v2 <<
"\n";
61 }
else if (v2 == 0.) {
65 for (
int mm = 1; mm <= M; ++mm) {
67 * pow(v2, mm) * pow(v1, M - mm);
69 #ifdef POLYHEDRAL_DIAGNOSTIC
70 if (diagnosis.debmsg >= 6)
71 std::cout <<
"contrib mm=" << mm <<
" t=" << term <<
" s=" << ret <<
"\n";
77 for (
int l = 1; l <= M / 2; ++l) {
79 * pow(u, 2 * l) * pow(v, M - 2 * l);
81 #ifdef POLYHEDRAL_DIAGNOSTIC
82 if (diagnosis.debmsg >= 6)
83 std::cout <<
"contrib l=" << l <<
" t=" << term <<
" s=" << ret <<
"\n";
100 double diameterFace = 0;
101 for (
size_t j = 0; j < V.size(); ++j)
102 for (
size_t jj = j + 1; jj < V.size(); ++jj)
103 diameterFace = std::max(diameterFace, (V[j] - V[jj]).mag());
107 #ifdef POLYHEDRAL_DIAGNOSTIC
108 void PolyhedralFace::setLimits(
double _qpa,
int _n)
122 size_t NV = V.size();
124 throw std::logic_error(
"Face with no edges");
126 throw std::logic_error(
"Face with less than three edges");
139 for (
size_t j = 0; j < NV; ++j) {
140 size_t jj = (j + 1) % NV;
145 size_t NE =
edges.size();
147 throw std::invalid_argument(
"Face has less than three non-vanishing edges");
151 for (
size_t j = 0; j < NE; ++j) {
152 size_t jj = (j + 1) % NE;
154 if (ee.
mag2() == 0) {
155 throw std::logic_error(
"Two adjacent edges are parallel");
161 for (
size_t j = 0; j < NV; ++j)
165 for (
size_t j = 1; j < NV; ++j)
167 throw std::logic_error(
"Face is not planar");
170 for (
size_t j = 0; j < NV; ++j) {
171 size_t jj = (j + 1) % NV;
177 throw std::logic_error(
"Odd #edges violates symmetry S2");
179 for (
size_t j = 0; j < NE; ++j) {
183 throw std::logic_error(
"Edge centers violate symmetry S2");
185 throw std::logic_error(
"Edge vectors violate symmetry S2");
200 if (qpa.
mag() <
eps * std::abs(qperp))
212 for (
size_t i = 0; i <
edges.size(); ++i) {
216 vfac = prevec.
dot(e.
E());
223 #ifdef POLYHEDRAL_DIAGNOSTIC
224 if (diagnosis.debmsg >= 4)
226 <<
"DBX ff_n_core " << m <<
" " << vfac <<
" " << tmp
227 <<
" term=" << vfac * tmp <<
" sum=" << ret <<
"\n";
238 if (std::abs(qn) <
eps * q.
mag())
243 double qpa_mag2 = qpa.
mag2();
244 if (qpa_mag2 == 0.) {
250 #ifdef POLYHEDRAL_DIAGNOSTIC
251 if (diagnosis.debmsg >= 3)
252 std::cout <<
"DBX ff_n " << n <<
" " << qn <<
" " << tmp <<
" " << qpa_mag2 <<
"\n";
254 return qn * tmp / qpa_mag2;
261 double abslevel)
const
263 #ifdef POLYHEDRAL_DIAGNOSTIC
264 diagnosis.nExpandedFaces += 1;
268 int count_return_condition = 0;
270 #ifdef POLYHEDRAL_DIAGNOSTIC
271 diagnosis.maxOrder = std::max(diagnosis.maxOrder, n);
274 #ifdef POLYHEDRAL_DIAGNOSTIC
275 if (diagnosis.debmsg >= 2)
276 std::cout << std::setprecision(16) <<
" sum=" << sum <<
" +term=" << term <<
"\n";
279 if (std::abs(term) <=
eps * std::abs(sum) || std::abs(sum) <
eps * abslevel)
280 ++count_return_condition;
282 count_return_condition = 0;
283 if (count_return_condition > 2)
285 n_fac =
mul_I(n_fac);
287 #ifdef POLYHEDRAL_DIAGNOSTIC
288 if (!diagnosis.request_convergence)
291 throw std::runtime_error(
"Series f(q_pa) not converged");
301 for (
size_t i = 0; i <
edges.size(); ++i) {
308 vfac = prevec.
dot(e.
E());
315 #ifdef POLYHEDRAL_DIAGNOSTIC
316 if (diagnosis.debmsg >= 2)
318 <<
" sum=" << sum <<
" term=" << term <<
" vf=" << vfac <<
" qE=" << qE
343 fac_even = 2. *
mul_I(sin(qr_perp));
344 fac_odd = 2. * cos(qr_perp);
346 fac_even =
exp_I(qr_perp);
349 return ff0 +
expansion(fac_even, fac_odd, qpa, std::abs(ff0));
354 prefac = sym_Ci ? -8. * sin(qr_perp) : 4. *
mul_I(
exp_I(qr_perp));
356 prefac = sym_Ci ? 4. : 2. *
exp_I(qr_perp);
357 #ifdef POLYHEDRAL_DIAGNOSTIC
358 if (diagnosis.debmsg >= 2)
359 std::cout <<
" qrperp=" << qr_perp <<
" => prefac=" << prefac <<
"\n";
370 throw std::logic_error(
"ff_2D called with perpendicular q component");
381 #ifdef POLYHEDRAL_DIAGNOSTIC
382 if (diagnosis.debmsg >= 2)
383 std::cout << std::setprecision(16) <<
" ret=" << ret <<
" ff=" <<
ff <<
"\n";
394 throw std::logic_error(
"Faces with different distance from origin violate symmetry Ci");
396 throw std::logic_error(
"Faces with different areas violate symmetry Ci");
398 throw std::logic_error(
"Faces do not have opposite orientation, violating symmetry Ci");
complex_t mul_I(complex_t z)
Returns product I*z, where I is the imaginary unit.
std::complex< double > complex_t
complex_t exp_I(complex_t z)
Returns exp(I*z), where I is the imaginary unit.
Defines namespace MathFunctions.
Defines classes PolyhedralEdge, PolyhedralFace.
Defines namespace Precomputed, providing precomputed constants.
BasicVector3D< std::complex< double > > cvector_t
BasicVector3D< double > kvector_t
double mag2() const
Returns magnitude squared of the vector.
auto dot(const BasicVector3D< U > &v) const
Returns dot product of vectors (antilinear in the first [=self] argument).
BasicVector3D< T > unit() const
Returns unit vector in direction of this. Throws for null vector.
double mag() const
Returns magnitude of the vector.
auto cross(const BasicVector3D< U > &v) const
Returns cross product of vectors (linear in both arguments).
One edge of a polygon, for form factor computation.
PolyhedralEdge(const kvector_t _Vlow, const kvector_t _Vhig)
kvector_t m_R
position vector of edge midpoint
complex_t qE(cvector_t q) const
complex_t qR(cvector_t q) const
complex_t contrib(int m, cvector_t qpa, complex_t qrperp) const
Returns sum_l=0^M/2 u^2l v^(M-2l) / (2l+1)!(M-2l)! - vperp^M/M!
kvector_t m_E
vector pointing from mid of edge to upper vertex
A polygon, for form factor computation.
complex_t ff_n(int m, cvector_t q) const
Returns contribution qn*f_n [of order q^(n+1)] from this face to the polyhedral form factor.
bool sym_S2
if true, then edges obtainable by inversion are not provided
complex_t ff_n_core(int m, cvector_t qpa, complex_t qperp) const
Returns core contribution to f_n.
static int n_limit_series
static double qpa_limit_series
determines when use power series
double m_radius_2d
radius of enclosing cylinder
double m_rperp
distance of this polygon's plane from the origin, along 'm_normal'
static double diameter(const std::vector< kvector_t > &V)
Static method, returns diameter of circle that contains all vertices.
complex_t ff_2D(cvector_t qpa) const
Returns the two-dimensional form factor of this face, for use in a prism.
complex_t expansion(complex_t fac_even, complex_t fac_odd, cvector_t qpa, double abslevel) const
Returns sum of n>=1 terms of qpa expansion of 2d form factor.
PolyhedralFace(const std::vector< kvector_t > &_V=std::vector< kvector_t >(), bool _sym_S2=false)
Sets internal variables for given vertex chain.
std::vector< PolyhedralEdge > edges
void decompose_q(cvector_t q, complex_t &qperp, cvector_t &qpa) const
Sets qperp and qpa according to argument q and to this polygon's normal.
kvector_t m_normal
normal vector of this polygon's plane
void assert_Ci(const PolyhedralFace &other) const
Throws if deviation from inversion symmetry is detected. Does not check vertices.
complex_t edge_sum_ff(cvector_t q, cvector_t qpa, bool sym_Ci) const
Returns core contribution to analytic 2d form factor.
complex_t ff(cvector_t q, bool sym_Ci) const
Returns the contribution ff(q) of this face to the polyhedral form factor.
double m_radius_3d
radius of enclosing sphere
double sinc(double x)
sinc function:
std::string scientific(const T value, int n=10)
Returns scientific string representing given value of any numeric type.
constexpr auto ReciprocalFactorialArray