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