# -*-shell-script-*-
# dislocation Peierls stress in Molybdenum
# make fs build=R SYS=intel

source "scripts/Examples/Tcl/startup.tcl"

#*******************************************
# Definition of procedures
#*******************************************
proc initmd { n } {
#MD++ setnolog
MD++ setoverwrite
MD++ dirname = runs/mo-peierls-tilt$n
MD++ NNM = 200
}

proc readpot { } { MD++ {
#--------------------------------------------
#Read in potential file
#
potfile = ~/Codes/MD++/potentials/mo_pot readpot
} }

proc create_datebase { } {
    global supercell
    set supercell(-90)    "1 1  1 24  -1 1 0 40   -1 -1  2 3"
    set supercell(-4.54)  "7 7  6 8   -1 1 0 160  -3 -3  7 2"
    set supercell(-4)     "2 2  1 25  -1 1 0 100  -1 -1  4 3"
    set supercell(-3)     "1 1  0 48  -1 1 0 40    0  0  1 8"
    set supercell(-2)     "2 2 -1 20  -1 1 0 80    1  1  4 2"
    set supercell(-1.75)  "5 5 -3 10  -1 1 0 100   3  3 10 1"
    set supercell(-1.5)   "3 3 -2 20  -1 1 0 100   1  1  3 3"
    set supercell(-1.25)  "5 5 -4 8   -1 1 0 80    2  2  5 2"
    set supercell(-1.125) "9 9 -8 4   -1 1 0 80    4  4  9 1"
    set supercell(-1)     "1 1 -1 36  -1 1 0 80    1  1  2 4"
    set supercell(-0.75)  "5 5 -6 10  -1 1 0 100   3  3  5 2"
    set supercell(-0.2)   "9 9 -16 4  -1 1 0 100   8  8  9 1"
    set supercell(0)      "1 1 -2 16  -1 1 0 40    1  1  1 4"
    
    set supercell(4.8)    "-13 -13 -14  4  -1 1 0 120  7 7 -13 1"
    set supercell(4.7)    " -6  -6  -7  8  -1 1 0 120  7 7 -12 1"
    set supercell(4.5)    " -3  -3  -4 15  -1 1 0 125  2 2  -3 3"
    set supercell(4.3)    " -9  -9 -14  5  -1 1 0 125  7 7  -9 1"
    set supercell(4.2)    " -3  -3  -5 15  -1 1 0 125  5 5  -6 1"
    set supercell(4)      " -1  -1  -2 24  -1 1 0  40  1 1  -1 5"
    set supercell(3.5)    " -3  -3  -8  8  -1 1 0 100  4 4  -3 2"
    set supercell(3)      " -1  -1  -4 16  -1 1 0  80  2 2  -1 4"
    set supercell(2.7)    " -1  -1  -6 12  -1 1 0 100  3 3  -1 3"
    set supercell(2.5)    " -1  -1 -10  8  -1 1 0 100  5 5  -1 2"
    set supercell(2.4)    " -1  -1 -20  4  -1 1 0 100 10 10 -1 1"
    set supercell(2)      "  0   0  -1 50  -1 1 0  40  1 1   0 8"
    set supercell(1.75)   "  1   1 -20  4  -1 1 0 100 10 10  1 1"
    set supercell(1.5)    "  1   1 -10  8  -1 1 0  80  5 5   1 1"
    set supercell(1)      "  1   1  -4 12  -1 1 0  80  2 2   1 4"
    set supercell(0.2)    "  4   4  -9  5  -1 1 0  65  9 9   8 1"    
}

proc choose_supercell { tilt } {
    global supercell

    # create perfect crystal
    MD++ crystalstructure = body-centered-cubic
    MD++ latticeconst = 3.1472
    MD++ latticesize = \[ $supercell($tilt) \]
    # overwrite simulation cell height (Ly)        
    MD++ latticesize(7) = 40
}

