#include "lbfgs.h" #include "source_pw/module_pwdft/global.h" #include "source_base/matrix3.h" #include "source_io/module_parameter/parameter.h" #include "ions_move_basic.h" #include "source_cell/update_cell.h" #include "source_cell/print_cell.h" // mohan add 2025-06-19 void LBFGS::allocate(const int _size) // initialize H0、H、pos0、force0、force { alpha=70;//default value in ase is 70 maxstep=PARAM.inp.relax_bfgs_rmax; size=_size; memory=100; iteration=0; H = std::vector>(3*size, std::vector(3*size, 0.0)); H0=1/alpha; pos = std::vector> (size, std::vector(3, 0.0)); pos0 = std::vector(3*size, 0.0); pos_taud = std::vector> (size, std::vector(3, 0.0)); pos_taud0 = std::vector(3*size, 0.0); dpos = std::vector>(size, std::vector(3, 0.0)); force0 = std::vector(3*size, 0.0); force = std::vector>(size, std::vector(3, 0.0)); steplength = std::vector(size, 0.0); //l_search.init_line_search(); } void LBFGS::relax_step(const ModuleBase::matrix _force,UnitCell& ucell,const double &etot) { get_pos(ucell,pos); get_pos_taud(ucell,pos_taud); //solver=p_esolver; ucell.ionic_position_updated = true; for(int i = 0; i < _force.nr; i++) { for(int j=0;j<_force.nc;j++) { force[i][j]=_force(i,j)*ModuleBase::Ry_to_eV/ModuleBase::BOHR_TO_A; } } int k=0; for(int i=0;iprepare_step(force,pos,H,pos0,force0,dpos,ucell,etot); this->determine_step(steplength,dpos,maxstep); this->update_pos(ucell); this->calculate_largest_grad(_force,ucell); this->is_restrain(dpos); // mohan add 2025-06-22 unitcell::print_tau(ucell.atoms,ucell.Coordinate,ucell.ntype,ucell.lat0,GlobalV::ofs_running); } void LBFGS::get_pos(UnitCell& ucell,std::vector>& pos) { int k=0; for(int i=0;i>& pos_taud) { int k=0; for(int i=0;i>& force, std::vector>& pos, std::vector>& H, std::vector& pos0, std::vector& force0, std::vector>& dpos, UnitCell& ucell, const double &etot) { std::vector changedforce = ReshapeMToV(force); std::vector changedpos = ReshapeMToV(pos); this->update(pos_taud,pos_taud0,changedforce,force0,ucell,iteration,memory,s,y,rho); std::vector q=DotInVAndFloat(changedforce,-1); int loopmax=std::min(memory,iteration); std::vector a(loopmax); for(int i=loopmax-1;i>=0;i--) { a[i]=rho[i]*DotInVAndV(s[i],q); std::vector temp=DotInVAndFloat(y[i],a[i]); q=VSubV(q,temp); } std::vector z=DotInVAndFloat(q,H0); for(int i=0;i temp=DotInVAndFloat(s[i],a[i]-b); z=VAddV(z,temp); } std::vector temp0=DotInVAndFloat(z,-1); dpos=ReshapeVToM(temp0); std::vector temp1=DotInVAndFloat(changedforce,-1); std::vector> g=ReshapeVToM(temp1); energy=etot; //alpha_k=l_search.line_search(ucell,pos,g,energy,maxstep,size,dpos,pos,solver); //std::vector temp2=DotInVAndFloat(temp0,alpha_k); std::vector temp2=DotInVAndFloat(temp0,1); dpos=ReshapeVToM(temp2); for(int i = 0; i < size; i++) { double k = 0; for(int j = 0; j < 3; j++) { k += dpos[i][j] * dpos[i][j]; } steplength[i] = sqrt(k); } iteration+=1; pos0 = ReshapeMToV(pos); pos_taud0=ReshapeMToV(pos_taud); force0 = changedforce; } void LBFGS::update(std::vector>& pos_taud, std::vector& pos_taud0, std::vector& force, std::vector& force0, UnitCell& ucell, int iteration, int memory, std::vector>& s, std::vector>& y, std::vector& rho) { if(iteration>0) { std::vector term=ReshapeMToV(pos_taud); std::vector dpos =VSubV(term, pos_taud0); for(int i=0;i<3*size;i++) { double shortest_move = dpos[i]; for (int cell = -1; cell <= 1; ++cell) { const double now_move = dpos[i] + cell; if (std::abs(now_move) < std::abs(shortest_move)) { shortest_move = now_move; } } dpos[i]=shortest_move; } std::vector> c=ReshapeVToM(dpos); for(int iat=0; iat move_ion_cart; move_ion_cart.x = c[iat][0] *ModuleBase::BOHR_TO_A * ucell.lat0; move_ion_cart.y = c[iat][1] * ModuleBase::BOHR_TO_A * ucell.lat0; move_ion_cart.z = c[iat][2] * ModuleBase::BOHR_TO_A * ucell.lat0; //convert pos ModuleBase::Vector3 move_ion_dr = move_ion_cart* ucell.latvec; int it = ucell.iat2it[iat]; int ia = ucell.iat2ia[iat]; Atom* atom = &ucell.atoms[it]; if(atom->mbl[ia].x == 1) { dpos[iat * 3] = move_ion_dr.x; } if(atom->mbl[ia].y == 1) { dpos[iat * 3 + 1] = move_ion_dr.y ; } if(atom->mbl[ia].z == 1) { dpos[iat * 3 + 2] = move_ion_dr.z ; } } std::vector dforce =VSubV(force0, force); double rho0=1.0/DotInVAndV(dpos,dforce); s.push_back(dpos); y.push_back(dforce); rho.push_back(rho0); } if(iteration>memory) { s.erase(s.begin()); y.erase(y.begin()); rho.erase(rho.begin()); } } void LBFGS::determine_step(std::vector& steplength,std::vector>& dpos,double& maxstep) { std::vector::iterator maxsteplength = max_element(steplength.begin(), steplength.end()); double a = *maxsteplength; if(a >= maxstep) { double scale = maxstep / a; for(int i = 0; i < size; i++) { for(int j=0;j<3;j++) { dpos[i][j]*=scale; } } } } void LBFGS::update_pos(UnitCell& ucell) { double a[3*size]; for(int i=0;i>& dpos) { Ions_Move_Basic::converged = Ions_Move_Basic::largest_grad * ModuleBase::Ry_to_eV / 0.529177 grad= std::vector(3*size, 0.0); int iat = 0; for (int it = 0; it < ucell.ntype; it++) { Atom *atom = &ucell.atoms[it]; for (int ia = 0; ia < ucell.atoms[it].na; ia++) { for (int ik = 0; ik < 3; ++ik) { if (atom->mbl[ia][ik]) { grad[3 * iat + ik] = -_force(iat, ik) * ucell.lat0; } } ++iat; } } Ions_Move_Basic::largest_grad = 0.0; for (int i = 0; i < 3*size; i++) { if (Ions_Move_Basic::largest_grad < std::abs(grad[i])) { Ions_Move_Basic::largest_grad = std::abs(grad[i]); } } Ions_Move_Basic::largest_grad /= ucell.lat0; if (PARAM.inp.out_level == "ie") { std::cout << " LARGEST GRAD (eV/Angstrom) : " << Ions_Move_Basic::largest_grad * ModuleBase::Ry_to_eV / 0.5291772109 << std::endl; } }