Skip to content

Commit 02db2eb

Browse files
committed
add a version of enforce detailed balance to the phonon scattering matrix
1 parent b000023 commit 02db2eb

File tree

10 files changed

+140
-36
lines changed

10 files changed

+140
-36
lines changed

src/algebra/PMatrix.cpp

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,10 @@ ParallelMatrix<double>::elpaDiagonalize() {
174174
if( eigenvalues[0] < 0 ) { // negative modes were found
175175
if(mpi->mpiHead()) {
176176
Warning("Relaxons diagonalization found negative eigenvalues."
177-
"\n\tThis can happen when there's a bit of numerical noise on the scattering matrix,"
178-
"\n\tand finding them may indicate the calculation is unconverged."
177+
"\n\tThis can happen when there's a numerical issue with the scattering matrix."
179178
"\n\tWhile we simply do not include these when computing transport, "
180-
"\n\tand likely if they are small the calculation will be unaffected, "
181-
"\n\tyou may want to consider using with more wavevectors or an improved DFT calculation."
182-
"\n\tAdditionally, setting symmetrizeMatrix = true in your input file will help.");
179+
"\n\tand likely if they are very small the calculation will be unaffected, "
180+
"\n\tplease view the relaxons tutorial for advice about resolving this.");
183181
std::cout << "These eigenvalues are (in atomic units):" << std::endl;
184182
for (int i = 0; eigenvalues[i] <= 0; i++) {
185183
std::cout << i << " " << eigenvalues[i] << std::endl;
@@ -292,11 +290,10 @@ ParallelMatrix<double>::scalapackDiagonalize() {
292290
if( eigenvalues[0] < 0 ) { // negative modes were found
293291
if(mpi->mpiHead()) {
294292
Warning("Relaxons diagonalization found negative eigenvalues."
295-
"\n\tThis can happen when there's a bit of numerical noise on the scattering matrix,"
296-
"\n\tand finding them may indicate the calculation is unconverged."
293+
"\n\tThis can happen when there's a numerical issue with the scattering matrix."
297294
"\n\tWhile we simply do not include these when computing transport, "
298-
"\n\tyou may want to consider using with more wavevectors or an improved DFT calculation."
299-
"\n\tAdditionally, setting symmetrizeMatrix = true in your input file will help.");
295+
"\n\tand likely if they are very small the calculation will be unaffected, "
296+
"\n\tplease view the relaxons tutorial for advice about resolving this.");
300297
std::cout << "These eigenvalues are (in atomic units):" << std::endl;
301298
for (int i = 0; eigenvalues[i] <= 0; i++) {
302299
std::cout << i << " " << eigenvalues[i] << std::endl;
@@ -486,11 +483,10 @@ std::tuple<std::vector<double>, ParallelMatrix<double>>
486483
if(mpi->mpiHead()) {
487484
Warning("Relaxons diagonalization found " + std::to_string(m) +
488485
" in the range -1 < eigenvalues <= 0."
489-
"\n\tThis can happen when there's a bit of numerical noise on the scattering matrix,"
490-
"\n\tand finding them may indicate the calculation is unconverged."
491-
"\n\tWhile we simply do not include these when computing transport, "
492-
"\n\tyou may want to consider using with more wavevectors or an improved DFT calculation."
493-
"\n\tAdditionally, setting symmetrizeMatrix = true in your input file will help.");
486+
"\n\tThis can happen when there's a numerical issue with the scattering matrix."
487+
"\n\tWhile we simply do not include these when computing transport, "
488+
"\n\tand likely if they are very small the calculation will be unaffected, "
489+
"\n\tplease view the relaxons tutorial for advice about resolving this.");
494490
std::cout << "These eigenvalues are (in atomic units):" << std::endl;
495491

496492
for (int i = 0; i < m; i++) {

src/apps/coupled_bte_app.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ void CoupledTransportApp::checkRequirements(Context &context) {
169169
throwErrorIfUnset(context.getTemperatures(), "temperatures");
170170
throwErrorIfUnset(context.getSmearingMethod(), "smearingMethod");
171171
if (context.getSmearingMethod() == DeltaFunction::gaussian) {
172-
throwErrorIfUnset(context.getSmearingWidth(), "smearingWidth");
172+
if (std::isnan(context.getElSmearingWidth()) || !std::isnan(context.getPhSmearingWidth())) {
173+
throwErrorIfUnset(context.getSmearingWidth(), "smearingWidth");
174+
}
173175
}
174176
if (!context.getElphFileName().empty()) {
175177
throwErrorIfUnset(context.getElectronH0Name(), "electronH0Name");

src/bte/coupled_scattering_matrix.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <map>
1212
/*
1313
enum DragType {
14-
elph,
14+
elph,
1515
phel
1616
};
1717
*/
@@ -191,12 +191,12 @@ void CoupledScatteringMatrix::builder(std::shared_ptr<VectorBTE> linewidth,
191191
if (!std::isnan(context.getBoundaryLength())) {
192192
if (context.getBoundaryLength() > 0.) {
193193
// phonon boundary scattering
194-
//addBoundaryScattering(*this, context, inPopulations, outPopulations,
195-
// innerBandStructure, linewidth);
196-
//std::cout << std::endl;
194+
addBoundaryScattering(*this, context, inPopulations, outPopulations,
195+
innerBandStructure, linewidth);
196+
std::cout << std::endl;
197197
// electron boundary scattering
198-
//addBoundaryScattering(*this, context, inPopulations, outPopulations,
199-
// outerBandStructure, linewidth);
198+
addBoundaryScattering(*this, context, inPopulations, outPopulations,
199+
outerBandStructure, linewidth);
200200
}
201201
}
202202

@@ -620,7 +620,7 @@ std::vector<std::vector<std::tuple<std::vector<int>, int>>>
620620
}
621621

622622
// reweight the matrix quadrants
623-
void CoupledScatteringMatrix::reweightQuadrants() {
623+
/* void CoupledScatteringMatrix::reweightQuadrants() {
624624
625625
// TODO if we use linewidths also apply 2 to them
626626
@@ -668,7 +668,7 @@ void CoupledScatteringMatrix::reweightQuadrants() {
668668
}
669669
}
670670
}
671-
671+
*/
672672
BaseBandStructure* CoupledScatteringMatrix::getPhBandStructure() { return &innerBandStructure; }
673673
BaseBandStructure* CoupledScatteringMatrix::getElBandStructure() { return &outerBandStructure; }
674674

src/bte/coupled_scattering_matrix.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class CoupledScatteringMatrix : virtual public BaseElScatteringMatrix,
104104

105105
/** Function to reweight the different quadrants of the matrix
106106
* coupled matrix to account for spin dengeneracy */
107-
void reweightQuadrants();
107+
//void reweightQuadrants();
108108

109109
// friend functions for adding scattering rates
110110
// see respective header files for more details

src/bte/el_scattering_matrix.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,8 @@ void ElScatteringMatrix::builder(std::shared_ptr<VectorBTE> linewidth,
4949
getIteratorWavevectorPairs(rowMajor);
5050

5151
// add scattering contributions ---------------------------------------
52+
5253
// add elph scattering
53-
// TODO are we sure this should get two Fermi's and not have one of them be a Bose?
54-
5554
{ // let the interaction elph go out of scope after this, it takes a lot of memory
5655

5756
// load the elph coupling
@@ -61,6 +60,7 @@ void ElScatteringMatrix::builder(std::shared_ptr<VectorBTE> linewidth,
6160
InteractionElPhWan couplingElPh =
6261
InteractionElPhWan::parse(context, crystal, phononH0);
6362

63+
if(mpi->mpiHead()) std::cout << std::endl;
6464
addElPhScattering(*this, context, inPopulations, outPopulations,
6565
kPairIterator, innerFermi, //outerFermi,
6666
innerBandStructure, outerBandStructure, phononH0,

src/bte/ph_scattering_matrix.cpp

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ void PhScatteringMatrix::builder(std::shared_ptr<VectorBTE> linewidth,
5151

5252
Crystal crystal = innerBandStructure.getPoints().getCrystal();
5353

54+
bool usePhElScattering = !context.getElphFileName().empty();
55+
5456
// here we call the function to add ph-ph scattering
5557
if(!context.getPhFC3FileName().empty()) {
5658
// read this in and let it go out of scope afterwards
@@ -158,7 +160,14 @@ void PhScatteringMatrix::builder(std::shared_ptr<VectorBTE> linewidth,
158160

159161
// recalculate the phonon linewidths from the off diagonals
160162
// we should do this if phel is not involved, otherwise it wipes out phel
161-
//enforceDetailedBalance();
163+
if(context.getEnforceDetailedBalance()) {
164+
if(usePhElScattering) {
165+
Warning("Ignoring request to enforce detailed balance on the scattering matrix,"
166+
"as this will erase the ph-el contribution along the diagonal!");
167+
} else {
168+
enforceDetailedBalance();
169+
}
170+
}
162171

163172
// some phonons like acoustic modes at the gamma, with omega = 0,
164173
// might have zero frequencies, and infinite populations. We set those
@@ -246,5 +255,102 @@ void PhScatteringMatrix::builder(std::shared_ptr<VectorBTE> linewidth,
246255
}
247256
}
248257

258+
void PhScatteringMatrix::enforceDetailedBalance() {
259+
260+
// kill the function if it's used inappropriately
261+
if(isMatrixOmega) { // If this matrix has not been symmetrized, this function won't work
262+
DeveloperError("enforceDetailedBalance should not be called on a matrix without symmetrization factors in the ph only case.");
263+
}
264+
if(!highMemory) return; // must be high mem, we explicitly use iCalc=1 here
265+
if(context.getUseSymmetries()) return; // this is not designed for BTE syms, would need to
266+
// change the way we are indexing this
267+
if(context.getUseUpperTriangle()) { // TODO this can be implemented without too much difficulty
268+
Warning("Cannot run enforceDetailedBalance with only upper triangle for now.");
269+
return;
270+
};
271+
272+
if(mpi->mpiHead()) std::cout << "\nEnforcing detailed balance, summing off-diagonals to compute diagonal." << std::endl;
273+
274+
// this only happens when we have one iCalc, and no symmetries -- VectorBTE = an array,
275+
// which we use here because of some trouble with coupledVectorBTE object
276+
Eigen::MatrixXd newLinewidths(1,numStates); // copy matrix which is the same as internal diag
277+
newLinewidths.setZero();
278+
279+
// rebuild the diagonal ---------------------------------
280+
281+
LoopPrint loopPrint("Recalculating the diagonal","matrix elements",getAllLocalStates().size());
282+
283+
// NOTE: if later we want to use symmetries here,
284+
// these would actually be iBTE instead of iState, and we would convert
285+
// sum over the v' states owned by this process
286+
// TODO may want to add OMP here as well as MPI
287+
for (auto [ibte1, ibte2] : getAllLocalStates()) {
288+
289+
loopPrint.update();
290+
291+
// throw out lower triangle states
292+
// FIXME DOESNT WORK!
293+
if(context.getUseUpperTriangle() && ibte1 > ibte2) continue;
294+
295+
// we are computing the diagonal using the off diagonal,
296+
// so these elements won't matter
297+
if(ibte1 == ibte2) continue;
298+
299+
// NOTE state and bte indices are here the same, as we are blocking the use of symmetries
300+
//BteIndex bteIdx1(ibte1);
301+
//BteIndex bteIdx2(ibte2);
302+
StateIndex is1(ibte1);
303+
StateIndex is2(ibte2);
304+
305+
double initialEn = innerBandStructure.getEnergy(is1);
306+
double finalEn = outerBandStructure.getEnergy(is2);
307+
308+
// remove accoustic phonons
309+
if(initialEn < 1e-9 || finalEn < 1e-9) continue;
310+
311+
// calculate the new linewidths
312+
newLinewidths(0,ibte1) -= theMatrix(ibte1,ibte2) * finalEn / initialEn;
313+
}
314+
loopPrint.close();
315+
316+
// sum the element contributions from all processes
317+
mpi->allReduceSum(&newLinewidths);
318+
319+
if(mpi->mpiHead()) {
320+
std::cout << "\nChecking the quality of recalculated ph diagonal elements." << std::endl;
321+
322+
for (int i = 0; i<numStates; i++) {
323+
324+
// don't print zeros
325+
if(newLinewidths(0,i) < 1e-15 && internalDiagonal->data(0,i) < 1e-15) continue;
326+
327+
if(newLinewidths(0,i) < 0 || std::isnan(newLinewidths(0,i))) {
328+
StateIndex sIdx(i);
329+
std::cout << std::setprecision(4) << "Found a negative ph linewidth for state: " << i << " " << innerBandStructure.getEnergy(sIdx) << " " << innerBandStructure.getPoints().cartesianToCrystal(innerBandStructure.getWavevector(sIdx)).transpose() << " " << internalDiagonal->data(0,i) << " " << newLinewidths(0,i) << std::endl;
330+
// replace with the standard one to avoid definite issues
331+
newLinewidths(0,i) = internalDiagonal->data(0, i);
332+
}
333+
// flag bad linewidth ratios
334+
else if(newLinewidths(0,i)/internalDiagonal->data(0,i) < 0.25 || newLinewidths(0,i)/internalDiagonal->data(0,i) > 1.75) {
335+
StateIndex sIdx(i);
336+
std::cout << std::setprecision(4) << "Found a bad ph linewidth for state: " << i << " " << innerBandStructure.getEnergy(sIdx) << " " << innerBandStructure.getPoints().cartesianToCrystal(innerBandStructure.getWavevector(sIdx)).transpose() << " " << newLinewidths(0,i) << " " << internalDiagonal->data(0,i) << " " << newLinewidths(0,i)/internalDiagonal->data(0,i) << std::endl;
337+
newLinewidths(0,i) = std::max(newLinewidths(0,i),internalDiagonal->data(0,i));
338+
}
339+
}
340+
}
341+
342+
// reinsert the linewidths in the scattering matrix
343+
internalDiagonal->data = newLinewidths;
344+
345+
// TODO figure out why this function doesn't work right now
346+
//replaceMatrixLinewidths();
347+
348+
// replace the linewidths on the scattering matrix diagonal
349+
int iCalc = 0;
350+
for (int iMat = 0; iMat < numStates; iMat++) {
351+
// zero the diagonal of the matrix
352+
if(theMatrix.indicesAreLocal(iMat,iMat)) theMatrix(iMat, iMat) = newLinewidths(iCalc, iMat);
353+
}
354+
}
249355

250356

src/bte/ph_scattering_matrix.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class PhScatteringMatrix : virtual public BasePhScatteringMatrix {
4646
std::vector<VectorBTE> &inPopulations,
4747
std::vector<VectorBTE> &outPopulations) override;
4848

49+
void enforceDetailedBalance();
50+
4951
// friend functions for adding scattering rates,
5052
// these live in ph_scattering.cpp
5153
// TODO write docstrings for these

src/bte/scattering_matrix.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,7 @@ void ScatteringMatrix::enforceDetailedBalance() {
14701470
// NOTE: if later we want to use symmetries here,
14711471
// these would actually be iBTE instead of iState, and we would convert
14721472
// sum over the v' states owned by this process
1473+
// TODO may want to add OMP here as well as MPI
14731474
for (auto [ibte1, ibte2] : getAllLocalStates()) {
14741475

14751476
loopPrint.update();
@@ -1501,10 +1502,6 @@ void ScatteringMatrix::enforceDetailedBalance() {
15011502
Particle initialParticle = initialBandStructure->getParticle();
15021503
Particle finalParticle = finalBandStructure->getParticle();
15031504

1504-
// this removes the drag term contributions, for test reasons
1505-
//if(initialParticle.isPhonon() && finalParticle.isElectron()) continue;
1506-
//if(initialParticle.isElectron() && finalParticle.isPhonon()) continue;
1507-
15081505
// shift the indices back to the ones used in bandstructures
15091506
// these indices are for the full matrix, if the matrix is coupled,
15101507
// we need to fold them back into the relevants quadrants in order
@@ -1531,7 +1528,7 @@ void ScatteringMatrix::enforceDetailedBalance() {
15311528
double initialFFm1 = initialParticle.getPopPopPm1(initialEn, kBT, initialChemicalPotential);
15321529
double finalFFm1 = finalParticle.getPopPopPm1(finalEn, kBT, finalChemicalPotential);
15331530

1534-
// spin degeneracy info -- TODO may need to put spin factors here
1531+
// spin degeneracy info -- TODO may need to put spin factors here?
15351532
double initialD = 1;
15361533
double finalD = 1;
15371534

@@ -1607,7 +1604,7 @@ void ScatteringMatrix::enforceDetailedBalance() {
16071604
}
16081605
}
16091606
}
1610-
1607+
/*
16111608
if(mpi->mpiHead()) {
16121609
16131610
std::cout << "compare first 50 el states, new vs. old " << std::setw(2) << std::scientific << std::setprecision(2) << std::endl;
@@ -1637,7 +1634,7 @@ void ScatteringMatrix::enforceDetailedBalance() {
16371634
16381635
}
16391636
std::cout << std::scientific << std::setprecision(4) << std::endl;
1640-
}
1637+
} */
16411638
// reinsert the linewidths in the scattering matrix
16421639
internalDiagonal->data = newLinewidths;
16431640

src/context.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,6 @@ void Context::printInputSummary(const std::string &fileName) {
10221022
// specific to coupled scattering matrix app
10231023
if (appName.find("oupled") != std::string::npos) {
10241024
std::cout << "useDragTerms = " << useDragTerms << std::endl;
1025-
std::cout << "enforceDetailedBalance = " << enforceDetailedBalance << std::endl;
10261025
}
10271026

10281027
if (!std::isnan(constantRelaxationTime))
@@ -1079,7 +1078,8 @@ void Context::printInputSummary(const std::string &fileName) {
10791078
if(numRelaxonsEigenvalues != 0) std::cout << "checkNegativeRelaxons = " << checkNegativeRelaxons << std::endl;
10801079
}
10811080
if(scatteringMatrixInMemory) {
1082-
std::cout << "enforcePositiveSemiDefinite = " << enforcePositiveSemiDefinite << std::endl;
1081+
std::cout << "enforceDetailedBalance = " << enforceDetailedBalance << std::endl;
1082+
// std::cout << "enforcePositiveSemiDefinite = " << enforcePositiveSemiDefinite << std::endl;
10831083
}
10841084
}
10851085

src/observable/viscosity_io.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ int relaxonEigenvectorOverlap(ParallelMatrix<double>& eigenvectors,
3636
std::cout << "\nMaximum scalar product " << eigenvectorName << ".theta_alpha = " << maxOverlap << " at alpha = " << idxMaxOverlap << "." << std::endl;
3737
std::cout << "First ten products with " << eigenvectorName << ":";
3838
for(int gamma = 0; gamma < maxPrint; gamma++) { std::cout << " " << overlaps(gamma); }
39+
std::cout << std::endl;
3940
}
4041

4142
// If the best overlap isn't very good, we return -1 so nothing is skipped

0 commit comments

Comments
 (0)