proc find_burgers_coord { tilt } {
    # compute Burgers vector in scaled coordinate
    set c1x [expr [MD++_Get latticesize(0)] * [MD++_Get latticesize(3)]]
    set c1y [expr [MD++_Get latticesize(1)] * [MD++_Get latticesize(3)]]
    set c1z [expr [MD++_Get latticesize(2)] * [MD++_Get latticesize(3)]]

    set c3x [expr [MD++_Get latticesize(8)] * [MD++_Get latticesize(11)]]
    set c3y [expr [MD++_Get latticesize(9)] * [MD++_Get latticesize(11)]]
    set c3z [expr [MD++_Get latticesize(10)]* [MD++_Get latticesize(11)]]

    set det [expr $c1x*$c3y-$c1y*$c3x]
    #puts "$c1x $c1y $c1z  $c3x $c3y $c3z"
    #puts "det = $det"
    if  { $det != 0 } {
            set a [expr 0.5*($c3y-$c3x) / $det ]
            set b [expr 0.5*($c1x-$c1y) / $det ]
    } else {
            set det [expr $c1z*$c3y-$c1y*$c3z ]
            if { $det == 0 } { exitmd }
            set a [expr 0.5*($c3y-$c3z)/$det ] 
            set b [expr 0.5*($c1z-$c1y)/$det ]
    }

    #make sure always remove atom, not insert atom
    if {$tilt > 0} {
        set a [expr -$a]
        set b [expr -$b]
        set bx0 -0.5
        set by0 -0.5
        set bz0 -0.5
    } else {
        set bx0  0.5
        set by0  0.5
        set bz0  0.5
    }            
    set bx [expr $a*$c1x+$b*$c3x]
    set by [expr $a*$c1y+$b*$c3y]
    set bz [expr $a*$c1z+$b*$c3z]

    puts "a=$a b=$b"
    puts "Burgers vector = ([format "%g %g %g" $bx $by $bz])"
    
    if { [expr abs($bx-$bx0)] > 1e-4 } { exitmd }
    if { [expr abs($by-$bx0)] > 1e-4 } { exitmd }
    if { [expr abs($bz-$bx0)] > 1e-4 } { exitmd }

    set coord [list $a $b $bx $by $bz]
    return $coord
}

proc make_dislocation { tilt  } { 
    global supercell

    # create perfect crystal
    choose_supercell $tilt
    MD++ makecrystal #finalcnfile = perf.cn writecn #eval

    # remove top and bottom layers of atoms
    MD++ input = \[ 1 -1 1 -1 -0.37 -1 1 \] fixatoms_by_position
    MD++ input = \[ 1 -1 1  0.37  1 -1 1 \] fixatoms_by_position
    MD++ removefixedatoms    
        
    # insert dislocation dipole
    set coord [ find_burgers_coord $tilt ]
    set a [lindex $coord 0]
    set b [lindex $coord 1]
    
    # dislocation position
    set x0 [expr 0.111 /   [MD++_Get latticesize(3)] ]
    set y0 [expr -0.5+0.125/[MD++_Get latticesize(7)] ]
    #set x0 0.01
    #set y0 -0.4996
    set y1 [expr $y0 + 0.5]
    MD++ input = \[ 3 2 $a 0 $b  $x0 $y0 $y1 0.305 -10 10 -10 10 1 0 0 0 0 \]
    MD++ makedipole    
}

proc mark_groups { } {
  MD++ NCS = 8 eval calcentralsymmetry freeallatoms
  
  #identify top surface atom
  MD++ input = \[ 1 -10 10 0 10 -10 10 10 20 \] fixatoms_by_pos_topol
  set  ntop     [MD++_Get NPfixed]
  MD++ input = 1 setfixedatomsgroup freeallatoms
  
  #identify bottom surface atom
  MD++ input = \[ 1 -10 10 -10 0 -10 10 10 20 \] fixatoms_by_pos_topol
  set  nbot     [MD++_Get NPfixed]
  MD++ input = 2 setfixedatomsgroup freeallatoms

  set natoms [list $ntop $nbot]
  return $natoms
}

#--------------------------------------------
proc relax_fixbox { } { MD++ {
# Conjugate-Gradient relaxation
conj_ftol = 1e-4 conj_itmax = 1000 conj_fevalmax = 1000
conj_fixbox = 1
relax
} }
#end of proc relax_fixbox

