14 const double zin,
double& ex,
double& ey,
15 double& ez,
double& p,
Medium*& m,
20 ex = ey = ez = p = 0.;
26 <<
" Field map is not available for interpolation.\n";
36 std::array<double, 2> x = {xin, yin};
37 std::array<bool, 2> mirr = {
false,
false};
45 std::array<double, nMaxVertices> w;
46 const auto i = FindElement(x[0], x[1], w);
55 for (
size_t j = 0; j < nVertices; ++j) {
56 const size_t index = element.vertex[j];
61 if (mirr[0]) ex = -ex;
62 if (mirr[1]) ey = -ey;
64 if (!
m_regions[element.region].drift || !m) status = -5;
67bool ComponentTcad2d::Interpolate(
const double xin,
const double yin,
69 const std::vector<std::array<double, 2> >& field,
70 double& fx,
double& fy,
double& fz) {
73 if (field.empty())
return false;
74 if (m_hasRangeZ && (z <
m_bbMin[2] || z >
m_bbMax[2]))
return false;
75 std::array<double, 2> x = {xin, yin};
76 std::array<bool, 2> mirr = {
false,
false};
82 std::array<double, nMaxVertices> w;
83 const auto i = FindElement(x[0], x[1], w);
89 for (
size_t j = 0; j < nVertices; ++j) {
90 const auto index = element.vertex[j];
91 fx += w[j] * field[index][0];
92 fy += w[j] * field[index][1];
94 if (mirr[0]) fx = -fx;
95 if (mirr[1]) fy = -fy;
99bool ComponentTcad2d::Interpolate(
const double xin,
const double yin,
101 const std::vector<double>& field,
double& f) {
104 if (field.empty())
return false;
105 if (m_hasRangeZ && (z <
m_bbMin[2] || z >
m_bbMax[2]))
return false;
106 std::array<double, 2>
x = {xin, yin};
107 std::array<bool, 2> mirr = {
false,
false};
112 std::array<double, nMaxVertices> w;
113 const auto i = FindElement(x[0], x[1], w);
119 for (
size_t j = 0; j < nVertices; ++j) {
120 f += w[j] * field[element.vertex[j]];
130 <<
" Field map not available for interpolation.\n";
134 if (m_hasRangeZ && (zin <
m_bbMin[2] || zin >
m_bbMax[2]))
return nullptr;
135 std::array<double, 2> x = {xin, yin};
136 std::array<bool, 2> mirr = {
false,
false};
142 std::array<double, nMaxVertices> w;
143 const size_t i = FindElement(x[0], x[1], w);
151void ComponentTcad2d::FillTree() {
159 for (
size_t i = 0; i < nVertices; ++i) {
165 for (
size_t i = 0; i < nElements; ++i) {
167 const double bb[4] = {element.bbMin[0], element.bbMin[1],
168 element.bbMax[0], element.bbMax[1]};
169 m_tree->InsertMeshElement(bb, i);
175 double& xmax,
double& ymax,
double& zmax) {
178 xmin = -std::numeric_limits<double>::infinity();
179 xmax = +std::numeric_limits<double>::infinity();
186 ymin = -std::numeric_limits<double>::infinity();
187 ymax = +std::numeric_limits<double>::infinity();
201 double& xmin,
double& ymin,
double& zmin,
202 double& xmax,
double& ymax,
double& zmax) {
212 const double xymax = std::max({fabs(xmin), fabs(xmax),
213 fabs(ymin), fabs(ymax)});
221 if (fabs(zmax - zmin) <= 0.) {
222 std::cerr <<
m_className <<
"::SetRangeZ: Zero range is not permitted.\n";
225 m_bbMin[2] = std::min(zmin, zmax);
226 m_bbMax[2] = std::max(zmin, zmax);
231 double& dmin,
double& dmax,
int& type,
232 std::vector<size_t>& nodes,
int& reg)
const {
235 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
241 if (element.type == 0) {
242 dmin = dmax = vol = 0;
243 }
else if (element.type == 1) {
244 const auto& v0 =
m_vertices[element.vertex[0]];
245 const auto& v1 =
m_vertices[element.vertex[1]];
246 const double d = std::hypot(v1[0] - v0[0], v1[1] - v0[1]);
247 dmin = dmax = vol = d;
248 }
else if (element.type == 2) {
249 const auto& v0 =
m_vertices[element.vertex[0]];
250 const auto& v1 =
m_vertices[element.vertex[1]];
251 const auto& v2 =
m_vertices[element.vertex[2]];
252 vol = 0.5 * fabs((v2[0] - v0[0]) * (v1[1] - v0[1]) -
253 (v2[1] - v0[1]) * (v1[0] - v0[0]));
254 const double a = std::hypot(v1[0] - v0[0], v1[1] - v0[1]);
255 const double b = std::hypot(v2[0] - v0[0], v2[1] - v0[1]);
256 const double c = std::hypot(v1[0] - v2[0], v1[1] - v2[1]);
257 dmin = std::min({a, b, c});
258 dmax = std::max({a, b, c});
259 }
else if (element.type == 3) {
260 const auto& v0 =
m_vertices[element.vertex[0]];
261 const auto& v1 =
m_vertices[element.vertex[1]];
262 const auto& v3 =
m_vertices[element.vertex[3]];
263 const double a = std::hypot(v1[0] - v0[0], v1[1] - v0[1]);
264 const double b = std::hypot(v3[0] - v0[0], v3[1] - v0[1]);
266 dmin = std::min(a, b);
267 dmax = sqrt(a * a + b * b);
270 <<
" Unexpected element type (" << element.type <<
")\n";
274 for (
size_t j = 0; j < nVertices; ++j) {
275 nodes.push_back(element.vertex[j]);
277 reg = element.region;
282 double& v,
double& ex,
double& ey)
const {
284 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
298size_t ComponentTcad2d::FindElement(
const double x,
const double y,
299 std::array<double, nMaxVertices>& w)
const {
303 const auto& elements = m_tree->GetElementsInBlock(x, y);
304 for (
const auto i : elements) {
305 if (InElement(x, y,
m_elements[i], w))
return i;
309 for (
size_t i = 0; i < nElements; ++i) {
310 if (InElement(x, y,
m_elements[i], w))
return i;
316 <<
" Point (" <<
x <<
", " <<
y <<
") is outside the mesh.\n";
321bool ComponentTcad2d::InElement(
const double x,
const double y,
322 const Element& element,
323 std::array<double, nMaxVertices>& w)
const {
324 if (x < element.bbMin[0] || x > element.bbMax[0] ||
325 y < element.bbMin[1] || y > element.bbMax[1]) {
328 switch (element.type) {
330 return AtPoint(x, y, element, w);
332 return OnLine(x, y, element, w);
334 return InTriangle(x, y, element, w);
336 return InRectangle(x, y, element, w);
339 <<
" Unknown element type. Program bug!\n";
345bool ComponentTcad2d::InRectangle(
const double x,
const double y,
346 const Element& element,
347 std::array<double, nMaxVertices>& w)
const {
348 const auto& v0 =
m_vertices[element.vertex[0]];
349 const auto& v1 =
m_vertices[element.vertex[1]];
350 const auto& v3 =
m_vertices[element.vertex[3]];
351 if (y < v0[1] || x > v3[0] || y > v1[1])
return false;
354 const double u = (
x - 0.5 * (v0[0] + v3[0])) / (v3[0] - v0[0]);
355 const double v = (
y - 0.5 * (v0[1] + v1[1])) / (v1[1] - v0[1]);
357 w[0] = (0.5 - u) * (0.5 - v);
358 w[1] = (0.5 - u) * (0.5 + v);
359 w[2] = (0.5 + u) * (0.5 + v);
360 w[3] = (0.5 + u) * (0.5 - v);
364bool ComponentTcad2d::InTriangle(
const double x,
const double y,
365 const Element& element,
366 std::array<double, nMaxVertices>& w)
const {
367 const auto& v0 =
m_vertices[element.vertex[0]];
368 const auto& v1 =
m_vertices[element.vertex[1]];
369 const auto& v2 =
m_vertices[element.vertex[2]];
370 if (x > v1[0] && x > v2[0])
return false;
371 if (y < v0[1] && y < v1[1] && y < v2[1])
return false;
372 if (y > v0[1] && y > v1[1] && y > v2[1])
return false;
378 const double sx = v1[0] - v0[0];
379 const double sy = v1[1] - v0[1];
380 const double tx = v2[0] - v0[0];
381 const double ty = v2[1] - v0[1];
382 const double d = 1. / (sx * ty - sy * tx);
383 w[1] = ((
x - v0[0]) * ty - (
y - v0[1]) * tx) * d;
384 if (w[1] < 0. || w[1] > 1.)
return false;
385 w[2] = ((v0[0] -
x) * sy - (v0[1] -
y) * sx) * d;
386 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
389 w[0] = 1. - w[1] - w[2];
394bool ComponentTcad2d::OnLine(
const double x,
const double y,
395 const Element& element,
396 std::array<double, nMaxVertices>& w)
const {
397 const auto& v0 =
m_vertices[element.vertex[0]];
398 const auto& v1 =
m_vertices[element.vertex[1]];
399 if (x > v1[0])
return false;
400 if (y < v0[1] && y < v1[1])
return false;
401 if (y > v0[1] && y > v1[1])
return false;
402 const double tx = (
x - v0[0]) / (v1[0] - v0[0]);
403 if (tx < 0. || tx > 1.)
return false;
404 const double ty = (
y - v0[1]) / (v1[1] - v0[1]);
405 if (ty < 0. || ty > 1.)
return false;
415bool ComponentTcad2d::AtPoint(
const double x,
const double y,
416 const Element& element,
417 std::array<double, nMaxVertices>& w)
const {
418 const auto& v0 =
m_vertices[element.vertex[0]];
419 if (x != v0[0] || y != v0[1])
return false;
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
ComponentTcad2d()
Constructor.
void SetRangeZ(const double zmin, const double zmax)
Set the z-extent of the bounding box (default: unlimited).
bool GetElement(const size_t i, double &vol, double &dmin, double &dmax, int &type, std::vector< size_t > &nodes, int ®) const
bool GetNode(const size_t i, double &x, double &y, double &v, double &ex, double &ey) const
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status) override
Calculate the drift field [V/cm] and potential [V] at (x, y, z).
bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the coordinates of the elementary cell.
bool InBoundingBox(const std::array< double, N > &x) const
std::vector< std::array< double, N > > m_vertices
std::vector< Element > m_elements
std::vector< Region > m_regions
static unsigned int ElementVertices(const Element &element)
std::array< double, 3 > m_bbMax
std::vector< double > m_epot
std::vector< std::array< double, N > > m_efield
void MapCoordinates(std::array< double, N > &x, std::array< bool, N > &mirr) const
ComponentTcadBase()=delete
std::array< double, 3 > m_bbMin
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
bool m_debug
Switch on/off debugging messages.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
std::string m_className
Class name.
bool m_ready
Ready for use?
Abstract base class for media.