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";
240 if (element.type == 0) {
241 dmin = dmax = vol = 0;
242 }
else if (element.type == 1) {
243 const auto& v0 =
m_vertices[element.vertex[0]];
244 const auto& v1 =
m_vertices[element.vertex[1]];
245 const double d = std::hypot(v1[0] - v0[0], v1[1] - v0[1]);
246 dmin = dmax = vol = d;
248 const auto& v0 =
m_vertices[element.vertex[0]];
249 const auto& v1 =
m_vertices[element.vertex[1]];
250 const auto& v2 =
m_vertices[element.vertex[2]];
251 vol = 0.5 * fabs((v2[0] - v0[0]) * (v1[1] - v0[1]) -
252 (v2[1] - v0[1]) * (v1[0] - v0[0]));
253 const double a = std::hypot(v1[0] - v0[0], v1[1] - v0[1]);
254 const double b = std::hypot(v2[0] - v0[0], v2[1] - v0[1]);
255 const double c = std::hypot(v1[0] - v2[0], v1[1] - v2[1]);
256 dmin = std::min({a, b, c});
257 dmax = std::max({a, b, c});
259 const auto& v0 =
m_vertices[element.vertex[0]];
260 const auto& v1 =
m_vertices[element.vertex[1]];
261 const auto& v3 =
m_vertices[element.vertex[3]];
262 const double a = std::hypot(v1[0] - v0[0], v1[1] - v0[1]);
263 const double b = std::hypot(v3[0] - v0[0], v3[1] - v0[1]);
265 dmin = std::min(a, b);
266 dmax = sqrt(a * a + b * b);
269 <<
" Unexpected element type (" << type <<
")\n";
273 for (
size_t j = 0; j < nVertices; ++j) {
274 nodes.push_back(element.vertex[j]);
276 reg = element.region;
281 double& v,
double& ex,
double& ey)
const {
283 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
297size_t ComponentTcad2d::FindElement(
const double x,
const double y,
298 std::array<double, nMaxVertices>& w)
const {
302 std::vector<int> elementsToSearch;
303 if (m_tree) elementsToSearch = m_tree->GetElementsInBlock(x, y);
304 const size_t nElementsToSearch = m_tree ? elementsToSearch.size() :
m_elements.size();
305 for (
size_t i = 0; i < nElementsToSearch; ++i) {
306 const size_t idx = m_tree ? elementsToSearch[i] : i;
307 if (InElement(x, y,
m_elements[idx], w))
return idx;
312 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
317bool ComponentTcad2d::InElement(
const double x,
const double y,
319 std::array<double, nMaxVertices>& w)
const {
320 if (x < element.bbMin[0] || x > element.bbMax[0] ||
321 y < element.bbMin[1] || y > element.bbMax[1]) {
324 switch (element.type) {
326 return AtPoint(x, y, element, w);
328 return OnLine(x, y, element, w);
330 return InTriangle(x, y, element, w);
332 return InRectangle(x, y, element, w);
335 <<
" Unknown element type. Program bug!\n";
341bool ComponentTcad2d::InRectangle(
const double x,
const double y,
343 std::array<double, nMaxVertices>& w)
const {
344 const auto& v0 =
m_vertices[element.vertex[0]];
345 const auto& v1 =
m_vertices[element.vertex[1]];
346 const auto& v3 =
m_vertices[element.vertex[3]];
347 if (y < v0[1] || x > v3[0] || y > v1[1])
return false;
350 const double u = (
x - 0.5 * (v0[0] + v3[0])) / (v3[0] - v0[0]);
351 const double v = (
y - 0.5 * (v0[1] + v1[1])) / (v1[1] - v0[1]);
353 w[0] = (0.5 - u) * (0.5 - v);
354 w[1] = (0.5 - u) * (0.5 + v);
355 w[2] = (0.5 + u) * (0.5 + v);
356 w[3] = (0.5 + u) * (0.5 - v);
360bool ComponentTcad2d::InTriangle(
const double x,
const double y,
362 std::array<double, nMaxVertices>& w)
const {
363 const auto& v0 =
m_vertices[element.vertex[0]];
364 const auto& v1 =
m_vertices[element.vertex[1]];
365 const auto& v2 =
m_vertices[element.vertex[2]];
366 if (x > v1[0] && x > v2[0])
return false;
367 if (y < v0[1] && y < v1[1] && y < v2[1])
return false;
368 if (y > v0[1] && y > v1[1] && y > v2[1])
return false;
374 const double sx = v1[0] - v0[0];
375 const double sy = v1[1] - v0[1];
376 const double tx = v2[0] - v0[0];
377 const double ty = v2[1] - v0[1];
378 const double d = 1. / (sx * ty - sy * tx);
379 w[1] = ((
x - v0[0]) * ty - (y - v0[1]) * tx) * d;
380 if (w[1] < 0. || w[1] > 1.)
return false;
381 w[2] = ((v0[0] -
x) * sy - (v0[1] - y) * sx) * d;
382 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
385 w[0] = 1. - w[1] - w[2];
390bool ComponentTcad2d::OnLine(
const double x,
const double y,
392 std::array<double, nMaxVertices>& w)
const {
393 const auto& v0 =
m_vertices[element.vertex[0]];
394 const auto& v1 =
m_vertices[element.vertex[1]];
395 if (x > v1[0])
return false;
396 if (y < v0[1] && y < v1[1])
return false;
397 if (y > v0[1] && y > v1[1])
return false;
398 const double tx = (
x - v0[0]) / (v1[0] - v0[0]);
399 if (tx < 0. || tx > 1.)
return false;
400 const double ty = (
y - v0[1]) / (v1[1] - v0[1]);
401 if (ty < 0. || ty > 1.)
return false;
411bool ComponentTcad2d::AtPoint(
const double x,
const double y,
413 std::array<double, nMaxVertices>& w)
const {
414 const auto& v0 =
m_vertices[element.vertex[0]];
415 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.
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
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.