//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // SDAIonicStepper.cpp // //////////////////////////////////////////////////////////////////////////////// #include "MPIdata.h" #include "SDAIonicStepper.h" using namespace std; //////////////////////////////////////////////////////////////////////////////// void SDAIonicStepper::compute_r(double e0, const vector >& f0) { double fp0; bool wolfe1, wolfe2; // check if the largest component of the force f0 is larger than max_force const double max_force = 0.1; double largest_force = 0.0; for ( int is = 0; is < r0_.size(); is++ ) { for ( int i = 0; i < r0_[is].size(); i++ ) { largest_force = max(largest_force,fabs(f0[is][i])); } } if ( largest_force > max_force ) { if ( MPIdata::onpe0() ) cout << " SDAIonicStepper: force exceeds limit, taking SD step " << endl; // take a steepest descent step with limited displacement and exit const double alpha_sd = max_force/largest_force; // SD step for ( int is = 0; is < r0_.size(); is++ ) { for ( int i = 0; i < r0_[is].size(); i++ ) { rp_[is][i] = r0_[is][i] + alpha_sd * f0[is][i]; } } constraints_.enforce_r(r0_,rp_); rm_ = r0_; r0_ = rp_; atoms_.set_positions(r0_); // reset the SDA algorithm first_step_ = true; return; } // SDA algorithm if ( !first_step_ ) { wolfe1 = e0 < ec_ + fpc_ * sigma1_ * alpha_; // fp0 = -proj(f0,pc) fp0 = 0.0; for ( int is = 0; is < r0_.size(); is++ ) { for ( int i = 0; i < r0_[is].size(); i++ ) { fp0 -= f0[is][i] * pc_[is][i]; } } wolfe2 = fabs(fp0) < sigma2_ * fabs(fpc_); if ( MPIdata::onpe0() ) { cout << " SDAIonicStepper: fpc = " << fpc_ << endl; cout << " SDAIonicStepper: fp0 = " << fp0 << endl; cout << " SDAIonicStepper: ec = " << ec_ << " e0 = " << e0 << endl; cout << " SDAIonicStepper: ec_ + fpc_ * sigma1_ * alpha_ =" << ec_ + fpc_ * sigma1_ * alpha_ << endl; cout << " SDAIonicStepper: wolfe1/wolfe2 = " << wolfe1 << "/" << wolfe2 << endl; } } if ( first_step_ || (wolfe1 && wolfe2) || linmin_.done() ) { // set new descent direction // pc = f0 fc_ = f0; pc_ = fc_; // fpc = d_e / d_alpha in direction pc fpc_ = 0.0; for ( int is = 0; is < r0_.size(); is++ ) { for ( int i = 0; i < r0_[is].size(); i++ ) { fpc_ -= fc_[is][i] * pc_[is][i]; } } ec_ = e0; rc_ = r0_; fp0 = fpc_; // reset line minimizer linmin_.reset(); } alpha_ = linmin_.next_alpha(alpha_,e0,fp0); if ( MPIdata::onpe0() ) cout << " SDAIonicStepper: alpha = " << alpha_ << endl; // rp = rc + alpha * pc for ( int is = 0; is < r0_.size(); is++ ) { for ( int i = 0; i < r0_[is].size(); i++ ) { rp_[is][i] = rc_[is][i] + alpha_ * pc_[is][i]; } } constraints_.enforce_r(r0_,rp_); rm_ = r0_; r0_ = rp_; atoms_.set_positions(r0_); first_step_ = false; }