vasputils 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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