vasputils 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/Gemfile +1 -0
  2. data/Rakefile +1 -1
  3. data/bin/lsvaspdir +4 -1
  4. data/lib/vasputils/poscar.rb +0 -0
  5. data/lib/vasputils/vaspdir.rb +257 -253
  6. data/test/test_vaspdir.rb +235 -235
  7. data/vasputils.gemspec +7 -110
  8. metadata +30 -170
  9. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/CONTCAR +0 -17
  10. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/INCAR +0 -27
  11. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/KPOINTS +0 -6
  12. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/OUTCAR +0 -1436
  13. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/POSCAR +0 -12
  14. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/POTCAR +0 -3151
  15. data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/lock +0 -0
  16. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/CONTCAR +0 -17
  17. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/INCAR +0 -28
  18. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/KPOINTS +0 -6
  19. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/OUTCAR +0 -1436
  20. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/POSCAR +0 -12
  21. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/POTCAR +0 -3151
  22. data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/lock +0 -0
  23. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/CONTCAR +0 -17
  24. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/INCAR +0 -28
  25. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/KPOINTS +0 -6
  26. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/OUTCAR +0 -1436
  27. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/POSCAR +0 -12
  28. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/POTCAR +0 -3151
  29. data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/lock +0 -0
  30. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/CONTCAR +0 -17
  31. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/INCAR +0 -28
  32. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/KPOINTS +0 -6
  33. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/OUTCAR +0 -1436
  34. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/POSCAR +0 -12
  35. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/POTCAR +0 -3151
  36. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/lock +0 -0
  37. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/CONTCAR +0 -17
  38. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/INCAR +0 -28
  39. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/KPOINTS +0 -6
  40. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/OUTCAR +0 -2602
  41. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/POSCAR +0 -12
  42. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/POTCAR +0 -3151
  43. data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/lock +0 -0
  44. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/CONTCAR +0 -17
  45. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/INCAR +0 -28
  46. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/KPOINTS +0 -6
  47. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/OUTCAR +0 -1436
  48. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/POSCAR +0 -12
  49. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/POTCAR +0 -3151
  50. data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/lock +0 -0
  51. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/CONTCAR +0 -17
  52. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/INCAR +0 -28
  53. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/KPOINTS +0 -6
  54. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/OUTCAR +0 -1436
  55. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/POSCAR +0 -12
  56. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/POTCAR +0 -3151
  57. data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/lock +0 -0
  58. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/CONTCAR +0 -17
  59. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/INCAR +0 -28
  60. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/KPOINTS +0 -6
  61. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/OUTCAR +0 -2025
  62. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/POSCAR +0 -12
  63. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/POTCAR +0 -3151
  64. data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/lock +0 -0
  65. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/CONTCAR +0 -0
  66. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/INCAR +0 -28
  67. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/KPOINTS +0 -6
  68. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/OUTCAR +0 -619
  69. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/POSCAR +0 -12
  70. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/POTCAR +0 -3151
  71. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/lock +0 -0
  72. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/CONTCAR +0 -17
  73. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/INCAR +0 -28
  74. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/KPOINTS +0 -6
  75. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/OUTCAR +0 -2602
  76. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/POSCAR +0 -12
  77. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/POTCAR +0 -3151
  78. data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/lock +0 -0
  79. data/test/vaspdir/PI/INCAR +0 -28
  80. data/test/vaspdir/PI/KPOINTS +0 -5
  81. data/test/vaspdir/PI/PI12345 +0 -0
  82. data/test/vaspdir/PI/POSCAR +0 -57
  83. data/test/vaspdir/PI/POTCAR +0 -698
  84. data/test/vaspdir/lock/INCAR +0 -28
  85. data/test/vaspdir/lock/KPOINTS +0 -5
  86. data/test/vaspdir/lock/POSCAR +0 -57
  87. data/test/vaspdir/lock/POTCAR +0 -698
  88. data/test/vaspdir/lock/lock +0 -0
  89. data/test/vaspdir/lock-PI/INCAR +0 -28
  90. data/test/vaspdir/lock-PI/KPOINTS +0 -5
  91. data/test/vaspdir/lock-PI/PI12345 +0 -0
  92. data/test/vaspdir/lock-PI/POSCAR +0 -57
  93. data/test/vaspdir/lock-PI/POTCAR +0 -698
  94. data/test/vaspdir/lock-PI/lock +0 -0
  95. data/test/vaspdir/next-try00/CONTCAR +0 -17
  96. data/test/vaspdir/next-try00/INCAR +0 -28
  97. data/test/vaspdir/next-try00/KPOINTS +0 -6
  98. data/test/vaspdir/next-try00/OUTCAR +0 -2025
  99. data/test/vaspdir/next-try00/POSCAR +0 -12
  100. data/test/vaspdir/next-try00/POTCAR +0 -3151
  101. data/test/vaspdir/next-try00/lock +0 -0
  102. data/test/vaspdir/not-yet-ISIF2/INCAR +0 -28
  103. data/test/vaspdir/not-yet-ISIF2/KPOINTS +0 -5
  104. data/test/vaspdir/not-yet-ISIF2/PI17489 +0 -2
  105. data/test/vaspdir/not-yet-ISIF2/PI17736 +0 -2
  106. data/test/vaspdir/not-yet-ISIF2/PI1858 +0 -2
  107. data/test/vaspdir/not-yet-ISIF2/PI1866 +0 -2
  108. data/test/vaspdir/not-yet-ISIF2/PI2059 +0 -2
  109. data/test/vaspdir/not-yet-ISIF2/POSCAR +0 -57
  110. data/test/vaspdir/not-yet-ISIF2/POTCAR +0 -698
  111. data/test/vaspdir/not-yet-ISIF3/INCAR +0 -28
  112. data/test/vaspdir/not-yet-ISIF3/KPOINTS +0 -5
  113. data/test/vaspdir/not-yet-ISIF3/POSCAR +0 -57
  114. data/test/vaspdir/not-yet-ISIF3/POTCAR +0 -698
