TABLE OF CONTENTS


::pwtk::runPW_remedy

SYNOPSIS

proc ::pwtk::runPW_remedy {args} {

USAGE

   runPW_remedy [remedy-options] [runPW-options] input ?output?

   The remedy-options are:    
     -reduceconv FACTOR
     -nsteps NUMBER
     -script SCRIPT
     -nlevels NUMBER
     -remedy1st
     -restart

   For the runPW-options see the options of ::pwtk::runPW

PURPOSE

A variant of ::pwtk::runPW with a mechanism for dealing with SCF convergence problems.

OPTIONS

The remedy-options are the following:

ARGUMENTS

DESCRIPTION

The ::pwtk::runPW_remedy behaves like ::pwtk::runPW but if the SCF fails, it tries to remedy it by making a calculation in "remedy" mode where the pw.x input will be changed by the instructions provided with the -script option. If the SCF converges with the remedy calculation, then the calculation is restarted in normal mode. If even the remedy calculation fails and -reduceconv option was specified, then another remedy calculation is performed with the reduced conv_thr threshold.

The names of the I/O files of remedy calculations are prefixed with "__remedy-N__", where N is the sequential number of a given remedy calculation.

EXAMPLE

   ::pwtk::runPW_remedy -script {
       CONTROL { calculation = 'scf' }
       SYSTEM { degauss = 0.05 }
       ::pwtk::pwi::disableDipoleCorr
   } relax.in

SOURCE

    variable error
    variable state
    variable remedy_level
    variable run_options
    variable run_extra_options
    variable run
    
    # query the calculation type and for non-allowed calculation, raise an error
    set calc [::pwtk::input::namelistGetVarValue CONTROL calculation trim]
    ifset calc scf
    switch -glob -- $calc {
        scf - relax - vc-relax {}
        default {
            ::pwtk::error "[procName] does not work for \"calculation = '$calc'\";\nit supports only 'scf', 'relax', and 'vc-relax' calculations" 1
        }
    }
    
    incr remedy_level

    if { $remedy_level == 1 } {
        printTitle REMEDY "Running pw.x in \"remedy\" mode"
    }

    set remedy_options {
        {reduceconv.arg  1.0 "reduce the conv_thr if remedy calculation fails and make another trial"}
        {nsteps.arg      2   "how many ionic steps to run in remedy mode"}
        {script.arg      {}  "script to execute before runing the remedy calculation (the purpose of the script is to modify the pw.x input)"}
        {nlevels.arg     5   "number of remedy trials before aborting"}
        {remedy1st     "run first in remedy mode"}
        {restart       "run the first calculation in restart mode (e.g., restart from the scf-failed calculation"}
    }
    
    set args_orig $args
    array set opt [::cmdline::getKnownOptions args $remedy_options]    
    
    set argums $args    
    ::cmdline::getoptions argums [concat $run_options $run_extra_options] "\n\nUsage: ::pwtk::runPW_remedy \[options\] input ?output?\n\nOptions are:"
    
    set argums_len [llength $argums]
    set args_len   [llength $args]
    if { $argums_len < 1 || $argums_len > 2 } {
        ::pwtk::error [::cmdline::usage [concat $run_options $run_extra_options] "\n\nUsage: ::pwtk::runPW_remedy \[options\] input ?output?"] 1
    } else {
        set pw_options [lrange $args 0 [expr $args_len - $argums_len - 1]]
    }
    
    set input  [lindex $argums 0]
    set output [lindex $argums 1]   
    ifset output [outputName_ $input]    
    
    set runPW runPW
    if { $opt(restart) } {
        set runPW rerunPW
    }
    
    # check the values of options
    ::pwtk::checkOTypeStrict_ -reduceconv $opt(reduceconv) {number real} "real number"
    ::pwtk::checkOTypeStrict_ -nsteps     $opt(nsteps) {number posint} "positive integer"
    ::pwtk::checkOTypeStrict_ -nlevels    $opt(nlevels) {number posint} "positive integer"
    
    input_pushpop {
        set disk_io [::pwtk::input::namelistGetVarValue CONTROL disk_io trim]
        if { $disk_io ne "high" || $disk_io ne "medium" } {        
            infoMsg "temporarily setting disk_io = 'medium'"
            CONTROL { disk_io = 'medium' }
        }    

        # BEWARE where state() is modified wrt input_pushpop
        set stopOnError_orig $state(stopOnError)
        set state(stopOnError) -1; # BEWARE: has to be -1 (see ::pwtk::checkForError)

        if { ! $opt(remedy1st) } {
            #
            # NORMAL mode
            #

            ::pwtk::print REMEDY-#$remedy_level "Running calculation in normal mode\n"

            #------------------------------------------------------------------------
            eval $runPW $pw_options $input $output
            if { $error(type) eq {} } { ::pwtk::print REMEDY-#$remedy_level "SUCCESS: calculation converged !!!\n" }
            #------------------------------------------------------------------------

            set runPW rerunPW
            set output $run(output)
        }

        if { $remedy_level > $opt(nlevels) && $error(type) == "convergence failure" } {
            # if there is already too many remedy trials, abort as to
            # prevent too many trials
            if { $stopOnError_orig } {
                ::pwtk::error "Too many trials of runPW_remedy. Aborting ..." 1
            } else {
                ::pwtk::warning "Too many trials of runPW_remedy. Giving up ..."
            }
        } elseif { (! $opt(remedy1st) && $error(type) == "convergence failure") || $opt(remedy1st) } {
            #
            # REMEDY mode (r.m.)
            #        
            # i.e.: either a convergence failure or a "remedy1st" request
            
            set head [::pwtk::trim_prefix $calc [::pwtk::headname $input]]
            set head __remedy-${remedy_level}__.$head
            
            ::pwtk::print REMEDY-#$remedy_level "Trying to remedy SCF convergence problems using the following instructions:\n"
            ::pwtk::print $opt(script)\n

            #1: try with the supplied script
            input_pushpop {
                
                if { [string match *relax $calc] }  {
                    # remedy mode should make only $opt(nsteps) ionic steps
                    if { [file exists $output] } {
                        set curr_cycles [::pwtk::grep_field "number of scf cycles" $pwo end end]
                    }
                    ifset curr_cycles 0
                    CONTROL " nstep = [expr $curr_cycles + $opt(nsteps)] "
                }

                # eval the REMEDY script
                eval $opt(script)
                
                if { $opt(reduceconv) <= 1.0} {
                    # do not retry if the remedy #1 calculation fails, hence
                    # treat the stopOnError by original (default) way
                    set state(stopOnError) $stopOnError_orig
                }

                ::pwtk::print REMEDY-#$remedy_level "Runing the remedy calculation\n"
                
                #---remedy #1----------------
                eval $runPW $pw_options $head 
                #----------------------------

                set runPW rerunPW
                set state(stopOnError) $stopOnError_orig        
                
                if { $error(type) == "convergence failure" && $opt(reduceconv) > 1.0} {
                    #
                    ::pwtk::print REMEDY-#$remedy_level "The remedy calculation failed !\n"

                    #2: try by reducing conv_thr
                    input_pushpop {
                        # reduce the conv_thr and make another trial; but do not go beyond conv_thr = 1e-4
                        set conv_thr     [::pwtk::pwi::reduceConvThr $opt(reduceconv)]
                        
                        if { [string match *relax $calc] }  {
                            ::pwtk::print REMEDY-#$remedy_level "Temporarily setting upscale = 1.0"
                            IONS { upscale = 1.0 }              
                        }   
                        ::pwtk::print REMEDY-#$remedy_level "Temporarily loosing the SCF conv_thr by a factor of $opt(reduceconv)
* new value of conv_thr = [format %7.2e $conv_thr]\n"

                        file copy -force $head.in $head.fail.in
                        
                        #---remedy #2------------------------
                        eval $runPW $pw_options -append $head
                        if { $error(type) eq {} } { ::pwtk::print REMEDY-#$remedy_level "SUCCESS: calculation converged !!!\n" }
                        #------------------------------------
                    }; #2
                }    
            }; #1
            
            set state(stopOnError) $stopOnError_orig

            # for $stopOnError_orig == true: if we come thus far, the remedy calculation converged;
            # restart a "normal" calculation via the recursive call to runPW_remedy -restart
            
            # strip the -restart & -remedy1st options 
            array set opt [::cmdline::getKnownOptions args_orig {{restart ""} {remedy1st ""}} ]
            
            #------------------------------------
            eval runPW_remedy -restart $args_orig
            #------------------------------------
        }; # REMEDY-mode (r.m.)
        # BEWARE no need to revert state(stopOnError) due to input_pushpop
    }; # input_pushpop
    
    incr remedy_level -1
}