Skip to content

Conversation

@WHUweiqingzhou
Copy link
Collaborator

@WHUweiqingzhou WHUweiqingzhou commented Nov 6, 2024

Fix #5406

Motivation

For systems that are difficult to converge, the SCF process may exhibit oscillations in charge density, preventing further progress toward the specified convergence criteria and resulting in continuous oscillation until the maximum number of steps is reached; this greatly wastes computational resources. To address this issue, I have designed a new feature that allows ABACUS to terminate the SCF process early upon detecting oscillations, thus reducing subsequent meaningless calculations. The detection of oscillations is based on the slope of the logarithm of historical drho values.

What's Changed?

  1. add a new parameter scf_os_stop. If true, SCF will stop if charge density oscillation is found. The default is false
  2. add a new parameter to control the slope threshold scf_os_thr. The default value is -0.01
  3. add a new parameter scf_os_ndim to control the number of past iterations used in slope calculation. Generally speaking, if the number of oscillation steps persists beyond the steps considered for charge density mixing mixing_ndim, the SCF is unlikely to break free from oscillations. So, I set the default value as the same as mixing_ndim, you can change it.
  4. add a new function Charge_Mixing::if_scf_oscillate to determine if oscillation happens.
  5. add a new member oscillate_esolver, similar to conv_esolver.
  6. add some docs and comments for users.

@WHUweiqingzhou
Copy link
Collaborator Author

If anyone is unsure how to choose scf_thr_os, run this script and check your slope of your drho calculated. I think -0.01 is a good choice.

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <cmath>

bool if_scf_oscillate(std::vector<double>& drho_history, const int iteration, const double drho, const int iternum_used, const double threshold)
{

    if(threshold >= 0) // close the function
    {
        return false;
    }

    // add drho into history
    drho_history[iteration - 1] = drho;

    // check if the history is long enough
    if(iteration < iternum_used)
    {
        return false;
    }

    // calculate the slope of the last iternum_used iterations' drho
    double slope = 0.0;

    // Least Squares Method
    double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0;
    for (int i = iteration - iternum_used; i < iteration; i++)
    {
        sumX += i;
        sumY += std::log10(drho_history[i]);
        sumXY += i * std::log10(drho_history[i]);
        sumXX += i * i;
    }
    double numerator = iternum_used * sumXY - sumX * sumY;
    double denominator = iternum_used * sumXX - sumX * sumX;
    if (denominator == 0) {
        return false;
    }
    slope =  numerator / denominator;

    std::cout << iteration << "-th slope: " << slope << std::endl;

    // if the slope is less than the threshold, return true
    if(slope > threshold)
    {
        return true;
    }

    return false; 
}

int main() {
    std::string filename = "data.txt"; // 替换为你的文件名
    std::ifstream file(filename);
    std::vector<double> numbers;
    std::string line;

    if (file.is_open()) {
        while (getline(file, line)) {
            std::istringstream iss(line);
            double number;
            if (!(iss >> number)) { // 如果转换失败,跳过这个数字
                continue;
            }
            numbers.push_back(number);
        }
        file.close();
    } else {
        std::cerr << "Unable to open file" << std::endl;
        return 1;
    }

    int scf_nmax = 10;
    int scf_os_ndim = 3;
    double scf_thr_os = -0.05;

    std::vector<double> drho_history;
    drho_history.resize(scf_nmax);

    bool oscillate = false;

    for (int i = 1; i <= numbers.size(); i++) {
        oscillate = if_scf_oscillate(drho_history, i, numbers[i-1], scf_os_ndim, scf_thr_os);
        if (oscillate) {
            std::cout << "Oscillation detected at iteration " << i << std::endl;
        }
    }

    return 0;
}

@mohanchen mohanchen added the Features Needed The features are indeed needed, and developers should have sophisticated knowledge label Nov 6, 2024
@WHUweiqingzhou WHUweiqingzhou merged commit 0d455cb into deepmodeling:develop Nov 7, 2024
14 checks passed
@WHUweiqingzhou WHUweiqingzhou deleted the drho branch November 7, 2024 02:08
Fisherd99 pushed a commit to Fisherd99/abacus-BSE that referenced this pull request Mar 31, 2025
…s found (deepmodeling#5421)

* add an input parameter to control the threshold for SCF oscillation

* add a function to tell whether SCF oscillates

* add a member oscillate_esolver in esolver_ks.h, similar to conv_esolver

* add a read-in test for scf_thr_os

* add a read-in test for scf_ene_thr

* add a new parameter scf_os_ndim and corresponding test

* set scf_os_ndim as mixing_ndim if default

* add a UnitTest for new function

* add some docs and comments

* add a new parameter scf_os_stop

* use scf_os_stop to control esovler

* rename scf_thr_os as scf_os_thr

* update the docs of scf_os_thr

* add a value-check for scf_os_thr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Features Needed The features are indeed needed, and developers should have sophisticated knowledge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: SCF should stop if the oscillation steps of drho exceed mixing_ndim

2 participants