proc setup_window { } { MD++ {
#------------------------------------------------------------
#colors for Central symmetry view
color00 = "red" color01 = "blue" color02 = "green"
color03 = "magenta" color04 = "cyan" color05 = "purple"
color06 = "gray80" color07 = "white" color08 = "orange"
#--------------------------------------------
# Plot Configuration
#
atomradius = [1.0 0.78] bondradius = 0.3 bondlength = 0 #2.8285 #for Si
win_width=600 win_height=400
#atomradius = 0.9 bondradius = 0.3 bondlength = 0 #2.8285 #for Si
atomcolor = cyan highlightcolor = purple  bondcolor = red
fixatomcolor = yellow backgroundcolor = gray70
#atomcolor = lightgrey highlightcolor = purple  bondcolor = darkgrey
#plot_color_windows = [ 5
#                 -5   -4   0
#                 -5.5 -5   8   #color00 = red
#                 -6  -5.5  1
#               -6.55 -6    2
#               -6.72 -6.55 3
#                 -6.5 -6   6   #color06 = gray80
#                 -7.5 -6.5 4
#                ]
plot_color_axis = 2
plot_color_windows = [ 4
                       0.6 6   1  
                       6  10   5
                       10 20   6
                       20 50   8
                     ]
#plot_atom_info = 1 # reduced coordinates of atoms
#plot_atom_info = 2 # real coordinates of atoms
plot_atom_info = 3 # energy of atoms
#plot_highlight = [ 0 0 1 2 3 4 5 6 7 8 9 ]
plotfreq = 10
#
rotateangles = [ 0 0 0 1.2 ]
#openwin alloccolors rotate saverot plot
#plot_color_axis = 0 input = [ -8 -3 10] GnuPlotHistogram
#plot_color_axis = 2 input = [ 0.6 50 50 ] GnuPlotHistogram
} }

proc openwindow { } { 
setup_window
MD++ openwin alloccolors rotate saverot eval plot
}

#--------------------------------------------
proc exitmd { } { MD++ quit }
#end of proc exitmd
#--------------------------------------------

#--------------------------------------------
proc setup_md { } { MD++ {     
equilsteps = 0  timestep = 0.001 # (ps)
atommass = 95.94 # (g/mol)
DOUBLE_T = 1
saveprop = 1 savepropfreq = 100 openpropfile #run
savecn = 1 savecnfreq = 1000 openintercnfile
savecfg = 1 savecfgfreq = 50
plotfreq = 100 printfreq = 100
vt2 = 1e28  #1e28 2e28 5e28
wallmass = 2e3     # atommass * NP = 14380
boxdamp = 1e-3     # optimal damping for 216 atoms and wallmass 1e-3
saveH # Use current H as reference (H0), needed for specifying stress
fixboxvec  = [ 0 1 1 
               1 0 1
               1 1 0 ]
stress = [ 0 0 0
           0 0 0
           0 0 0 ]
output_fmt = "curstep EPOT KATOM Tinst HELM HELMP TSTRESS_xx TSTRESS_yy TSTRESS_zz H_11 H_22 H_33" 
} }
#end of proc setup_md


#*******************************************
# Main program starts here
#*******************************************
# status 0:
#        1:
#        2:
#
# read in status from command line argument
if { $argc == 0 } {
 set status 0
} elseif { $argc > 0 } {
 set status [lindex $argv 0]
}
puts "status = $status"

if { $argc <= 1 } {
 set n 0
} elseif { $argc > 1 } {
 set n [lindex $argv 1]
}
puts "n = $n"

set n0 0

#for debugging I12potential (reference potential 2)
#MD++ refpotential = 2  RLIST = 4.2 SKIN = 0.4
#MD++ I12_rc = 3.771   I12_sigma = 2.0951   I12_epsilon = 2.1675 

