45 if (
param ==
"potential") source.
throwException(
"<potential> boundary conditions have been permanently renamed to <voltage>");
47 if (
param ==
"voltage")
48 this->readBoundaryConditions(manager, source, voltage_boundary);
50 else if (
param ==
"loop") {
52 double c0 = default_junction_conductivity.c00, c1 = default_junction_conductivity.c11;
53 auto vert = source.
getAttribute<std::string>(
"start-cond");
55 if (vert->find(
',') == std::string::npos) {
56 c1 = boost::lexical_cast<double>(*vert);
60 source,
"tag attribute 'start-cond' has two values, but attribute 'start-cond-inplane' is also provided");
62 c0 = boost::lexical_cast<double>(values.first);
63 c1 = boost::lexical_cast<double>(values.second);
66 c0 = source.
getAttribute<
double>(
"start-cond-inplane", c0);
77 else if (
param ==
"contacts") {
83 else if (!this->parseFemConfiguration(source, manager)) {
84 this->parseStandardConfiguration(source, manager);
93 if (!this->geometry || !this->mesh) {
94 if (junction_conductivity.size() != 1) {
96 for (
auto cond : junction_conductivity)
condy += cond;
97 junction_conductivity.reset(1,
condy /
double(junction_conductivity.size()));
102 this->setupMaskedMesh();
104 auto points = this->mesh->getElementMesh();
106 std::vector<typename Active::Region> regions;
108 for (
size_t r = 0; r < points->axis[1]->size(); ++r) {
111 for (
size_t c = 0; c < points->axis[0]->size(); ++c) {
112 auto point = points->at(c, r);
113 size_t num = isActive(point);
116 if (regions.size() >= num && regions[num - 1].warn) {
118 material = this->geometry->getMaterial(points->at(c, r));
119 else if (*material != *this->geometry->getMaterial(points->at(c, r))) {
121 regions[num - 1].warn =
false;
124 regions.resize(
max(regions.size(), num));
125 auto& reg = regions[num - 1];
128 throw Exception(
"{0}: Junction {1} is disjoint", this->getId(), num - 1);
132 else if (reg.rowr <= c)
133 throw Exception(
"{0}: Junction {1} is disjoint", this->getId(), num - 1);
136 if (reg.left > reg.rowl) reg.left = reg.rowl;
139 if (prev && prev != num) {
140 auto& reg = regions[prev - 1];
141 if (reg.bottom < r && reg.rowl >= c)
throw Exception(
"{0}: Junction {1} is disjoint", this->getId(), prev - 1);
143 if (reg.right < reg.rowr) reg.right = reg.rowr;
148 regions[prev - 1].rowr = regions[prev - 1].right = points->axis[0]->size();
153 active.reserve(regions.size());
155 for (
auto& reg : regions) {
156 if (reg.bottom == std::numeric_limits<size_t>::max()) reg.bottom = reg.top = 0;
157 active.emplace_back(
condsize, reg.left, reg.right, reg.bottom, reg.top,
158 this->mesh->axis[1]->at(reg.top) -
this->mesh->axis[1]->at(reg.bottom));
160 this->
writelog(
LOG_DETAIL,
"Detected junction {0} thickness = {1}nm", i++, 1
e3 * active.back().height);
161 this->
writelog(
LOG_DEBUG,
"Junction {0} span: [{1},{3}]-[{2},{4}]", i - 1, reg.left, reg.right, reg.bottom, reg.top);
164 if (junction_conductivity.size() !=
condsize) {
166 for (
auto cond : junction_conductivity)
condy += cond;
244 for (
auto e : this->maskedMesh->elements()) {
245 if (
size_t nact = isActive(
e)) {
246 size_t i =
e.getIndex();
247 size_t left = this->maskedMesh->index0(
e.getLoLoIndex());
248 size_t right = this->maskedMesh->index0(
e.getUpLoIndex());
252 (potentials[this->maskedMesh->index(left,
act.top)] - potentials[this->maskedMesh->index(left,
act.bottom)] +
253 potentials[this->maskedMesh->index(right,
act.top)] - potentials[this->maskedMesh->index(right,
act.bottom)]);
254 double jy = 0.1 * conds[i].c11 * U /
act.height;
255 size_t ti = this->maskedMesh->element(
e.getIndex0(), (
act.top +
act.bottom) / 2).getIndex();
257 switch (convergence) {
259 cond = 0.5 * (conds[i] + cond);
263 if (
isnan(conds[i].c11) || abs(conds[i].c11) < 1
e-16) conds[i].c11 = 1
e-16;
272 for (
auto e : this->maskedMesh->elements()) {
273 size_t i =
e.getIndex();
287 double kx = conds[i].c00;
288 double ky = conds[i].c11;
299 k43 =
k21 = (-2. * kx + ky) / 6.;
300 k42 =
k31 = -(kx + ky) / 6.;
301 k32 =
k41 = (kx - 2. * ky) / 6.;
304 setLocalMatrix(
k44,
k33,
k22,
k11,
k43,
k21,
k42,
k31,
k32,
k41, ky,
elemwidth,
midpoint);
322 double*
aend = A.data + A.size;
325 throw ComputationError(this->getId(),
"error in stiffness matrix at position {0} ({1})",
pa - A.data,
332 auto midmesh = this->maskedMesh->getElementMesh();
333 auto temperature = inTemperature(midmesh);
335 for (
auto e : this->maskedMesh->elements()) {
336 size_t i =
e.getIndex();
339 auto roles = this->geometry->getRolesAt(
midpoint);
341 const auto&
act = active[
actn - 1];
342 conds[i] = junction_conductivity[
act.offset +
e.getIndex0()];
343 if (
isnan(conds[i].c11) || abs(conds[i].c11) < 1
e-16) conds[i].c11 = 1
e-16;
344 }
else if (roles.find(
"p-contact") != roles.end()) {
346 }
else if (roles.find(
"n-contact") != roles.end()) {
349 conds[i] = this->geometry->getMaterial(
midpoint)->cond(temperature[i]);
364 this->initCalculation();
369 auto vconst = voltage_boundary(this->maskedMesh, this->geometry);
375 std::unique_ptr<FemMatrix>
pA(this->getMatrix());
382 if (!potentials.unique()) this->
writelog(
LOG_DEBUG,
"Voltage data held by something else...");
384 potentials = potentials.claim();
388 auto temperature = loadConductivities();
390 bool noactive = (active.size() == 0);
391 double minj = 100
e-7;
395 A.solve(
rhs, potentials);
399 for (
auto el : this->maskedMesh->elements()) {
400 size_t i = el.getIndex();
401 size_t loleftno = el.getLoLoIndex();
402 size_t lorghtno = el.getUpLoIndex();
403 size_t upleftno = el.getLoUpIndex();
404 size_t uprghtno = el.getUpUpIndex();
406 (el.getUpper0() - el.getLower0());
408 (el.getUpper1() - el.getLower1());
417 double delta =
abs2(currents[i] -
cur);
418 if (delta > err) err = delta;
423 if ((
loop != 0 ||
mcur >=
minj) && err > toterr) toterr = err;
431 }
while ((!this->iter_params.converged || err > maxerr) && (
loops == 0 ||
loop <
loops));
433 saveConductivities();
435 outVoltage.fireChanged();
436 outCurrentDensity.fireChanged();
437 outHeat.fireChanged();
544 if (!potentials)
throw NoValue(
"heat density");
546 if (!heats) saveHeatDensities();
549 if (this->maskedMesh->full()) {
550 auto result =
interpolate(this->mesh->getElementMesh(), heats, dest_mesh, method, flags);
552 return this->geometry->getChildBoundingBox().contains(flags.wrap(dest_mesh->at(i))) ? result[i] : 0.;
555 auto result =
interpolate(this->maskedMesh->getElementMesh(), heats, dest_mesh, method, flags);
558 auto val = result[i];
559 return isnan(val) ? 0. : val;