data/Gemfile CHANGED
@@ -14,5 +14,6 @@ group :development do
14
14
  gem "mageo", ">= 0.0.0"
15
15
  gem "malge", ">= 0.0.1"
16
16
  gem "maset", ">= 0.0.0"
17
+ gem "comana", ">= 0.0.0"
17
18
  gem "builtinextension", ">= 0.0.3"
18
19
  end
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ Jeweler::Tasks.new do |gem|
18
18
  gem.homepage = "http://github.com/ippei94da/vasputils"
19
19
  gem.license = "MIT"
20
20
  gem.summary = %Q{Utilities for VASP, first-principles calculation code.}
21
- gem.description = %Q{This gem provides parsers for some VASP input and output files.
21
+ gem.description = %Q{This gem provides parsers for some of input and output files for VASP.
22
22
  This will provide support command for computations.}
23
23
  gem.email = "ippei94da@gmail.com"
24
24
  gem.authors = ["ippei94da"]
data/bin/lsvaspdir CHANGED
@@ -24,9 +24,12 @@
24
24
  # -S オプションで状態を出力せず、ディレクトリ名だけを出力する。
25
25
  # このオプションはシェルの backquote `` 機能から使うことを想定している。
26
26
 
27
+ require "optparse"
28
+
29
+ require "rubygems"
30
+ gem "vasputils"
27
31
  require "vasputils/calcinspector.rb"
28
32
  require "vasputils/vaspdir.rb"
29
- require "optparse"
30
33
 
31
34
  OPTIONS = {}
32
35
  OPTIONS[:target_status] = ["YET", "STARTED", "NEXT", "FINISHED"]
File without changes
@@ -1,14 +1,18 @@
1
1
  #! /usr/bin/env ruby
2
2
  # coding: utf-8
3
3
 
4
- require "vasputils/incar.rb"
5
- require "vasputils/outcar.rb"
6
- require "vasputils/poscar.rb"
7
- require "vasputils/kpoints.rb"
8
4
  require "fileutils"
9
5
  require "pp"
10
6
  require "date"
11
7
 
8
+ require "rubygems"
9
+ gem "comana"
10
+ require "comana.rb"
11
+
12
+ require "vasputils/incar.rb"
13
+ require "vasputils/outcar.rb"
14
+ require "vasputils/poscar.rb"
15
+ require "vasputils/kpoints.rb"
12
16
 
13
17
  # vasp 実行ディレクトリ(入力・出力ファイルを含む)を扱うクラス
14
18
  #
@@ -24,255 +28,255 @@ require "date"
24
28
  #
25
29
  class VaspDir
26
30
 
27
- class InitializeError < Exception; end
28
- class ConvergedError < Exception; end
29
- class NotEndedError < Exception; end
30
- class LockedError < Exception; end
31
- class PostfixMismatchError < Exception; end
32
-
33
-
34
- LOCK_FILE = "lock"
35
- POSTFIX = /try(\d+)$/
36
-
37
- YET = 0# - 未計算。
38
- STARTED = 1# - 開始した。
39
- INTERRUPTED = 2# - 中断された。
40
- CONTINUED = 3# - 終了し、次の計算を生成した。
41
- COMPLETED = 4# - 終了し、収束した。
42
-
43
- attr_reader :mode
44
- #attr_reader :dir
45
-
46
- #INCAR 解析とかして、モードを調べる。
47
- #- 格子定数の構造最適化モード(ISIF = 3)
48
- #- 格子定数を固定した構造最適化モード(ISIF = 2)
49
- ##- k 点探索モードは無理だろう。
50
- def initialize(dir_name)
51
- @dir = dir_name
52
-
53
- %w(INCAR KPOINTS POSCAR POTCAR).each do |file|
54
- infile = "#{@dir}/#{file}"
55
- raise InitializeError, infile unless FileTest.exist? infile
56
- end
57
-
58
- @incar = Incar.load_file("#{@dir}/INCAR")
59
- case @incar["IBRION"]
60
- when "-1"
61
- @mode = :single_point
62
- #when "1"
63
- # @mode = :molecular_dynamics
64
- when "2"
65
- if (@incar["ISIF"] == "2")
66
- @mode = :geom_opt_atoms
67
- elsif (@incar["ISIF"] == "3")
68
- @mode = :geom_opt_lattice
69
- else
70
- @mode = :geom_opt
71
- end
72
- else
73
- @mode = nil
74
- end
75
- end
76
-
77
- # ディレクトリ名を返す。
78
- def name
79
- @dir
80
- end
81
-
82
- # 計算が過去に始まっていれば true を返す。
83
- # 終わっているかは判定しない。
84
- # 具体的には lock ファイルが存在すれば true を返す。
85
- #
86
- # MEMO
87
- # (mpi 経由で?)vasp を実行すると PI12345 とかいうファイルができるが、
88
- # これはたぶん起動してから若干のタイムラグが生じる。
89
- # このタイムラグ中に別のプロセスが同時に計算したらマズい。
90
- def started?
91
- return File.exist? lock_file
92
- end
93
-
94
- # 正常に終了していれば true を返す。
95
- # 実行する前や実行中、OUTCAR が完遂していなければ false。
96
- #
97
- # MEMO
98
- # PI12345 ファイルは実行中のみ存在し、終了後 vasp (mpi?) に自動的に削除される。
99
- def normal_ended?
100
- begin
101
- return Outcar.load_file("#{@dir}/OUTCAR")[:normal_ended]
102
- rescue Errno::ENOENT
103
- return false
104
- end
105
- end
106
-
107
- # normal_ended? が false なら false。
108
- # normal_ended? が true のうち、
109
- # 結果を使って次に計算すべきなら true を、そうでなければ false を返す。
110
- #
111
- # 計算すべき、の条件はモードによって異なる。
112
- # NSW = 0 もしくは NSW = 1 のとき、必ず false。
113
- # - :single_point モードならば、常に false。
114
- # - :geom_opt_lattice モードならば、ionic step が 2 以上なら true。
115
- # - :geom_opt_atoms モードならば、ionic step が NSW と同じなら true。
116
- #
117
- def to_be_continued?
118
- begin
119
- outcar = Outcar.load_file("#{@dir}/OUTCAR")
120
- rescue Errno::ENOENT
121
- return false
122
- end
123
- ionic_steps = outcar[:ionic_steps]
124
- return false unless outcar[:normal_ended]
125
- return false if @incar["NSW"].to_i <= 1
126
- if @mode == :geom_opt_lattice
127
- return ionic_steps != 1
128
- elsif @mode == :geom_opt_atoms
129
- return ionic_steps == @incar["NSW"].to_i
130
- else
131
- return false
132
- end
133
- end
134
-
135
- # vasp を投げる。
136
- # 計算実行時に lock を生成する。
137
- # もし既に lock が存在していれば、例外 VaspDirLockedError を
138
- # 投げる。
139
- # lock は作られっぱなしで、プログラムからは削除されない。
140
- # 通常、一度計算したらもう二度と計算しないし。
141
- #
142
- # MEMO
143
- # mpirun で投げる場合は
144
- # machinefile を生成しないとどのホストで計算するか、安定しない。
145
- # そのうち mpiexec from torque に対応するが、
146
- # まずは mpirun で動くように作る。
147
- def calculate
148
- raise LockedError if started?
149
-
150
- File.open(lock_file, "w") do |lock_io|
151
- lock_io.puts "HOST: #{ENV["HOST"]}"
152
- lock_io.puts "START: #{Time.now.to_s}"
153
- lock_io.flush
154
-
155
- num_cores = 4 if /^Se\d\d/ =~ ENV["HOST"]
156
- num_cores = 4 if /^Ge\d\d/ =~ ENV["HOST"]
157
- num_cores = 4 if /^Ga\d\d/ =~ ENV["HOST"]
158
- num_cores = 4 if /^At$/ =~ ENV["HOST"]
159
- num_cores = 2 if /^yggdrasil$/ =~ ENV["HOST"]
160
-
161
- # machines を生成
162
- File.open("#{@dir}/machines", "w") do |io|
163
- io.puts "localhost:#{num_cores}"
164
- end
165
-
166
- command = "cd #{@dir};" +
167
- "/usr/local/calc/mpich-1.2.7-ifc7/bin/mpirun " +
168
- "-np #{num_cores} " +
169
- "-machinefile machines " +
170
- "/usr/local/calc/vasp/vasp4631mpi" +
171
- "> stdout"
172
-
173
- if $TEST
174
- generated_files = [
175
- "CHG",
176
- "CHGCAR",
177
- "CONTCAR",
178
- "DOSCAR",
179
- "EIGENVAL",
180
- "IBZKPT",
181
- "OSZICAR",
182
- "OUTCAR",
183
- "PCDAT",
184
- "WAVECAR",
185
- "XDATCAR",
186
- "machines",
187
- "vasprun.xml",
188
- "lock",
189
- ]
190
- generated_files.map!{|i| "#{@dir}/#{i}"}
191
- command = "touch #{generated_files.join(" ")}"
192
- end
193
-
194
- status = system command
195
- if status
196
- lock_io.puts "STATUS: normal ended."
197
- else
198
- lock_io.puts "STATUS: irregular ended, status #{$?}."
199
- end
200
- end
201
- end
202
-
203
- # 次の計算ディレクトリを作成し、
204
- # その VaspDir クラスで self を置き換える。
205
- # 計算が正常終了していなければ、例外 VaspDirNotEndedError を生じる。
206
- # 次の計算ディレクトリが既に存在していれば例外 Errno::EEXIST が投げられる。
207
- def next
208
- raise NotEndedError unless normal_ended?
209
- raise ConvergedError unless to_be_continued?
210
- #postfix = /try(\d+)$/
211
- POSTFIX =~ @dir
212
- try_num = $1.to_i
213
- next_dir = @dir.sub(POSTFIX, sprintf("try%02d", try_num + 1))
214
- Dir.mkdir next_dir
215
- FileUtils.cp( "#{@dir}/INCAR" , "#{next_dir}/INCAR")
216
- FileUtils.cp( "#{@dir}/KPOINTS", "#{next_dir}/KPOINTS")
217
- FileUtils.cp( "#{@dir}/POTCAR" , "#{next_dir}/POTCAR")
218
- FileUtils.cp( "#{@dir}/CONTCAR", "#{next_dir}/POSCAR")
219
- initialize(next_dir)
220
- end
221
-
222
- # Postprocess.
223
- def teardown
224
- # Do nothing.
225
- end
226
-
227
- # Return number of electronic steps.
228
- def internal_steps
229
- return outcar[:electronic_steps] if outcar
230
- return 0
231
- end
232
-
233
- # Return number of ionic steps.
234
- def external_steps
235
- return outcar[:ionic_steps] if outcar
236
- return 0
237
- end
238
-
239
- # Return elapsed time.
240
- def elapsed_time
241
- return outcar[:elapsed_time] if outcar
242
- return 0.0
243
- end
244
-
245
- # 配下の OUTCAR を Outcar インスタンスにして返す。
246
- # 存在しなければ例外 Errno::ENOENT を返す。
247
- def outcar
248
- Outcar.load_file("#{@dir}/OUTCAR")
249
- end
250
-
251
- # 配下の CONTCAR を Cell2 インスタンスにして返す。
252
- # 存在しなければ例外 Errno::ENOENT を返す。
253
- def contcar
254
- Poscar.load_file("#{@dir}/CONTCAR")
255
- end
256
-
257
- # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。
258
- #
259
- # 存在しなければ例外 Errno::ENOENT を返す筈だが、
260
- # vasp dir の判定を incar でやっているので置こる筈がない。
261
- def incar
262
- Incar.load_file("#{@dir}/INCAR")
263
- end
264
-
265
- # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。
266
- def kpoints
267
- Kpoints.load_file("#{@dir}/KPOINTS")
268
- end
269
-
270
- private
271
-
272
- # Return lock file name.
273
- def lock_file
274
- return "#{@dir}/#{LOCK_FILE}"
275
- end
31
+ class InitializeError < Exception; end
32
+ class ConvergedError < Exception; end
33
+ class NotEndedError < Exception; end
34
+ class LockedError < Exception; end
35
+ class PostfixMismatchError < Exception; end
36
+
37
+
38
+ LOCK_FILE = "lock"
39
+ POSTFIX = /try(\d+)$/
40
+
41
+ YET = 0# - 未計算。
42
+ STARTED = 1# - 開始した。
43
+ INTERRUPTED = 2# - 中断された。
44
+ CONTINUED = 3# - 終了し、次の計算を生成した。
45
+ COMPLETED = 4# - 終了し、収束した。
46
+
47
+ attr_reader :mode
48
+ #attr_reader :dir
49
+
50
+ #INCAR 解析とかして、モードを調べる。
51
+ #- 格子定数の構造最適化モード(ISIF = 3)
52
+ #- 格子定数を固定した構造最適化モード(ISIF = 2)
53
+ ##- k 点探索モードは無理だろう。
54
+ def initialize(dir_name)
55
+ @dir = dir_name
56
+
57
+ %w(INCAR KPOINTS POSCAR POTCAR).each do |file|
58
+ infile = "#{@dir}/#{file}"
59
+ raise InitializeError, infile unless FileTest.exist? infile
60
+ end
61
+
62
+ @incar = Incar.load_file("#{@dir}/INCAR")
63
+ case @incar["IBRION"]
64
+ when "-1"
65
+ @mode = :single_point
66
+ #when "1"
67
+ # @mode = :molecular_dynamics
68
+ when "2"
69
+ if (@incar["ISIF"] == "2")
70
+ @mode = :geom_opt_atoms
71
+ elsif (@incar["ISIF"] == "3")
72
+ @mode = :geom_opt_lattice
73
+ else
74
+ @mode = :geom_opt
75
+ end
76
+ else
77
+ @mode = nil
78
+ end
79
+ end
80
+
81
+ # ディレクトリ名を返す。
82
+ def name
83
+ @dir
84
+ end
85
+
86
+ # 計算が過去に始まっていれば true を返す。
87
+ # 終わっているかは判定しない。
88
+ # 具体的には lock ファイルが存在すれば true を返す。
89
+ #
90
+ # MEMO
91
+ # (mpi 経由で?)vasp を実行すると PI12345 とかいうファイルができるが、
92
+ # これはたぶん起動してから若干のタイムラグが生じる。
93
+ # このタイムラグ中に別のプロセスが同時に計算したらマズい。
94
+ def started?
95
+ return File.exist? lock_file
96
+ end
97
+
98
+ # 正常に終了していれば true を返す。
99
+ # 実行する前や実行中、OUTCAR が完遂していなければ false。
100
+ #
101
+ # MEMO
102
+ # PI12345 ファイルは実行中のみ存在し、終了後 vasp (mpi?) に自動的に削除される。
103
+ def normal_ended?
104
+ begin
105
+ return Outcar.load_file("#{@dir}/OUTCAR")[:normal_ended]
106
+ rescue Errno::ENOENT
107
+ return false
108
+ end
109
+ end
110
+
111
+ # normal_ended? が false なら false。
112
+ # normal_ended? が true のうち、
113
+ # 結果を使って次に計算すべきなら true を、そうでなければ false を返す。
114
+ #
115
+ # 計算すべき、の条件はモードによって異なる。
116
+ # NSW = 0 もしくは NSW = 1 のとき、必ず false。
117
+ # - :single_point モードならば、常に false。
118
+ # - :geom_opt_lattice モードならば、ionic step が 2 以上なら true。
119
+ # - :geom_opt_atoms モードならば、ionic step が NSW と同じなら true。
120
+ #
121
+ def to_be_continued?
122
+ begin
123
+ outcar = Outcar.load_file("#{@dir}/OUTCAR")
124
+ rescue Errno::ENOENT
125
+ return false
126
+ end
127
+ ionic_steps = outcar[:ionic_steps]
128
+ return false unless outcar[:normal_ended]
129
+ return false if @incar["NSW"].to_i <= 1
130
+ if @mode == :geom_opt_lattice
131
+ return ionic_steps != 1
132
+ elsif @mode == :geom_opt_atoms
133
+ return ionic_steps == @incar["NSW"].to_i
134
+ else
135
+ return false
136
+ end
137
+ end
138
+
139
+ # vasp を投げる。
140
+ # 計算実行時に lock を生成する。
141
+ # もし既に lock が存在していれば、例外 VaspDirLockedError を
142
+ # 投げる。
143
+ # lock は作られっぱなしで、プログラムからは削除されない。
144
+ # 通常、一度計算したらもう二度と計算しないし。
145
+ #
146
+ # MEMO
147
+ # mpirun で投げる場合は
148
+ # machinefile を生成しないとどのホストで計算するか、安定しない。
149
+ # そのうち mpiexec from torque に対応するが、
150
+ # まずは mpirun で動くように作る。
151
+ def calculate
152
+ raise LockedError if started?
153
+
154
+ File.open(lock_file, "w") do |lock_io|
155
+ lock_io.puts "HOST: #{ENV["HOST"]}"
156
+ lock_io.puts "START: #{Time.now.to_s}"
157
+ lock_io.flush
158
+
159
+ num_cores = 4 if /^Se\d\d/ =~ ENV["HOST"]
160
+ num_cores = 4 if /^Ge\d\d/ =~ ENV["HOST"]
161
+ num_cores = 4 if /^Ga\d\d/ =~ ENV["HOST"]
162
+ num_cores = 4 if /^At$/ =~ ENV["HOST"]
163
+ num_cores = 2 if /^yggdrasil$/ =~ ENV["HOST"]
164
+
165
+ # machines を生成
166
+ File.open("#{@dir}/machines", "w") do |io|
167
+ io.puts "localhost:#{num_cores}"
168
+ end
169
+
170
+ command = "cd #{@dir};" +
171
+ "/usr/local/calc/mpich-1.2.7-ifc7/bin/mpirun " +
172
+ "-np #{num_cores} " +
173
+ "-machinefile machines " +
174
+ "/usr/local/calc/vasp/vasp4631mpi" +
175
+ "> stdout"
176
+
177
+ if $TEST
178
+ generated_files = [
179
+ "CHG",
180
+ "CHGCAR",
181
+ "CONTCAR",
182
+ "DOSCAR",
183
+ "EIGENVAL",
184
+ "IBZKPT",
185
+ "OSZICAR",
186
+ "OUTCAR",
187
+ "PCDAT",
188
+ "WAVECAR",
189
+ "XDATCAR",
190
+ "machines",
191
+ "vasprun.xml",
192
+ "lock",
193
+ ]
194
+ generated_files.map!{|i| "#{@dir}/#{i}"}
195
+ command = "touch #{generated_files.join(" ")}"
196
+ end
197
+
198
+ status = system command
199
+ if status
200
+ lock_io.puts "STATUS: normal ended."
201
+ else
202
+ lock_io.puts "STATUS: irregular ended, status #{$?}."
203
+ end
204
+ end
205
+ end
206
+
207
+ # 次の計算ディレクトリを作成し、
208
+ # その VaspDir クラスで self を置き換える。
209
+ # 計算が正常終了していなければ、例外 VaspDirNotEndedError を生じる。
210
+ # 次の計算ディレクトリが既に存在していれば例外 Errno::EEXIST が投げられる。
211
+ def next
212
+ raise NotEndedError unless normal_ended?
213
+ raise ConvergedError unless to_be_continued?
214
+ #postfix = /try(\d+)$/
215
+ POSTFIX =~ @dir
216
+ try_num = $1.to_i
217
+ next_dir = @dir.sub(POSTFIX, sprintf("try%02d", try_num + 1))
218
+ Dir.mkdir next_dir
219
+ FileUtils.cp( "#{@dir}/INCAR" , "#{next_dir}/INCAR")
220
+ FileUtils.cp( "#{@dir}/KPOINTS", "#{next_dir}/KPOINTS")
221
+ FileUtils.cp( "#{@dir}/POTCAR" , "#{next_dir}/POTCAR")
222
+ FileUtils.cp( "#{@dir}/CONTCAR", "#{next_dir}/POSCAR")
223
+ initialize(next_dir)
224
+ end
225
+
226
+ # Postprocess.
227
+ def teardown
228
+ # Do nothing.
229
+ end
230
+
231
+ # Return number of electronic steps.
232
+ def internal_steps
233
+ return outcar[:electronic_steps] if outcar
234
+ return 0
235
+ end
236
+
237
+ # Return number of ionic steps.
238
+ def external_steps
239
+ return outcar[:ionic_steps] if outcar
240
+ return 0
241
+ end
242
+
243
+ # Return elapsed time.
244
+ def elapsed_time
245
+ return outcar[:elapsed_time] if outcar
246
+ return 0.0
247
+ end
248
+
249
+ # 配下の OUTCAR を Outcar インスタンスにして返す。
250
+ # 存在しなければ例外 Errno::ENOENT を返す。
251
+ def outcar
252
+ Outcar.load_file("#{@dir}/OUTCAR")
253
+ end
254
+
255
+ # 配下の CONTCAR を Cell2 インスタンスにして返す。
256
+ # 存在しなければ例外 Errno::ENOENT を返す。
257
+ def contcar
258
+ Poscar.load_file("#{@dir}/CONTCAR")
259
+ end
260
+
261
+ # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。
262
+ #
263
+ # 存在しなければ例外 Errno::ENOENT を返す筈だが、
264
+ # vasp dir の判定を incar でやっているので置こる筈がない。
265
+ def incar
266
+ Incar.load_file("#{@dir}/INCAR")
267
+ end
268
+
269
+ # 配下の KPOINTS を読み込んだ結果をハッシュにして返す。
270
+ def kpoints
271
+ Kpoints.load_file("#{@dir}/KPOINTS")
272
+ end
273
+
274
+ private
275
+
276
+ # Return lock file name.
277
+ def lock_file
278
+ return "#{@dir}/#{LOCK_FILE}"
279
+ end
276
280
 
277
281
  end
278
282