lib/vasputils/vaspdir.rb in vasputils-0.0.0 vs lib/vasputils/vaspdir.rb in vasputils-0.0.1

- old
+ new

@@ -1,17 +1,21 @@ #! /usr/bin/env ruby # coding: utf-8 -require "vasputils/incar.rb" -require "vasputils/outcar.rb" -require "vasputils/poscar.rb" -require "vasputils/kpoints.rb" require "fileutils" require "pp" require "date" +require "rubygems" +gem "comana" +require "comana.rb" +require "vasputils/incar.rb" +require "vasputils/outcar.rb" +require "vasputils/poscar.rb" +require "vasputils/kpoints.rb" + # vasp 実行ディレクトリ(入力・出力ファイルを含む)を扱うクラス # # MEMO # interrupted? みたいなメソッドは作れない。 # 実行が開始したあと、その計算の状態が中断されているのか、 @@ -22,257 +26,257 @@ # try00 形式の postfix がついていることを前提とする。 # 00 の部分には CONTCAR を POSCAR にする手続きで連続して行う計算の番号を示す。 # class VaspDir - class InitializeError < Exception; end - class ConvergedError < Exception; end - class NotEndedError < Exception; end - class LockedError < Exception; end - class PostfixMismatchError < Exception; end + class InitializeError < Exception; end + class ConvergedError < Exception; end + class NotEndedError < Exception; end + class LockedError < Exception; end + class PostfixMismatchError < Exception; end - LOCK_FILE = "lock" - POSTFIX = /try(\d+)$/ + LOCK_FILE = "lock" + POSTFIX = /try(\d+)$/ - YET = 0# - 未計算。 - STARTED = 1# - 開始した。 - INTERRUPTED = 2# - 中断された。 - CONTINUED = 3# - 終了し、次の計算を生成した。 - COMPLETED = 4# - 終了し、収束した。 + YET = 0# - 未計算。 + STARTED = 1# - 開始した。 + INTERRUPTED = 2# - 中断された。 + CONTINUED = 3# - 終了し、次の計算を生成した。 + COMPLETED = 4# - 終了し、収束した。 - attr_reader :mode - #attr_reader :dir + attr_reader :mode + #attr_reader :dir - #INCAR 解析とかして、モードを調べる。 - #- 格子定数の構造最適化モード(ISIF = 3) - #- 格子定数を固定した構造最適化モード(ISIF = 2) - ##- k 点探索モードは無理だろう。 - def initialize(dir_name) - @dir = dir_name + #INCAR 解析とかして、モードを調べる。 + #- 格子定数の構造最適化モード(ISIF = 3) + #- 格子定数を固定した構造最適化モード(ISIF = 2) + ##- k 点探索モードは無理だろう。 + def initialize(dir_name) + @dir = dir_name - %w(INCAR KPOINTS POSCAR POTCAR).each do |file| - infile = "#{@dir}/#{file}" - raise InitializeError, infile unless FileTest.exist? infile - end + %w(INCAR KPOINTS POSCAR POTCAR).each do |file| + infile = "#{@dir}/#{file}" + raise InitializeError, infile unless FileTest.exist? infile + end - @incar = Incar.load_file("#{@dir}/INCAR") - case @incar["IBRION"] - when "-1" - @mode = :single_point - #when "1" - # @mode = :molecular_dynamics - when "2" - if (@incar["ISIF"] == "2") - @mode = :geom_opt_atoms - elsif (@incar["ISIF"] == "3") - @mode = :geom_opt_lattice - else - @mode = :geom_opt - end - else - @mode = nil - end - end + @incar = Incar.load_file("#{@dir}/INCAR") + case @incar["IBRION"] + when "-1" + @mode = :single_point + #when "1" + # @mode = :molecular_dynamics + when "2" + if (@incar["ISIF"] == "2") + @mode = :geom_opt_atoms + elsif (@incar["ISIF"] == "3") + @mode = :geom_opt_lattice + else + @mode = :geom_opt + end + else + @mode = nil + end + end - # ディレクトリ名を返す。 - def name - @dir - end + # ディレクトリ名を返す。 + def name + @dir + end - # 計算が過去に始まっていれば true を返す。 - # 終わっているかは判定しない。 - # 具体的には lock ファイルが存在すれば true を返す。 - # - # MEMO - # (mpi 経由で?)vasp を実行すると PI12345 とかいうファイルができるが、 - # これはたぶん起動してから若干のタイムラグが生じる。 - # このタイムラグ中に別のプロセスが同時に計算したらマズい。 - def started? - return File.exist? lock_file - end + # 計算が過去に始まっていれば true を返す。 + # 終わっているかは判定しない。 + # 具体的には lock ファイルが存在すれば true を返す。 + # + # MEMO + # (mpi 経由で?)vasp を実行すると PI12345 とかいうファイルができるが、 + # これはたぶん起動してから若干のタイムラグが生じる。 + # このタイムラグ中に別のプロセスが同時に計算したらマズい。 + def started? + return File.exist? lock_file + end - # 正常に終了していれば true を返す。 - # 実行する前や実行中、OUTCAR が完遂していなければ false。 - # - # MEMO - # PI12345 ファイルは実行中のみ存在し、終了後 vasp (mpi?) に自動的に削除される。 - def normal_ended? - begin - return Outcar.load_file("#{@dir}/OUTCAR")[:normal_ended] - rescue Errno::ENOENT - return false - end - end + # 正常に終了していれば true を返す。 + # 実行する前や実行中、OUTCAR が完遂していなければ false。 + # + # MEMO + # PI12345 ファイルは実行中のみ存在し、終了後 vasp (mpi?) に自動的に削除される。 + def normal_ended? + begin + return Outcar.load_file("#{@dir}/OUTCAR")[:normal_ended] + rescue Errno::ENOENT + return false + end + end - # normal_ended? が false なら false。 - # normal_ended? が true のうち、 - # 結果を使って次に計算すべきなら true を、そうでなければ false を返す。 - # - # 計算すべき、の条件はモードによって異なる。 - # NSW = 0 もしくは NSW = 1 のとき、必ず false。 - # - :single_point モードならば、常に false。 - # - :geom_opt_lattice モードならば、ionic step が 2 以上なら true。 - # - :geom_opt_atoms モードならば、ionic step が NSW と同じなら true。 - # - def to_be_continued? - begin - outcar = Outcar.load_file("#{@dir}/OUTCAR") - rescue Errno::ENOENT - return false - end - ionic_steps = outcar[:ionic_steps] - return false unless outcar[:normal_ended] - return false if @incar["NSW"].to_i <= 1 - if @mode == :geom_opt_lattice - return ionic_steps != 1 - elsif @mode == :geom_opt_atoms - return ionic_steps == @incar["NSW"].to_i - else - return false - end - end + # normal_ended? が false なら false。 + # normal_ended? が true のうち、 + # 結果を使って次に計算すべきなら true を、そうでなければ false を返す。 + # + # 計算すべき、の条件はモードによって異なる。 + # NSW = 0 もしくは NSW = 1 のとき、必ず false。 + # - :single_point モードならば、常に false。 + # - :geom_opt_lattice モードならば、ionic step が 2 以上なら true。 + # - :geom_opt_atoms モードならば、ionic step が NSW と同じなら true。 + # + def to_be_continued? + begin + outcar = Outcar.load_file("#{@dir}/OUTCAR") + rescue Errno::ENOENT + return false + end + ionic_steps = outcar[:ionic_steps] + return false unless outcar[:normal_ended] + return false if @incar["NSW"].to_i <= 1 + if @mode == :geom_opt_lattice + return ionic_steps != 1 + elsif @mode == :geom_opt_atoms + return ionic_steps == @incar["NSW"].to_i + else + return false + end + end - # vasp を投げる。 - # 計算実行時に lock を生成する。 - # もし既に lock が存在していれば、例外 VaspDirLockedError を - # 投げる。 - # lock は作られっぱなしで、プログラムからは削除されない。 - # 通常、一度計算したらもう二度と計算しないし。 - # - # MEMO - # mpirun で投げる場合は - # machinefile を生成しないとどのホストで計算するか、安定しない。 - # そのうち mpiexec from torque に対応するが、 - # まずは mpirun で動くように作る。 - def calculate - raise LockedError if started? + # vasp を投げる。 + # 計算実行時に lock を生成する。 + # もし既に lock が存在していれば、例外 VaspDirLockedError を + # 投げる。 + # lock は作られっぱなしで、プログラムからは削除されない。 + # 通常、一度計算したらもう二度と計算しないし。 + # + # MEMO + # mpirun で投げる場合は + # machinefile を生成しないとどのホストで計算するか、安定しない。 + # そのうち mpiexec from torque に対応するが、 + # まずは mpirun で動くように作る。 + def calculate + raise LockedError if started? - File.open(lock_file, "w") do |lock_io| - lock_io.puts "HOST: #{ENV["HOST"]}" - lock_io.puts "START: #{Time.now.to_s}" - lock_io.flush + File.open(lock_file, "w") do |lock_io| + lock_io.puts "HOST: #{ENV["HOST"]}" + lock_io.puts "START: #{Time.now.to_s}" + lock_io.flush - num_cores = 4 if /^Se\d\d/ =~ ENV["HOST"] - num_cores = 4 if /^Ge\d\d/ =~ ENV["HOST"] - num_cores = 4 if /^Ga\d\d/ =~ ENV["HOST"] - num_cores = 4 if /^At$/ =~ ENV["HOST"] - num_cores = 2 if /^yggdrasil$/ =~ ENV["HOST"] + num_cores = 4 if /^Se\d\d/ =~ ENV["HOST"] + num_cores = 4 if /^Ge\d\d/ =~ ENV["HOST"] + num_cores = 4 if /^Ga\d\d/ =~ ENV["HOST"] + num_cores = 4 if /^At$/ =~ ENV["HOST"] + num_cores = 2 if /^yggdrasil$/ =~ ENV["HOST"] - # machines を生成 - File.open("#{@dir}/machines", "w") do |io| - io.puts "localhost:#{num_cores}" - end + # machines を生成 + File.open("#{@dir}/machines", "w") do |io| + io.puts "localhost:#{num_cores}" + end - command = "cd #{@dir};" + - "/usr/local/calc/mpich-1.2.7-ifc7/bin/mpirun " + - "-np #{num_cores} " + - "-machinefile machines " + - "/usr/local/calc/vasp/vasp4631mpi" + - "> stdout" + command = "cd #{@dir};" + + "/usr/local/calc/mpich-1.2.7-ifc7/bin/mpirun " + + "-np #{num_cores} " + + "-machinefile machines " + + "/usr/local/calc/vasp/vasp4631mpi" + + "> stdout" - if $TEST - generated_files = [ - "CHG", - "CHGCAR", - "CONTCAR", - "DOSCAR", - "EIGENVAL", - "IBZKPT", - "OSZICAR", - "OUTCAR", - "PCDAT", - "WAVECAR", - "XDATCAR", - "machines", - "vasprun.xml", - "lock", - ] - generated_files.map!{|i| "#{@dir}/#{i}"} - command = "touch #{generated_files.join(" ")}" - end + if $TEST + generated_files = [ + "CHG", + "CHGCAR", + "CONTCAR", + "DOSCAR", + "EIGENVAL", + "IBZKPT", + "OSZICAR", + "OUTCAR", + "PCDAT", + "WAVECAR", + "XDATCAR", + "machines", + "vasprun.xml", + "lock", + ] + generated_files.map!{|i| "#{@dir}/#{i}"} + command = "touch #{generated_files.join(" ")}" + end - status = system command - if status - lock_io.puts "STATUS: normal ended." - else - lock_io.puts "STATUS: irregular ended, status #{$?}." - end - end - end + status = system command + if status + lock_io.puts "STATUS: normal ended." + else + lock_io.puts "STATUS: irregular ended, status #{$?}." + end + end + end - # 次の計算ディレクトリを作成し、 - # その VaspDir クラスで self を置き換える。 - # 計算が正常終了していなければ、例外 VaspDirNotEndedError を生じる。 - # 次の計算ディレクトリが既に存在していれば例外 Errno::EEXIST が投げられる。 - def next - raise NotEndedError unless normal_ended? - raise ConvergedError unless to_be_continued? - #postfix = /try(\d+)$/ - POSTFIX =~ @dir - try_num = $1.to_i - next_dir = @dir.sub(POSTFIX, sprintf("try%02d", try_num + 1)) - Dir.mkdir next_dir - FileUtils.cp( "#{@dir}/INCAR" , "#{next_dir}/INCAR") - FileUtils.cp( "#{@dir}/KPOINTS", "#{next_dir}/KPOINTS") - FileUtils.cp( "#{@dir}/POTCAR" , "#{next_dir}/POTCAR") - FileUtils.cp( "#{@dir}/CONTCAR", "#{next_dir}/POSCAR") - initialize(next_dir) - end + # 次の計算ディレクトリを作成し、 + # その VaspDir クラスで self を置き換える。 + # 計算が正常終了していなければ、例外 VaspDirNotEndedError を生じる。 + # 次の計算ディレクトリが既に存在していれば例外 Errno::EEXIST が投げられる。 + def next + raise NotEndedError unless normal_ended? + raise ConvergedError unless to_be_continued? + #postfix = /try(\d+)$/ + POSTFIX =~ @dir + try_num = $1.to_i + next_dir = @dir.sub(POSTFIX, sprintf("try%02d", try_num + 1)) + Dir.mkdir next_dir + FileUtils.cp( "#{@dir}/INCAR" , "#{next_dir}/INCAR") + FileUtils.cp( "#{@dir}/KPOINTS", "#{next_dir}/KPOINTS") + FileUtils.cp( "#{@dir}/POTCAR" , "#{next_dir}/POTCAR") + FileUtils.cp( "#{@dir}/CONTCAR", "#{next_dir}/POSCAR") + initialize(next_dir) + end - # Postprocess. - def teardown - # Do nothing. - end + # Postprocess. + def teardown + # Do nothing. + end - # Return number of electronic steps. - def internal_steps - return outcar[:electronic_steps] if outcar - return 0 - end + # Return number of electronic steps. + def internal_steps + return outcar[:electronic_steps] if outcar + return 0 + end - # Return number of ionic steps. - def external_steps - return outcar[:ionic_steps] if outcar - return 0 - end + # Return number of ionic steps. + def external_steps + return outcar[:ionic_steps] if outcar + return 0 + end - # Return elapsed time. - def elapsed_time - return outcar[:elapsed_time] if outcar - return 0.0 - end + # Return elapsed time. + def elapsed_time + return outcar[:elapsed_time] if outcar + return 0.0 + end - # 配下の OUTCAR を Outcar インスタンスにして返す。 - # 存在しなければ例外 Errno::ENOENT を返す。 - def outcar - Outcar.load_file("#{@dir}/OUTCAR") - end + # 配下の OUTCAR を Outcar インスタンスにして返す。 + # 存在しなければ例外 Errno::ENOENT を返す。 + def outcar + Outcar.load_file("#{@dir}/OUTCAR") + end - # 配下の CONTCAR を Cell2 インスタンスにして返す。 - # 存在しなければ例外 Errno::ENOENT を返す。 - def contcar - Poscar.load_file("#{@dir}/CONTCAR") - end + # 配下の CONTCAR を Cell2 インスタンスにして返す。 + # 存在しなければ例外 Errno::ENOENT を返す。 + def contcar + Poscar.load_file("#{@dir}/CONTCAR") + end - # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。 - # - # 存在しなければ例外 Errno::ENOENT を返す筈だが、 - # vasp dir の判定を incar でやっているので置こる筈がない。 - def incar - Incar.load_file("#{@dir}/INCAR") - end + # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。 + # + # 存在しなければ例外 Errno::ENOENT を返す筈だが、 + # vasp dir の判定を incar でやっているので置こる筈がない。 + def incar + Incar.load_file("#{@dir}/INCAR") + end - # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。 - def kpoints - Kpoints.load_file("#{@dir}/KPOINTS") - end + # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。 + def kpoints + Kpoints.load_file("#{@dir}/KPOINTS") + end - private + private - # Return lock file name. - def lock_file - return "#{@dir}/#{LOCK_FILE}" - end + # Return lock file name. + def lock_file + return "#{@dir}/#{LOCK_FILE}" + end end