if { $status == 0 } {
  # prepare and relax dislocation structure
  initmd $n
  readpot

  create_datebase

  #screw
  #set tilt 0

  #[001]
  #set tilt -3
  
  #[11-1]
  #set tilt 4

  set tilt $n
  
  make_dislocation $tilt
  
  openwindow
  
  MD++ conj_ftol = 1e-4 conj_fixbox = 1 conj_fevalmax = 10000
  MD++ relax

  MD++ finalcnfile = "mo-tilt$tilt.cn" writecn
  MD++ eval

  MD++ sleep
  exitmd
  
} elseif { $status == 1 } {
  # visualization
  MD++ setnolog
  initmd "view"
  readpot
  
  #set tilt_list {-90 -4.54 -4 -3 -2 -1.75 -1.5 -1.25 -1.125 -1 -0.75 -0.2 0 4.8 4.7 4.5 4.3 4.2 4 3.5 3 2.7 2.5 2.4 2 1.75 1.5 1 0.2}

  #set tilt_list {-1.25-stress10 -1.25-stress8 -1.25stress10 }
  set tilt_list {0-stress2100 0-stress2200 0-stress2240 0-stress2250 }

  for { set i 0 } { $i < [llength $tilt_list] } { incr i 1 } {
      set tilt [lindex $tilt_list $i]
      #MD++ incnfile = "../mo-peierls-tilt$tilt/mo-tilt$tilt.cn" readcn
      #MD++ incnfile = "../mo-peierls-tilt-1.25/mo-tilt$tilt.cn" readcn
      MD++ incnfile = "../mo-peierls-tilt0-reverse/mo-tilt$tilt.cn" readcn
      MD++ finalcnfile = "view-[format %04d $i].cfg" writeatomeyecfg
      #MD++ NCS = 8 eval calcentralsymmetry 
      if { $i == 0 } { openwindow }
      if { $i >  0 } { MD++ eval plot }
      after 2000
  }

  #MD++ conj_ftol = 1e-4 conj_fixbox = 1 conj_fevalmax = 1000
  #MD++ relax
  
  MD++ sleep
  exitmd

} elseif { $status == 2 } {
  # measuring Peierls barrier
  #MD++ setnolog

  set reverse_force 0
  set tilt $n  

  if { $tilt == 0 } {
     set reverse_force 1
  }

  if { $reverse_force == 1 } {
     initmd "$n-reverse"
  } else {
     initmd $n
  }

  readpot

  create_datebase
  choose_supercell $tilt

  MD++ incnfile = "mo-tilt$tilt.cn" readcn setconfig1
  set natoms [ mark_groups ]
  set ntop [lindex $natoms 0]
  set nbot [lindex $natoms 1]
  puts "ntop = $ntop  nbot = $nbot"

  #obtain cross section area
  set Lx [MD++_Get H_11]
  set Ly [MD++_Get H_22]
  set Lz [MD++_Get H_33]
  set A  [expr $Lx*$Lz ]
  
  puts "Lx = $Lx  Lz = $Lz  A = $A"

  # find Burgers vector direction, set as Fext direction
  set coord [ find_burgers_coord $tilt ]
  set a [lindex $coord 0]
  set b [lindex $coord 1]
  set Fx [expr $a*$Lx]
  set Fz [expr $b*$Lz]
  if { $reverse_force == 1 } {
      set Fx [expr -$Fx]
      set Fz [expr -$Fz]
  }

  # normalize Fext to correspond to 1 MPa
  set F  [expr sqrt($Fx*$Fx+$Fz*$Fz)]
  set F0 [expr $A / 160.2e3]
  set Fx [expr $Fx/$F*$F0]
  set Fz [expr $Fz/$F*$F0]
   
  MD++ conj_ftol = 1e-4 conj_fixbox = 1 conj_fevalmax = 10000
  MD++ relax
  set E0 [MD++_Get EPOT]

  set datafile "EPOT.dat"
  set fileID [open $datafile w ]
  puts $fileID "0 $E0 0 0"
  flush $fileID

  set minsigma 200 
  set dsigma   1
  set maxsigma 3000
  
#  if { $tilt == -3 } { set minsigma 560  }
  if { $tilt == 0  } { set minsigma 2240 }
#  if { $tilt == 4  } { set minsigma 390  }
#  if { $tilt == 0.2} { set minsigma 350  }
  
  if { $minsigma != $dsigma } {
       MD++ incnfile = "mo-tilt$tilt-stress$minsigma.cn" readcn
       mark_groups
  }

  MD++ applyFext = 1
  for { set stress $minsigma } { $stress < $maxsigma } { incr stress $dsigma } {
          
      set fx_top [expr  $Fx*$stress/$ntop]
      set fz_top [expr  $Fz*$stress/$ntop]
      set fx_bot [expr -$Fx*$stress/$nbot]
      set fz_bot [expr -$Fz*$stress/$nbot]
      puts "fx_top = $fx_top fz_top = $fz_top fx_bot = $fx_bot fz_bot = $fz_bot"

      MD++ clearFext
      MD++ input = \[ 1 $fx_top 0 $fz_top \] addFext_to_group 
      MD++ input = \[ 2 $fx_bot 0 $fz_bot \] addFext_to_group 
  
      MD++ relax
      MD++ finalcnfile = "mo-tilt$tilt-stress$stress.cn" writecn

      set E [MD++_Get EPOT]
      set dE [expr $E-$E0 ]
      set dr [expr -0.5*$dE/($F0*$stress)]
      puts $fileID "$stress $E $dE $dr"
      flush $fileID

      if { [expr abs($dr)] > 10 } {
          break
      }
  }
  close $fileID 
  exitmd

} else {
        
 puts "unknown status = $status"
 exitmd 

} 

