85 throw std::invalid_argument(
"BandClassifier: projectability_minimum (" +
87 ") must be below projectability_maximum (" +
98 require_classifiable(record);
111 const Real frozen_ceiling =
113 std::map<int, int> kpoints_excluded_from_freeze;
116 for (std::size_t kpoint_index = 0; kpoint_index < record.
projectabilities.size();
118 const std::vector<Real>& projectability = record.
projectabilities[kpoint_index];
122 entry.
roles.reserve(projectability.size());
123 for (std::size_t band = 0; band < projectability.size(); band++) {
124 const bool in_window = energies[band] <= frozen_ceiling;
125 const BandRole role = role_of(projectability[band], in_window);
126 entry.
roles.push_back(role);
129 kpoints_excluded_from_freeze[
static_cast<int>(band)]++;
136 entry.
kept_bands.push_back(
static_cast<int>(band));
138 require_feasible(entry, kpoint_index, number_of_wannier_functions);
139 classification.
kpoints.push_back(std::move(entry));
141 for (
const auto& [band_index, number_of_kpoints] : kpoints_excluded_from_freeze) {
144 return classification;
154 [[nodiscard]]
static int
156 Real fermi_energy_rydberg) {
157 std::size_t common_bands = eigenvalues_rydberg.empty() ? 0 : eigenvalues_rydberg[0].size();
158 for (
const std::vector<Real>& energies : eigenvalues_rydberg) {
159 common_bands = energies.size() < common_bands ? energies.size() : common_bands;
162 for (std::size_t band = 0; band < common_bands; band++) {
165 for (
const std::vector<Real>& energies : eigenvalues_rydberg) {
167 energies[band] < fermi_energy_rydberg -
170 energies[band] > fermi_energy_rydberg +
173 if (below && above) {
188 [[nodiscard]]
BandRole role_of(
Real projectability,
bool in_window)
const {
197 static void require_feasible(
const KPointBandClassification& entry,
198 std::size_t kpoint_index,
199 int number_of_wannier_functions) {
200 if (entry.number_frozen() > number_of_wannier_functions) {
201 throw WannierDiagnosticError(
203 "disentanglement: k-point " + std::to_string(kpoint_index) +
" freezes " +
204 std::to_string(entry.number_frozen()) +
" bands but only " +
205 std::to_string(number_of_wannier_functions) +
206 " Wannier functions were asked for. Lower "
207 "control.interpolation.frozen_window_above_fermi_ev, raise "
208 "projectability_maximum, or ask for more Wannier functions.");
210 if (entry.number_kept() < number_of_wannier_functions) {
211 throw WannierDiagnosticError(
213 "disentanglement: k-point " + std::to_string(kpoint_index) +
" keeps only " +
214 std::to_string(entry.number_kept()) +
" bands, fewer than the " +
215 std::to_string(number_of_wannier_functions) +
216 " Wannier functions asked for. Lower "
217 "control.interpolation.projectability_minimum, or widen "
218 "control.interpolation.bands so more states are available.");
222 static void require_classifiable(
const WannierInputs& record) {
223 const std::vector<std::vector<Real>>& projectabilities = record.projectabilities;
224 const std::vector<std::vector<Real>>& eigenvalues_rydberg = record.eigenvalues_rydberg;
225 if (projectabilities.size() != eigenvalues_rydberg.size()) {
226 throw std::invalid_argument(
"BandClassifier::classify: the projectabilities cover " +
227 std::to_string(projectabilities.size()) +
228 " k-points and the eigenvalues " +
229 std::to_string(eigenvalues_rydberg.size()));
231 if (projectabilities.empty()) {
232 throw std::invalid_argument(
"BandClassifier::classify: no k-points");
234 if (record.number_of_trial_orbitals <= 0) {
235 throw std::invalid_argument(
236 "BandClassifier::classify: number_of_wannier_functions must be positive");
238 for (std::size_t kpoint_index = 0; kpoint_index < projectabilities.size(); kpoint_index++) {
239 if (projectabilities[kpoint_index].size() != eigenvalues_rydberg[kpoint_index].size()) {
240 throw std::invalid_argument(
241 "BandClassifier::classify: k-point " + std::to_string(kpoint_index) +
" has " +
242 std::to_string(projectabilities[kpoint_index].size()) +
243 " projectabilities and " +
244 std::to_string(eigenvalues_rydberg[kpoint_index].size()) +
" eigenvalues");
249 BandClassificationThresholds thresholds_;
BandClassifier(BandClassificationThresholds thresholds)
Inverted thresholds describe no rule, and are refused here rather than at each k-point.
BandClassification classify(const WannierInputs &record) const
static int bands_crossing_fermi(const std::vector< std::vector< Real > > &eigenvalues_rydberg, Real fermi_energy_rydberg)
@ frozen_window_overfull
A k-point freezes more bands than there are Wannier functions.
@ kept_bands_underfull
A k-point keeps fewer bands than there are Wannier functions.
Real frozen_window_above_fermi_rydberg
The window actually applied, in rydberg, after any automatic resolution.
int number_of_bands_crossing_fermi
bool frozen_window_automatic
std::vector< BandExcludedFromFreeze > bands_excluded_from_freeze
Ascending by band.
bool metallic
Whether some band straddles the Fermi level across the mesh.
bool automatic_frozen_window
Apply the published window, AUTOMATIC_WINDOW_RYDBERG, instead of the value above.
Real projectability_maximum
p >= this freezes a band regardless of its energy.
Real frozen_window_above_fermi_rydberg
static constexpr Real CROSSING_MARGIN_RYDBERG
static constexpr Real AUTOMATIC_WINDOW_RYDBERG
The published window for atomic projectors, 2 eV above the Fermi level, in rydberg.
Real projectability_minimum
p < this discards a band, whatever its energy: the singular-gauge rule.
Every k-point's verdict, and the summary of the whole.
std::vector< KPointBandClassification > kpoints
BandClassificationSummary summary
std::vector< int > kept_bands
Band indices that survive, frozen first is NOT assumed; ascending.
std::vector< int > frozen_positions
Positions within kept_bands that are frozen, ascending.
std::vector< BandRole > roles