14 const double zin,
double& ex,
double& ey,
15 double& ez,
double& p,
Medium*& m,
19 ex = ey = ez = p = 0.;
24 <<
" Field map is not available for interpolation.\n";
28 std::array<double, 3> x = {xin, yin, zin};
29 std::array<bool, 3> mirr = {
false,
false,
false};
38 std::array<double, nMaxVertices> w;
39 const size_t i = FindElement(x[0], x[1], x[2], w);
47 for (
unsigned int j = 0; j < nVertices; ++j) {
48 const auto index = element.vertex[j];
54 if (mirr[0]) ex = -ex;
55 if (mirr[1]) ey = -ey;
56 if (mirr[2]) ez = -ez;
58 if (!
m_regions[element.region].drift || !m) status = -5;
62 const double z,
double& ex,
double& ey,
63 double& ez,
Medium*& m,
int& status) {
68bool ComponentTcad3d::Interpolate(
69 const double xin,
const double yin,
const double zin,
70 const std::vector<std::array<double, 3> >& field,
71 double& fx,
double& fy,
double& fz) {
73 if (field.empty())
return false;
74 std::array<double, 3> x = {xin, yin, zin};
75 std::array<bool, 3> mirr = {
false,
false,
false};
81 std::array<double, nMaxVertices> w;
82 const size_t i = FindElement(x[0], x[1], x[2], w);
88 for (
size_t j = 0; j < nVertices; ++j) {
89 const auto index = element.vertex[j];
90 fx += w[j] * field[index][0];
91 fy += w[j] * field[index][1];
92 fz += w[j] * field[index][2];
94 if (mirr[0]) fx = -fx;
95 if (mirr[1]) fy = -fy;
96 if (mirr[2]) fz = -fz;
100bool ComponentTcad3d::Interpolate(
101 const double xin,
const double yin,
const double zin,
102 const std::vector<double>& field,
double& f) {
105 if (field.empty())
return false;
106 std::array<double, 3>
x = {xin, yin, zin};
107 std::array<bool, 3> mirr = {
false,
false,
false};
113 std::array<double, nMaxVertices> w;
114 const auto i = FindElement(x[0], x[1], x[2], w);
120 for (
size_t j = 0; j < nVertices; ++j) {
121 f += w[j] * field[element.vertex[j]];
131 <<
" Field map not available for interpolation.\n";
135 std::array<double, 3> x = {xin, yin, zin};
136 std::array<bool, 3> mirr = {
false,
false,
false};
142 std::array<double, nMaxVertices> w;
143 const size_t i = FindElement(x[0], x[1], x[2], w);
151void ComponentTcad3d::FillTree() {
162 for (
size_t i = 0; i < nVertices; ++i) {
164 m_tree->InsertMeshNode(
Vec3(vtx[0], vtx[1], vtx[2]), i);
169 for (
size_t i = 0; i < nElements; ++i) {
171 const double bb[6] = {element.bbMin[0], element.bbMin[1], element.bbMin[2],
172 element.bbMax[0], element.bbMax[1], element.bbMax[2]};
173 m_tree->InsertMeshElement(bb, i);
178 double& xmax,
double& ymax,
double& zmax) {
187 xmin = -std::numeric_limits<double>::infinity();
188 xmax = +std::numeric_limits<double>::infinity();
191 ymin = -std::numeric_limits<double>::infinity();
192 ymax = +std::numeric_limits<double>::infinity();
195 zmin = -std::numeric_limits<double>::infinity();
196 zmax = +std::numeric_limits<double>::infinity();
202 double& xmin,
double& ymin,
double& zmin,
203 double& xmax,
double& ymax,
double& zmax) {
214size_t ComponentTcad3d::FindElement(
215 const double x,
const double y,
const double z,
216 std::array<double, nMaxVertices>& w)
const {
220 std::vector<int> elementsToSearch;
222 elementsToSearch = m_tree->GetElementsInBlock(
Vec3(x, y, z));
224 const size_t nElementsToSearch = m_tree ? elementsToSearch.size() :
m_elements.size();
226 for (
size_t i = 0; i < nElementsToSearch; ++i) {
227 const size_t idx = m_tree ? elementsToSearch[i] : i;
228 if (InElement(x, y, z,
m_elements[idx], w))
return idx;
233 <<
" Point (" <<
x <<
", " <<
y <<
", " <<
z
234 <<
") is outside the mesh.\n";
240 double& dmin,
double& dmax,
int& type,
241 std::vector<size_t>& nodes,
int& reg)
const {
244 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
249 if (element.type == 2) {
251 const auto& v0 =
m_vertices[element.vertex[0]];
252 const auto& v1 =
m_vertices[element.vertex[1]];
253 const auto& v2 =
m_vertices[element.vertex[2]];
254 const double vx = (v1[1] - v0[1]) * (v2[2] - v0[2]) -
255 (v1[2] - v0[2]) * (v2[1] - v0[1]);
256 const double vy = (v1[2] - v0[2]) * (v2[0] - v0[0]) -
257 (v1[0] - v0[0]) * (v2[2] - v0[2]);
258 const double vz = (v1[0] - v0[0]) * (v2[1] - v0[1]) -
259 (v1[1] - v0[1]) * (v2[0] - v0[0]);
260 vol = sqrt(vx * vx + vy * vy + vz * vz);
261 const double a = sqrt(pow(v1[0] - v0[0], 2) + pow(v1[1] - v0[1], 2) +
262 pow(v1[2] - v0[2], 2));
263 const double b = sqrt(pow(v2[0] - v0[0], 2) + pow(v2[1] - v0[1], 2) +
264 pow(v2[2] - v0[2], 2));
265 const double c = sqrt(pow(v1[0] - v2[0], 2) + pow(v1[1] - v2[1], 2) +
266 pow(v1[2] - v2[2], 2));
267 dmin = std::min({a, b, c});
268 dmax = std::max({a, b, c});
269 }
else if (element.type == 5) {
271 const auto& v0 =
m_vertices[element.vertex[0]];
272 const auto& v1 =
m_vertices[element.vertex[1]];
273 const auto& v2 =
m_vertices[element.vertex[2]];
274 const auto& v3 =
m_vertices[element.vertex[3]];
275 vol = fabs((v3[0] - v0[0]) * ((v1[1] - v0[1]) * (v2[2] - v0[2]) -
276 (v2[1] - v0[1]) * (v1[2] - v0[2])) +
277 (v3[1] - v0[1]) * ((v1[2] - v0[2]) * (v2[0] - v0[0]) -
278 (v2[2] - v0[2]) * (v1[0] - v0[0])) +
279 (v3[2] - v0[2]) * ((v1[0] - v0[0]) * (v2[1] - v0[1]) -
280 (v3[0] - v0[0]) * (v1[1] - v0[1]))) /
284 const auto& vj =
m_vertices[element.vertex[j]];
286 const auto& vk =
m_vertices[element.vertex[k]];
288 const double dist = sqrt(pow(vj[0] - vk[0], 2) + pow(vj[1] - vk[1], 2) +
289 pow(vj[2] - vk[2], 2));
293 if (dist < dmin) dmin = dist;
294 if (dist > dmax) dmax = dist;
300 <<
" Unexpected element type (" << type <<
").\n";
304 for (
size_t j = 0; j < nVertices; ++j) {
305 nodes.push_back(element.vertex[j]);
307 reg = element.region;
312 double& z,
double& v,
double& ex,
double& ey,
315 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
331bool ComponentTcad3d::InTetrahedron(
332 const double x,
const double y,
const double z,
const Element& element,
333 std::array<double, nMaxVertices>& w)
const {
334 const auto& v0 =
m_vertices[element.vertex[0]];
335 const auto& v1 =
m_vertices[element.vertex[1]];
336 const auto& v2 =
m_vertices[element.vertex[2]];
337 const auto& v3 =
m_vertices[element.vertex[3]];
338 const double x10 = v1[0] - v0[0];
339 const double y10 = v1[1] - v0[1];
340 const double z10 = v1[2] - v0[2];
342 const double x20 = v2[0] - v0[0];
343 const double y20 = v2[1] - v0[1];
344 const double z20 = v2[2] - v0[2];
346 const double x30 = v3[0] - v0[0];
347 const double y30 = v3[1] - v0[1];
348 const double z30 = v3[2] - v0[2];
350 const double x21 = v2[0] - v1[0];
351 const double y21 = v2[1] - v1[1];
352 const double z21 = v2[2] - v1[2];
354 const double x31 = v3[0] - v1[0];
355 const double y31 = v3[1] - v1[1];
356 const double z31 = v3[2] - v1[2];
358 const double x32 = v3[0] - v2[0];
359 const double y32 = v3[1] - v2[1];
360 const double z32 = v3[2] - v2[2];
362 w[0] = (x - v1[0]) * (y21 * z31 - y31 * z21) +
363 (y - v1[1]) * (z21 * x31 - z31 * x21) +
364 (z - v1[2]) * (x21 * y31 - x31 * y21);
366 w[0] /= x10 * (y31 * z21 - y21 * z31) + y10 * (z31 * x21 - z21 * x31) +
367 z10 * (x31 * y21 - x21 * y31);
368 if (w[0] < 0.)
return false;
370 w[1] = (x - v2[0]) * (-y20 * z32 + y32 * z20) +
371 (y - v2[1]) * (-z20 * x32 + z32 * x20) +
372 (z - v2[2]) * (-x20 * y32 + x32 * y20);
374 w[1] /= x21 * (y20 * z32 - y32 * z20) + y21 * (z20 * x32 - z32 * x20) +
375 z21 * (x20 * y32 - x32 * y20);
376 if (w[1] < 0.)
return false;
378 w[2] = (x - v3[0]) * (y30 * z31 - y31 * z30) +
379 (y - v3[1]) * (z30 * x31 - z31 * x30) +
380 (z - v3[2]) * (x30 * y31 - x31 * y30);
382 w[2] /= x32 * (y31 * z30 - y30 * z31) + y32 * (z31 * x30 - z30 * x31) +
383 z32 * (x31 * y30 - x30 * y31);
384 if (w[2] < 0.)
return false;
386 w[3] = (x - v0[0]) * (y20 * z10 - y10 * z20) +
387 (y - v0[1]) * (z20 * x10 - z10 * x20) +
388 (z - v0[2]) * (x20 * y10 - x10 * y20);
390 w[3] /= x30 * (y20 * z10 - y10 * z20) + y30 * (z20 * x10 - z10 * x20) +
391 z30 * (x20 * y10 - x10 * y20);
392 if (w[3] < 0.)
return false;
396 const double xr = w[0] * v0[0] + w[1] * v1[0] + w[2] * v2[0] + w[3] * v3[0];
397 const double yr = w[0] * v0[1] + w[1] * v1[1] + w[2] * v2[1] + w[3] * v3[1];
398 const double zr = w[0] * v0[2] + w[1] * v1[2] + w[2] * v2[2] + w[3] * v3[2];
400 <<
" Original coordinates: (" << x <<
", " << y <<
", "
402 <<
" Local coordinates: (" << w[0] <<
", " << w[1]
403 <<
", " << w[2] <<
", " << w[3] <<
")\n"
404 <<
" Reconstructed coordinates: (" << xr <<
", " << yr <<
", "
406 <<
" Checksum: " << w[0] + w[1] + w[2] + w[3] - 1. <<
"\n";
412bool ComponentTcad3d::InTriangle(
413 const double x,
const double y,
const double z,
const Element& element,
414 std::array<double, nMaxVertices>& w)
const {
415 const auto& v0 =
m_vertices[element.vertex[0]];
416 const auto& v1 =
m_vertices[element.vertex[1]];
417 const auto& v2 =
m_vertices[element.vertex[2]];
419 const double v1x = v1[0] - v0[0];
420 const double v2x = v2[0] - v0[0];
421 const double v1y = v1[1] - v0[1];
422 const double v2y = v2[1] - v0[1];
423 const double v1z = v1[2] - v0[2];
424 const double v2z = v2[2] - v0[2];
428 const double a = v1y * v2z - v2y * v1z;
429 const double b = v1z * v2x - v2z * v1x;
430 const double c = v1x * v2y - v2x * v1y;
431 const double d = a * v0[0] + b * v0[1] + c * v0[2];
433 if (a * x + b * y + c * z != d)
return false;
439 w[1] = ((
x - v0[0]) * v2y - (y - v0[1]) * v2x) / (v1x * v2y - v1y * v2x);
440 if (w[1] < 0. || w[1] > 1.)
return false;
441 w[2] = ((v0[0] -
x) * v1y - (v0[1] - y) * v1x) / (v1x * v2y - v1y * v2x);
442 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
445 w[0] = 1. - w[1] - w[2];
bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the coordinates of the elementary cell.
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 GetNode(const size_t i, double &x, double &y, double &z, double &v, double &ex, double &ey, double &ez) const
bool GetElement(const size_t i, double &vol, double &dmin, double &dmax, int &type, std::vector< size_t > &nodes, int ®) const
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
ComponentTcad3d()
Constructor.
Interpolation in a field map created by Sentaurus Device.
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
static constexpr size_t nMaxVertices
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
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.
Helper class for searches in field maps.