vasputils 0.0.0
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.
- data/.document +5 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/addVolumeToten.rb +19 -0
- data/bin/latticeconstants +14 -0
- data/bin/lsvaspdir +60 -0
- data/bin/lsvaspseries +95 -0
- data/bin/repeatvasp +47 -0
- data/bin/symposcar +154 -0
- data/lib/vasputils/calcinspector.rb +24 -0
- data/lib/vasputils/calcrepeater.rb +27 -0
- data/lib/vasputils/calcseries.rb +98 -0
- data/lib/vasputils/incar.rb +55 -0
- data/lib/vasputils/kpoints.rb +41 -0
- data/lib/vasputils/outcar.rb +59 -0
- data/lib/vasputils/poscar.rb +168 -0
- data/lib/vasputils/potcar.rb +18 -0
- data/lib/vasputils/vaspdir.rb +278 -0
- data/lib/vasputils.rb +0 -0
- data/test/calcseries/dup_finished/try00/CONTCAR +17 -0
- data/test/calcseries/dup_finished/try00/INCAR +28 -0
- data/test/calcseries/dup_finished/try00/KPOINTS +6 -0
- data/test/calcseries/dup_finished/try00/OUTCAR +28 -0
- data/test/calcseries/dup_finished/try00/POSCAR +12 -0
- data/test/calcseries/dup_finished/try00/POTCAR +2 -0
- data/test/calcseries/dup_finished/try00/lock +0 -0
- data/test/calcseries/dup_finished/try01/CONTCAR +17 -0
- data/test/calcseries/dup_finished/try01/INCAR +28 -0
- data/test/calcseries/dup_finished/try01/KPOINTS +6 -0
- data/test/calcseries/dup_finished/try01/OUTCAR +28 -0
- data/test/calcseries/dup_finished/try01/POSCAR +12 -0
- data/test/calcseries/dup_finished/try01/POTCAR +2 -0
- data/test/calcseries/dup_finished/try01/lock +0 -0
- data/test/calcseries/normal_finished/try00/CONTCAR +17 -0
- data/test/calcseries/normal_finished/try00/INCAR +28 -0
- data/test/calcseries/normal_finished/try00/KPOINTS +6 -0
- data/test/calcseries/normal_finished/try00/OUTCAR +40 -0
- data/test/calcseries/normal_finished/try00/POSCAR +12 -0
- data/test/calcseries/normal_finished/try00/POTCAR +2 -0
- data/test/calcseries/normal_finished/try00/lock +0 -0
- data/test/calcseries/normal_finished/try01/CONTCAR +17 -0
- data/test/calcseries/normal_finished/try01/INCAR +28 -0
- data/test/calcseries/normal_finished/try01/KPOINTS +6 -0
- data/test/calcseries/normal_finished/try01/OUTCAR +33 -0
- data/test/calcseries/normal_finished/try01/POSCAR +12 -0
- data/test/calcseries/normal_finished/try01/POTCAR +2 -0
- data/test/calcseries/normal_finished/try01/lock +0 -0
- data/test/calcseries/not_finished/try00/CONTCAR +17 -0
- data/test/calcseries/not_finished/try00/INCAR +28 -0
- data/test/calcseries/not_finished/try00/KPOINTS +6 -0
- data/test/calcseries/not_finished/try00/OUTCAR +38 -0
- data/test/calcseries/not_finished/try00/POSCAR +12 -0
- data/test/calcseries/not_finished/try00/POTCAR +2 -0
- data/test/calcseries/not_finished/try00/lock +0 -0
- data/test/helper.rb +17 -0
- data/test/incar/INCAR.00 +35 -0
- data/test/incar/INCAR.01 +28 -0
- data/test/kpoints/g123-456 +6 -0
- data/test/kpoints/m123-456 +6 -0
- data/test/outcar/01-03-INT.OUTCAR +619 -0
- data/test/outcar/01-13-FIN.OUTCAR +1436 -0
- data/test/outcar/02-05-FIN.OUTCAR +2025 -0
- data/test/outcar/03-05-FIN.OUTCAR +2602 -0
- data/test/outcar/10-01-FIN.OUTCAR +437 -0
- data/test/poscar/NOT_POSCAR +0 -0
- data/test/poscar/POSCAR.00 +10 -0
- data/test/poscar/POSCAR.01 +12 -0
- data/test/poscarparser/POSCAR.00 +10 -0
- data/test/poscarparser/POSCAR.01 +12 -0
- data/test/potcar/POTCAR +5279 -0
- data/test/potcar/POTCAR.allElement +165 -0
- data/test/potcar/POTCAR.dummy +3 -0
- data/test/repeatVasp/Iter2-Nsw2.00/INCAR +35 -0
- data/test/repeatVasp/Iter2-Nsw2.00/KPOINTS +6 -0
- data/test/repeatVasp/Iter2-Nsw2.00/POSCAR +12 -0
- data/test/repeatVasp/Iter2-Nsw2.00/POTCAR +3151 -0
- data/test/repeatVasp/test.sh +3 -0
- data/test/test_calcinspector.rb +53 -0
- data/test/test_calcrepeater.rb +69 -0
- data/test/test_calcseries.rb +77 -0
- data/test/test_incar.rb +126 -0
- data/test/test_kpoints.rb +110 -0
- data/test/test_outcar.rb +162 -0
- data/test/test_poscar.rb +209 -0
- data/test/test_potcar.rb +65 -0
- data/test/test_vaspdir.rb +253 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/CONTCAR +17 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/INCAR +27 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/KPOINTS +6 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/OUTCAR +1436 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/POSCAR +12 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/POTCAR +3151 -0
- data/test/vaspdir/IBRION-1-NSW000-OUTCAR-Iter1/lock +0 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/CONTCAR +17 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/INCAR +28 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/KPOINTS +6 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/OUTCAR +1436 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/POSCAR +12 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/POTCAR +3151 -0
- data/test/vaspdir/ISIF2-NSW000-OUTCAR-Iter1/lock +0 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/CONTCAR +17 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/INCAR +28 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/KPOINTS +6 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/OUTCAR +1436 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/POSCAR +12 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/POTCAR +3151 -0
- data/test/vaspdir/ISIF2-NSW001-OUTCAR-Iter1/lock +0 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/CONTCAR +17 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/INCAR +28 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/KPOINTS +6 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/OUTCAR +1436 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/POSCAR +12 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/POTCAR +3151 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter1/lock +0 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/CONTCAR +17 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/INCAR +28 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/KPOINTS +6 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/OUTCAR +2602 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/POSCAR +12 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/POTCAR +3151 -0
- data/test/vaspdir/ISIF2-NSW100-OUTCAR-Iter3/lock +0 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/CONTCAR +17 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/INCAR +28 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/KPOINTS +6 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/OUTCAR +1436 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/POSCAR +12 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/POTCAR +3151 -0
- data/test/vaspdir/ISIF3-NSW000-OUTCAR-Iter1/lock +0 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/CONTCAR +17 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/INCAR +28 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/KPOINTS +6 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/OUTCAR +1436 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/POSCAR +12 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/POTCAR +3151 -0
- data/test/vaspdir/ISIF3-NSW001-OUTCAR-Iter1/lock +0 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/CONTCAR +17 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/INCAR +28 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/KPOINTS +6 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/OUTCAR +2025 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/POSCAR +12 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/POTCAR +3151 -0
- data/test/vaspdir/ISIF3-NSW002-OUTCAR-Iter2/lock +0 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/CONTCAR +0 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/INCAR +28 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/KPOINTS +6 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/OUTCAR +619 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/POSCAR +12 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/POTCAR +3151 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter1-INT/lock +0 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/CONTCAR +17 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/INCAR +28 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/KPOINTS +6 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/OUTCAR +2602 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/POSCAR +12 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/POTCAR +3151 -0
- data/test/vaspdir/ISIF3-NSW100-OUTCAR-Iter3/lock +0 -0
- data/test/vaspdir/PI/INCAR +28 -0
- data/test/vaspdir/PI/KPOINTS +5 -0
- data/test/vaspdir/PI/PI12345 +0 -0
- data/test/vaspdir/PI/POSCAR +57 -0
- data/test/vaspdir/PI/POTCAR +698 -0
- data/test/vaspdir/lack-INCAR/KPOINTS +5 -0
- data/test/vaspdir/lack-INCAR/POSCAR +57 -0
- data/test/vaspdir/lack-INCAR/POTCAR +698 -0
- data/test/vaspdir/lack-KPOINTS/INCAR +28 -0
- data/test/vaspdir/lack-KPOINTS/POSCAR +57 -0
- data/test/vaspdir/lack-KPOINTS/POTCAR +698 -0
- data/test/vaspdir/lack-POSCAR/INCAR +28 -0
- data/test/vaspdir/lack-POSCAR/KPOINTS +5 -0
- data/test/vaspdir/lack-POSCAR/POTCAR +698 -0
- data/test/vaspdir/lack-POTCAR/INCAR +28 -0
- data/test/vaspdir/lack-POTCAR/KPOINTS +5 -0
- data/test/vaspdir/lack-POTCAR/POSCAR +57 -0
- data/test/vaspdir/lock/INCAR +28 -0
- data/test/vaspdir/lock/KPOINTS +5 -0
- data/test/vaspdir/lock/POSCAR +57 -0
- data/test/vaspdir/lock/POTCAR +698 -0
- data/test/vaspdir/lock/lock +0 -0
- data/test/vaspdir/lock-PI/INCAR +28 -0
- data/test/vaspdir/lock-PI/KPOINTS +5 -0
- data/test/vaspdir/lock-PI/PI12345 +0 -0
- data/test/vaspdir/lock-PI/POSCAR +57 -0
- data/test/vaspdir/lock-PI/POTCAR +698 -0
- data/test/vaspdir/lock-PI/lock +0 -0
- data/test/vaspdir/next-try00/CONTCAR +17 -0
- data/test/vaspdir/next-try00/INCAR +28 -0
- data/test/vaspdir/next-try00/KPOINTS +6 -0
- data/test/vaspdir/next-try00/OUTCAR +2025 -0
- data/test/vaspdir/next-try00/POSCAR +12 -0
- data/test/vaspdir/next-try00/POTCAR +3151 -0
- data/test/vaspdir/next-try00/lock +0 -0
- data/test/vaspdir/not-yet-ISIF2/INCAR +28 -0
- data/test/vaspdir/not-yet-ISIF2/KPOINTS +5 -0
- data/test/vaspdir/not-yet-ISIF2/PI17489 +2 -0
- data/test/vaspdir/not-yet-ISIF2/PI17736 +2 -0
- data/test/vaspdir/not-yet-ISIF2/PI1858 +2 -0
- data/test/vaspdir/not-yet-ISIF2/PI1866 +2 -0
- data/test/vaspdir/not-yet-ISIF2/PI2059 +2 -0
- data/test/vaspdir/not-yet-ISIF2/POSCAR +57 -0
- data/test/vaspdir/not-yet-ISIF2/POTCAR +698 -0
- data/test/vaspdir/not-yet-ISIF3/INCAR +28 -0
- data/test/vaspdir/not-yet-ISIF3/KPOINTS +5 -0
- data/test/vaspdir/not-yet-ISIF3/POSCAR +57 -0
- data/test/vaspdir/not-yet-ISIF3/POTCAR +698 -0
- data/vasputils.gemspec +272 -0
- metadata +409 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
# see http://cms.mpi.univie.ac.at/vasp/vasp/INCAR_File.html
|
5
|
+
#
|
6
|
+
# INCAR のフォーマット
|
7
|
+
# - 基本 1行 1項目。
|
8
|
+
# - = 区切りで左辺の項目名に対して右辺の値になる。
|
9
|
+
# - 半角# のあと、コメント
|
10
|
+
#
|
11
|
+
# TODO, Future feature
|
12
|
+
# INCAR のフォーマット
|
13
|
+
# - 右辺のあとの文字列は、セミコロンでなければ無視される。
|
14
|
+
# - ; 区切りで1行に複数の項目を設定できる。
|
15
|
+
# - \ で次の行に設定を続けることができる。
|
16
|
+
|
17
|
+
# Class to utilize INCAR file of VASP.
|
18
|
+
# まず、自分で使う範囲だけ作る。
|
19
|
+
# あとで余力があれば精密化する。
|
20
|
+
module Incar
|
21
|
+
#
|
22
|
+
#def initialize()
|
23
|
+
#end
|
24
|
+
|
25
|
+
# 与えられた IO を読み込み、INCAR として解析したハッシュを返す。
|
26
|
+
def self.parse(io)
|
27
|
+
results = {}
|
28
|
+
io.each_line do |line|
|
29
|
+
line.sub!(/\#.*/, "") # コメント文字以降を削除
|
30
|
+
next unless /=/ =~ line
|
31
|
+
if /(.*)=(.*)/ =~ line
|
32
|
+
key = $1.strip
|
33
|
+
val = $2.strip
|
34
|
+
val.sub!(/\s.*$/, "")
|
35
|
+
next if key.empty?
|
36
|
+
results[key] = val
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return results
|
40
|
+
end
|
41
|
+
|
42
|
+
# 与えられた名前のファイルを INCAR として解析したハッシュを返す。
|
43
|
+
def self.load_file(file)
|
44
|
+
io = File.open(file, "r")
|
45
|
+
return self.parse(io)
|
46
|
+
end
|
47
|
+
|
48
|
+
## 与えられたデータ対(ハッシュ)を io に書き出す。
|
49
|
+
## io が nil の場合は INCAR 形式文字列を返す。
|
50
|
+
## (改行文字を埋め込んでおり、配列化していない)
|
51
|
+
#def dump(pairs, io = nil)
|
52
|
+
#end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
# Module dearing with KPOINTS.
|
5
|
+
module Kpoints
|
6
|
+
def self.parse(io)
|
7
|
+
results = {}
|
8
|
+
results[:comment] = io.readline.chomp
|
9
|
+
|
10
|
+
raise "Not automatic generating KPOINTS! 2nd line must be 0." unless io.readline == "0\n"
|
11
|
+
|
12
|
+
line = io.readline
|
13
|
+
case line
|
14
|
+
when /^m/i; then; results[:type] = :monkhorst
|
15
|
+
when /^g/i; then; results[:type] = :gamma_center
|
16
|
+
else
|
17
|
+
raise "Kpoints module can deal with only monkhorst and gamma-center."
|
18
|
+
end
|
19
|
+
|
20
|
+
#pp io.readline.strip.split(/\s+/).map{|i| i.to_i}
|
21
|
+
results[:mesh] = io.readline.strip.split(/\s+/).map{|i| i.to_i}
|
22
|
+
#pp io.readline.strip.split(/\s+/).map{|i| i.to_f}
|
23
|
+
results[:shift] = io.readline.strip.split(/\s+/).map{|i| i.to_f}
|
24
|
+
|
25
|
+
return results
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
def self.load_file(file)
|
30
|
+
self.parse(File.open(file, "r"))
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.dump(data, io)
|
34
|
+
io.puts "Automatic mesh"
|
35
|
+
io.puts "0"
|
36
|
+
io.puts data[:type].to_s.capitalize
|
37
|
+
io.puts data[:mesh].join(" ")
|
38
|
+
io.puts data[:shift].join(" ")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# OUTCAR をパースする。
|
2
|
+
# 精確には行わず、必要な情報だけをピックアップする感じ。
|
3
|
+
#
|
4
|
+
# あまり頑張らないことにした理由は以下。
|
5
|
+
# OUTCAR がどう出力されるのかがよくわからない。
|
6
|
+
# 本来は vasp のソースを見て決めるべきだろう。
|
7
|
+
# やるとすればかなり大掛かりなプロジェクトになるが、そのわりには旨味が少ない。
|
8
|
+
# grep でなんとかなるし。
|
9
|
+
#
|
10
|
+
# 基本的に終了した計算から情報を取り出すには vasprun.xml を読む。
|
11
|
+
# OUTCAR は終了する前も含めてなんか簡単に見るために使う、という位置付けで。
|
12
|
+
|
13
|
+
module Outcar
|
14
|
+
#toten は全 electronic and ionic steps のを flat に並べただけのもの。
|
15
|
+
#必要なら構造化するが、現状その予定はない。
|
16
|
+
#attr_reader :name
|
17
|
+
#attr_reader :ionic_steps, :electronic_steps, :totens, :volumes, :elapsed_time
|
18
|
+
|
19
|
+
def self.load_file(file)
|
20
|
+
results = {}
|
21
|
+
results[:name] = file
|
22
|
+
results[:irreducible_kpoints] = nil
|
23
|
+
results[:electronic_steps ] = 0
|
24
|
+
results[:ionic_steps ] = 0
|
25
|
+
results[:totens ] = []
|
26
|
+
results[:volumes ] = []
|
27
|
+
results[:elapsed_time ] = nil
|
28
|
+
results[:normal_ended ] = false
|
29
|
+
|
30
|
+
lines = File.readlines(file)
|
31
|
+
lines.each do |line|
|
32
|
+
if /Found\s+(\d+)\s+irreducible k-points/i =~ line
|
33
|
+
results[:irreducible_kpoints] = $1.to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
if /^-* Iteration\s+(\d+)/ =~ line
|
37
|
+
results[:ionic_steps ] = $1.to_i
|
38
|
+
results[:electronic_steps] += 1
|
39
|
+
end
|
40
|
+
|
41
|
+
#if /free\s+energy\s+TOTEN\s+=\s(.*)\s+eV/ =~ line
|
42
|
+
if /TOTEN\s+=\s(.*)\s+eV/ =~ line
|
43
|
+
results[:totens] << $1.to_f
|
44
|
+
end
|
45
|
+
|
46
|
+
if /volume of cell :\s+(\d+\.\d+)$/ =~ line
|
47
|
+
results[:volumes] << $1.to_f
|
48
|
+
end
|
49
|
+
|
50
|
+
if (/Elapsed time \(sec\):\s+(\d+\.\d+)/ =~ line)
|
51
|
+
results[:elapsed_time] = $1.to_f
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
results[:normal_ended] = true if (/Voluntary context switches:/ =~ lines[-1])
|
56
|
+
|
57
|
+
results
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
gem "crystalcell"
|
5
|
+
require "crystalcell/cell.rb"
|
6
|
+
|
7
|
+
# Class to manage POSCAR format of VASP.
|
8
|
+
#
|
9
|
+
# parse と dump のどちらかだけでなく、両方を統括して扱うクラス。
|
10
|
+
#
|
11
|
+
# MEMO
|
12
|
+
# POSCAR 自身は元素の情報を持っていない。
|
13
|
+
# POSCAR が native に持っている情報だけを取り扱う。
|
14
|
+
# Poscar では個々の原子が何の element であるかという情報を取り扱わない。
|
15
|
+
# 1番目の種類の原子種が何かだけを扱う。
|
16
|
+
# こうしておくことで POTCAR がない環境でも POSCAR を扱うことができる。
|
17
|
+
#
|
18
|
+
# VASP 5 系を使うようになれば事情が変わるだろう。
|
19
|
+
class Poscar
|
20
|
+
|
21
|
+
class ElementMismatchError < Exception; end
|
22
|
+
class ParseError < Exception; end
|
23
|
+
|
24
|
+
# io を読み込んで Cell クラスインスタンスを返す。
|
25
|
+
# 構文解析できなければ例外 Poscar::ParseError を投げる。
|
26
|
+
def self.parse(io)
|
27
|
+
# analyze POSCAR.
|
28
|
+
|
29
|
+
begin
|
30
|
+
#line 1: comment (string)
|
31
|
+
comment = io.readline.chomp
|
32
|
+
|
33
|
+
#line 2: universal scaling factor (float)
|
34
|
+
scale = io.readline.to_f
|
35
|
+
raise "Poscar.load_file cannot use negative scaling factor.\n" if scale < 0
|
36
|
+
|
37
|
+
#line 3-5: axes (3x3 Array of float)
|
38
|
+
axes = []
|
39
|
+
3.times do |i| #each axis of a, b, c.
|
40
|
+
vec = io.readline.strip.split(/\s+/) #in x,y,z directions
|
41
|
+
axes << vec.collect! { |i| i.to_f * scale } #multiply scaling factor
|
42
|
+
end
|
43
|
+
|
44
|
+
#line 6: numbers of elements. e.g.,[1, 1, 2]
|
45
|
+
nums_elements = io.readline.strip.split( /\s+/ ).map{|i| i.to_i}
|
46
|
+
|
47
|
+
#line 7-(8): 'Selective dynamics' or not (bool)
|
48
|
+
line = io.readline
|
49
|
+
if line =~ /^\s*s/i
|
50
|
+
selective_dynamics = true
|
51
|
+
line = io.readline # when this situation, reading one more line is nessesarry
|
52
|
+
end
|
53
|
+
|
54
|
+
if (line =~ /^\s*d/i ) # allow only 'Direct' now
|
55
|
+
direct = true
|
56
|
+
else
|
57
|
+
raise "Not 'direct' indication."
|
58
|
+
end
|
59
|
+
|
60
|
+
#line 9(8): position
|
61
|
+
#e.g., positions_of_elements
|
62
|
+
#e.g., movable_flags_of_elements
|
63
|
+
|
64
|
+
atoms = []
|
65
|
+
nums_elements.size.times do |elem_index|
|
66
|
+
nums_elements[elem_index].times do |index|
|
67
|
+
items = io.readline.strip.split( /\s+/ )
|
68
|
+
pos = items[0..2].map {|coord| coord.to_f}
|
69
|
+
#pp pos
|
70
|
+
|
71
|
+
mov_flags = []
|
72
|
+
if items.size >= 6 then
|
73
|
+
items[3..5].each do |i|
|
74
|
+
( i =~ /^t/i ) ? mov_flags << true : mov_flags << false
|
75
|
+
end
|
76
|
+
atoms << Atom.new(elem_index, pos, mov_flags)
|
77
|
+
else
|
78
|
+
atoms << Atom.new(elem_index, pos)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
rescue EOFError
|
83
|
+
raise ParseError, "end of file reached"
|
84
|
+
end
|
85
|
+
|
86
|
+
cell = Cell.new(axes, atoms )
|
87
|
+
cell.comment = comment
|
88
|
+
cell
|
89
|
+
end
|
90
|
+
|
91
|
+
# file で与えられた名前のファイルを読み込んで Cell クラスインスタンスを返す。
|
92
|
+
# 構文解析できなければ例外 Poscar::ParseError を投げる。
|
93
|
+
def self.load_file(file)
|
94
|
+
io = File.open(file, "r")
|
95
|
+
self.parse(io)
|
96
|
+
end
|
97
|
+
|
98
|
+
# POSCAR 形式で書き出す。
|
99
|
+
# cell は Cell クラスインスタンスと同等のメソッドを持つもの。
|
100
|
+
# elems は書き出す元素の順番。
|
101
|
+
# elems が cell の持つ元素リストとマッチしなければ
|
102
|
+
# 例外 Poscar::ElementMismatchError を投げる。
|
103
|
+
# io は書き出すファイルハンドル。
|
104
|
+
def self.dump(cell, elems, io)
|
105
|
+
unless (Mapping::map?(cell.elements.uniq, elems){ |i, j| i == j })
|
106
|
+
raise ElementMismatchError,
|
107
|
+
"elems [#{elems.join(",")}] mismatches to cell.elements [#{cell.elements.join(",")}."
|
108
|
+
end
|
109
|
+
|
110
|
+
io.puts cell.comment
|
111
|
+
io.puts "1.0" #scale
|
112
|
+
3.times do |i|
|
113
|
+
io.printf( " % 18.15f % 18.15f % 18.15f\n", cell.axes[i][0], cell.axes[i][1], cell.axes[i][2]
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
# collect information
|
118
|
+
elem_list = Hash.new
|
119
|
+
elems.each do |elem|
|
120
|
+
elem_list[ elem ] = cell.atoms.select{ |atom| atom.element == elem }
|
121
|
+
end
|
122
|
+
io.puts(elems.map { |elem| elem_list[elem].size }.join(" "))
|
123
|
+
|
124
|
+
# Selective dynamics
|
125
|
+
# どれか1つでも getMovableFlag が真であれば Selective dynamics をオンにする
|
126
|
+
selective_dynamics = false
|
127
|
+
cell.atoms.each do |atom|
|
128
|
+
if atom.movable_flags
|
129
|
+
selective_dynamics = true
|
130
|
+
io.puts "Selective dynamics"
|
131
|
+
break
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
elems.each do |elem|
|
136
|
+
elem_list[ elem ].each do |atom|
|
137
|
+
if atom.movable_flags
|
138
|
+
selective_dynamics = true
|
139
|
+
break
|
140
|
+
end
|
141
|
+
end
|
142
|
+
break if selective_dynamics
|
143
|
+
end
|
144
|
+
|
145
|
+
io.puts "Direct"
|
146
|
+
|
147
|
+
# positions of atoms
|
148
|
+
elems.each do |elem|
|
149
|
+
elem_list[ elem ].each do |atom|
|
150
|
+
tmp = sprintf(
|
151
|
+
" % 18.15f % 18.15f % 18.15f",
|
152
|
+
* atom.position )
|
153
|
+
if selective_dynamics
|
154
|
+
if atom.movable_flags == nil
|
155
|
+
tmp += " T T T"
|
156
|
+
else
|
157
|
+
atom.movable_flags.each do |mov|
|
158
|
+
( mov == true ) ? tmp += " T" : tmp += " F"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
io.puts tmp
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#
|
2
|
+
# Class for dealing with POTCAR.
|
3
|
+
#
|
4
|
+
module Potcar
|
5
|
+
def self.load_file(file)
|
6
|
+
results = {}
|
7
|
+
results[:name] = file
|
8
|
+
|
9
|
+
elements = Array.new
|
10
|
+
File.open( file, "r" ).each do |line|
|
11
|
+
if line =~ /VRHFIN\s*=\s*([A-Za-z]*)/
|
12
|
+
elements << $1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
results[:elements] = elements
|
16
|
+
results
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
require "vasputils/incar.rb"
|
5
|
+
require "vasputils/outcar.rb"
|
6
|
+
require "vasputils/poscar.rb"
|
7
|
+
require "vasputils/kpoints.rb"
|
8
|
+
require "fileutils"
|
9
|
+
require "pp"
|
10
|
+
require "date"
|
11
|
+
|
12
|
+
|
13
|
+
# vasp 実行ディレクトリ(入力・出力ファイルを含む)を扱うクラス
|
14
|
+
#
|
15
|
+
# MEMO
|
16
|
+
# interrupted? みたいなメソッドは作れない。
|
17
|
+
# 実行が開始したあと、その計算の状態が中断されているのか、
|
18
|
+
# 単に実行中でファイルが書き込まれている途中なのか、
|
19
|
+
# プログラムを実行しているプロセス自身以外は、外部からは判別がつかない。
|
20
|
+
#
|
21
|
+
# ルール
|
22
|
+
# try00 形式の postfix がついていることを前提とする。
|
23
|
+
# 00 の部分には CONTCAR を POSCAR にする手続きで連続して行う計算の番号を示す。
|
24
|
+
#
|
25
|
+
class VaspDir
|
26
|
+
|
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
|
276
|
+
|
277
|
+
end
|
278
|
+
|
data/lib/vasputils.rb
ADDED
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Untitled (VASP)
|
2
|
+
1.00000000000000
|
3
|
+
3.6218218384059248 -0.0000000000000001 0.0000000000000000
|
4
|
+
-1.8109109192029544 3.1365897200407926 0.0000000000000000
|
5
|
+
0.0000000000000000 0.0000000000000000 3.8586803850215405
|
6
|
+
3 1
|
7
|
+
Selective dynamics
|
8
|
+
Direct
|
9
|
+
0.0000000000000000 0.0000000000000000 0.5000000000000000 T T T
|
10
|
+
0.3333333333333357 0.6666666666666642 0.0000000000000000 T T T
|
11
|
+
0.6666666666666642 0.3333333333333357 0.0000000000000000 T T T
|
12
|
+
0.0000000000000000 0.0000000000000000 0.0000000000000000 F F F
|
13
|
+
|
14
|
+
0.00000000E+00 0.00000000E+00 0.00000000E+00
|
15
|
+
0.00000000E+00 0.00000000E+00 0.00000000E+00
|
16
|
+
0.00000000E+00 0.00000000E+00 0.00000000E+00
|
17
|
+
0.00000000E+00 0.00000000E+00 0.00000000E+00
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# SCF input for VASP
|
2
|
+
|
3
|
+
SYSTEM = Untitled (VASP)
|
4
|
+
PREC = High
|
5
|
+
IBRION = 2 #-1:atoms not moved, 1:quasi-Newton, 2:conjugate-gradient
|
6
|
+
NSW = 3 #maximum number of ionic steps
|
7
|
+
ISIF = 2
|
8
|
+
ENCUT = 400
|
9
|
+
NELM = 60 #maximum number of electronic steps
|
10
|
+
NELMIN = 2 #minimum number of electronic steps
|
11
|
+
EDIFF = 1.0e-05
|
12
|
+
EDIFFG = -0.02
|
13
|
+
VOSKOWN = 1
|
14
|
+
NBLOCK = 1
|
15
|
+
ISPIN = 1 #1:non spin polarized, 2:spin polarized
|
16
|
+
INIWAV = 1
|
17
|
+
ISTART = 1
|
18
|
+
ICHARG = 1
|
19
|
+
LWAVE = .TRUE.
|
20
|
+
LCHARG = .TRUE.
|
21
|
+
ISMEAR = 0
|
22
|
+
SIGMA = 0.1
|
23
|
+
IALGO = 38 #38:KosugiAlgorithm, 48:RMM-DIIS
|
24
|
+
#LREAL = .FALSE.
|
25
|
+
LREAL = Auto #fast & not accurate
|
26
|
+
NGX = 36
|
27
|
+
NGY = 36
|
28
|
+
NGZ = 42
|