Chi-Tech
sldfe_sq_01d_utils.cc
Go to the documentation of this file.
1#include "sldfe_sq.h"
2
3//###################################################################
4/**Computes the area of a cell. This routine uses
5 * Girard's theorem to get the area of a spherical
6 * triangle using the spherical excess.*/
9 std::array<chi_mesh::Vertex,4>& vertices_xyz)
10{
11 const auto num_verts = 4;
12
13 //======================================== Compute centroid
14 chi_mesh::Vertex centroid_xyz;
15 for (auto& v : vertices_xyz)
16 centroid_xyz += v;
17 centroid_xyz /= num_verts;
18
19 //======================================== Compute area via
20 // spherical excess
21 double area = 0.0;
22 auto v0 = centroid_xyz.Normalized();
23 for (int v=0; v<num_verts; ++v)
24 {
25 auto v1 = vertices_xyz[v];
26 auto v2 = vertices_xyz[(v < (num_verts-1))? v+1 : 0];
27
28 if ((v1-v0).Cross(v2-v0).Dot(v0) < 0.0)
29 std::swap(v1,v2);
30
31 //====================================== Lambda for spherical excess
32 auto GetSphericalExcess = [](const chi_mesh::Vector3& vA,
33 const chi_mesh::Vector3& vB,
34 const chi_mesh::Vector3& vC)
35 {
36 const auto& n = vA;
37
38 auto vAB = vB - vA;
39 auto vAC = vC - vA;
40
41 auto tAB = vAB.Cross(n).Normalized();
42 auto tAC = vAC.Cross(n).Normalized();
43
44 auto bAB = n.Cross(tAB).Normalized();
45 auto bAC = n.Cross(tAC).Normalized();
46
47 double mu = std::max(-1.0,std::fmin(1.0,bAB.Dot(bAC)));
48
49 return std::fabs(acos(mu));
50 };
51
52 double excess = GetSphericalExcess(v0,v1,v2) +
53 GetSphericalExcess(v1,v2,v0) +
54 GetSphericalExcess(v2,v0,v1);
55
56 area += excess - M_PI;
57 }
58
59 return area;
60}
61
62
63//###################################################################
64/**Integrates shape functions to produce weights.*/
67 const SphericalQuadrilateral &sq,
68 std::array<chi_math::DynamicVector<double>,4>& shape_coeffs,
69 const std::vector<chi_math::QuadraturePointXYZ>& legendre_qpoints,
70 const std::vector<double>& legendre_qweights)
71{
72 //=================================== Lambda to evaluate LDFE shape func
73 auto EvaluateShapeFunction = [](chi_math::DynamicVector<double>& shape_coeffs,
74 chi_mesh::Vector3& mu_eta_xi)
75 {
76 return shape_coeffs[0] + shape_coeffs[1]*mu_eta_xi[0] +
77 shape_coeffs[2]*mu_eta_xi[1] +
78 shape_coeffs[3]*mu_eta_xi[2];
79 };
80
81 //=================================== Determine integration bounds
82 double x_tilde_max = 0.0;
83 double x_tilde_min = 1.0;
84 double y_tilde_max = 0.0;
85 double y_tilde_min = 1.0;
86
87 for (auto& v : sq.vertices_xy_tilde)
88 {
89 x_tilde_max = std::fmax(x_tilde_max,v.x);
90 x_tilde_min = std::fmin(x_tilde_min,v.x);
91 y_tilde_max = std::fmax(y_tilde_max,v.y);
92 y_tilde_min = std::fmin(y_tilde_min,v.y);
93 }
94
95 //=================================== Integrate Legendre Quadrature
96 std::array<double,4> integral = {0.0,0.0,0.0,0.0};
97 int Nq = legendre_qpoints.size();
98 double dx_tilde = (x_tilde_max - x_tilde_min);
99 double dy_tilde = (y_tilde_max - y_tilde_min);
100
101 for (int i=0; i<Nq; ++i)
102 {
103 for (int j=0; j<Nq; ++j)
104 {
105 //========================== Determine xy_tilde
106 double x_tilde = x_tilde_min + (1.0 + legendre_qpoints[j][0])*dx_tilde/2.0;
107 double y_tilde = y_tilde_min + (1.0 + legendre_qpoints[i][0])*dy_tilde/2.0;
108 chi_mesh::Vector3 xy_tilde(x_tilde,y_tilde,0.0);
109
110 //========================== Map to xyz
111 auto xyz = (sq.rotation_matrix*xy_tilde + sq.translation_vector).Normalized();
112
113 //========================== Determine Jacobian
114 double r = sqrt(x_tilde*x_tilde + y_tilde*y_tilde + a*a);
115 double detJ = (a/(r*r*r))*dx_tilde*dy_tilde/4.0;
116
117 //========================== Evaluate shape funcs and add to integral
118 for (int k=0; k<4; ++k)
119 integral[k] += EvaluateShapeFunction(shape_coeffs[k], xyz)*detJ*
120 legendre_qweights[i]*legendre_qweights[j];
121 }//for j
122 }//for i
123
124 return integral;
125}
126
127//###################################################################
128/**Deploys the current set of SQs to all octants.*/
130{
131 deployed_SQs_.clear(); //just to be sure
132 deployed_SQs_.reserve(initial_octant_SQs_.size() * 8);
133
134 //======================================== Define modifying variables
135 chi_mesh::Vector3 octant_mod(1.0,1.0,1.0);
136
137 //======================================== Top NE octant, no change
138 for (auto& sq : initial_octant_SQs_)
139 deployed_SQs_.push_back(sq);
140
141 //======================================== Top NW octant
142 octant_mod = chi_mesh::Vector3(-1.0,1.0,1.0);
143 for (auto& sq : initial_octant_SQs_)
144 {
145 SphericalQuadrilateral new_sq = sq;
146
147 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
148 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
149 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
150 new_sq.octant_modifier = octant_mod;
151
152 deployed_SQs_.push_back(new_sq);
153 }
154
155 //======================================== Top SW octant
156 octant_mod = chi_mesh::Vector3(-1.0,-1.0,1.0);
157 for (auto& sq : initial_octant_SQs_)
158 {
159 SphericalQuadrilateral new_sq = sq;
160
161 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
162 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
163 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
164 new_sq.octant_modifier = octant_mod;
165
166 deployed_SQs_.push_back(new_sq);
167 }
168
169 //======================================== Top SE octant
170 octant_mod = chi_mesh::Vector3(1.0,-1.0,1.0);
171 for (auto& sq : initial_octant_SQs_)
172 {
173 SphericalQuadrilateral new_sq = sq;
174
175 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
176 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
177 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
178 new_sq.octant_modifier = octant_mod;
179
180 deployed_SQs_.push_back(new_sq);
181 }
182
183 //======================================== Bot NE octant
184 octant_mod = chi_mesh::Vector3(1.0,1.0,-1.0);
185 for (auto& sq : initial_octant_SQs_)
186 {
187 SphericalQuadrilateral new_sq = sq;
188
189 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
190 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
191 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
192 new_sq.octant_modifier = octant_mod;
193
194 deployed_SQs_.push_back(new_sq);
195 }
196
197 //======================================== Bot NW octant
198 octant_mod = chi_mesh::Vector3(-1.0,1.0,-1.0);
199 for (auto& sq : initial_octant_SQs_)
200 {
201 SphericalQuadrilateral new_sq = sq;
202
203 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
204 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
205 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
206 new_sq.octant_modifier = octant_mod;
207
208 deployed_SQs_.push_back(new_sq);
209 }
210
211 //======================================== Bot SW octant
212 octant_mod = chi_mesh::Vector3(-1.0,-1.0,-1.0);
213 for (auto& sq : initial_octant_SQs_)
214 {
215 SphericalQuadrilateral new_sq = sq;
216
217 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
218 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
219 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
220 new_sq.octant_modifier = octant_mod;
221
222 deployed_SQs_.push_back(new_sq);
223 }
224
225 //======================================== Bot SE octant
226 octant_mod = chi_mesh::Vector3(1.0,-1.0,-1.0);
227 for (auto& sq : initial_octant_SQs_)
228 {
229 SphericalQuadrilateral new_sq = sq;
230
231 for (auto& xyz : new_sq.vertices_xyz) xyz = xyz*octant_mod;
232 auto& vcc = new_sq.centroid_xyz; vcc = vcc*octant_mod;
233 for (auto& xyz : new_sq.sub_sqr_points) xyz = xyz*octant_mod;
234 new_sq.octant_modifier = octant_mod;
235
236 deployed_SQs_.push_back(new_sq);
237 }
238
239 //======================================== Make history entry
240 deployed_SQs_history_.push_back(deployed_SQs_);
241}
242
243//###################################################################
244/**Populates the quadrature abscissaes, weights and direction vectors.*/
246{
247 abscissae_.clear();
248 weights_.clear();
249 omegas_.clear();
250
251 for (const auto& sq : deployed_SQs_)
252 {
253 for (int i=0;i<4;++i)
254 {
255 const auto& omega = sq.sub_sqr_points[i];
256 const double weight = sq.sub_sqr_weights[i];
257
258 double theta = acos(omega.z);
259 double phi = acos(omega.x/sin(theta));
260
261 if (omega.y/sin(theta)<0.0)
262 phi = 2.0*M_PI - phi;
263
264 const auto abscissa = chi_math::QuadraturePointPhiTheta(phi, theta);
265
266 abscissae_.push_back(abscissa);
267 weights_.push_back(weight);
268 omegas_.push_back(omega);
269 }
270 }
271}
272
static double ComputeSphericalQuadrilateralArea(std::array< chi_mesh::Vertex, 4 > &vertices_xyz)
static std::array< double, 4 > IntegrateLDFEShapeFunctions(const SphericalQuadrilateral &sq, std::array< chi_math::DynamicVector< double >, 4 > &shape_coeffs, const std::vector< chi_math::QuadraturePointXYZ > &legendre_qpoints, const std::vector< double > &legendre_qweights)
VectorN< 3 > Vector3
std::array< chi_mesh::Vertex, 4 > vertices_xy_tilde
On square.
Definition: sldfe_sq.h:37
std::array< chi_mesh::Vector3, 4 > sub_sqr_points
Definition: sldfe_sq.h:45
std::array< chi_mesh::Vertex, 4 > vertices_xyz
On unit sphere.
Definition: sldfe_sq.h:39
Vector3 Cross(const Vector3 &that) const
Vector3 Normalized() const