Class: VaspUtils::Poscar
- Inherits:
-
Object
- Object
- VaspUtils::Poscar
- Defined in:
- lib/vasputils/poscar.rb
Overview
Class to manage POSCAR format of VASP.
parse と dump のどちらかだけでなく、両方を統括して扱うクラス。
MEMO POSCAR 自身は元素の情報を持っていない。 POSCAR が native に持っている情報だけを取り扱う。 Poscar では個々の原子が何の element であるかという情報を取り扱わない。 1番目の種類の原子種が何かだけを扱う。 こうしておくことで POTCAR がない環境でも POSCAR を扱うことができる。
VASP 5 系を使うようになれば事情が変わるだろう。
Defined Under Namespace
Classes: ElementMismatchError, ParseError
Class Method Summary collapse
-
.dump(cell, elems, io, version = 5) ⇒ Object
POSCAR 形式で書き出す。 cell は Cell クラスインスタンスと同等のメソッドを持つもの。 elems は書き出す元素の順番。 elems が cell の持つ元素リストとマッチしなければ 例外 Poscar::ElementMismatchError を投げる。 io は書き出すファイルハンドル。 ‘version’ indicates a poscar style for vasp 4 or 5.
-
.load_file(file) ⇒ Object
file で与えられた名前のファイルを読み込んで Cell クラスインスタンスを返す。 構文解析できなければ例外 Poscar::ParseError を投げる。.
-
.parse(io) ⇒ Object
io を読み込んで Cell クラスインスタンスを返す。 構文解析できなければ例外 Poscar::ParseError を投げる。.
Class Method Details
.dump(cell, elems, io, version = 5) ⇒ Object
POSCAR 形式で書き出す。 cell は Cell クラスインスタンスと同等のメソッドを持つもの。 elems は書き出す元素の順番。
elems が cell の持つ元素リストとマッチしなければ
例外 Poscar::ElementMismatchError を投げる。
io は書き出すファイルハンドル。 ‘version’ indicates a poscar style for vasp 4 or 5.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/vasputils/poscar.rb', line 115 def self.dump(cell, elems, io, version = 5) unless (Mapping::map?(cell.elements.uniq, elems){ |i, j| i == j }) raise ElementMismatchError, "elems [#{elems.join(",")}] mismatches to cell.elements [#{cell.elements.join(",")}." end io.puts cell.comment io.puts "1.0" #scale 3.times do |i| io.printf(" % 18.15f % 18.15f % 18.15f\n", cell.axes[i][0], cell.axes[i][1], cell.axes[i][2] ) end # Element symbols for vasp 5. if version >= 5 io.puts cell.atoms.map {|atom| atom.element}.uniq.join(" ") end # Atom numbers. elem_list = Hash.new elems.each do |elem| elem_list[ elem ] = cell.atoms.select{ |atom| atom.element == elem } end io.puts(elems.map { |elem| elem_list[elem].size }.join(" ")) # Selective dynamics # どれか1つでも getMovableFlag が真であれば Selective dynamics をオンにする selective_dynamics = false cell.atoms.each do |atom| if atom.movable_flags selective_dynamics = true io.puts "Selective dynamics" break end end elems.each do |elem| elem_list[ elem ].each do |atom| if atom.movable_flags selective_dynamics = true break end end break if selective_dynamics end io.puts "Direct" # positions of atoms elems.each do |elem| elem_list[ elem ].each do |atom| tmp = sprintf( " % 18.15f % 18.15f % 18.15f", * atom.position) if selective_dynamics if atom.movable_flags == nil tmp += " T T T" else atom.movable_flags.each do |mov| (mov == true) ? tmp += " T" : tmp += " F" end end end io.puts tmp end end end |
.load_file(file) ⇒ Object
file で与えられた名前のファイルを読み込んで Cell クラスインスタンスを返す。 構文解析できなければ例外 Poscar::ParseError を投げる。
103 104 105 106 |
# File 'lib/vasputils/poscar.rb', line 103 def self.load_file(file) io = File.open(file, "r") self.parse(io) end |
.parse(io) ⇒ Object
io を読み込んで Cell クラスインスタンスを返す。 構文解析できなければ例外 Poscar::ParseError を投げる。
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/vasputils/poscar.rb', line 28 def self.parse(io) # analyze POSCAR. begin #line 1: comment (string) comment = io.readline.chomp #line 2: universal scaling factor (float) scale = io.readline.to_f raise "Poscar.load_file cannot use negative scaling factor.\n" if scale < 0 #line 3-5: axes (3x3 Array of float) axes = [] 3.times do |i| #each axis of a, b, c. vec = io.readline.strip.split(/\s+/) #in x,y,z directions axes << vec.collect! { |i| i.to_f * scale } #multiply scaling factor end # Element symbol (vasp 5). Nothing in vasp 4. #elements = io.readline.strip.split(/\s+/).map{|i| i.to_i} vals = io.readline.strip.split(/\s+/) if vals[0].to_i == 0 elements = vals nums_elements = io.readline.strip.split(/\s+/).map{|i| i.to_i} else elements = [] vals.size.times { |i| elements << i } nums_elements = vals.map{|i| i.to_i} end # 'Selective dynamics' or not (bool) line = io.readline if line =~ /^\s*s/i selective_dynamics = true line = io.readline # when this situation, reading one more line is nessesarry end if (line =~ /^\s*d/i) # allow only 'Direct' now direct = true else raise "Not 'direct' indication." end # atom positions # e.g., positions_of_elements # e.g., movable_flags_of_elements atoms = [] nums_elements.size.times do |elem_index| nums_elements[elem_index].times do |index| items = io.readline.strip.split(/\s+/) pos = items[0..2].map {|coord| coord.to_f} mov_flags = [] if items.size >= 6 then items[3..5].each do |i| (i =~ /^t/i) ? mov_flags << true : mov_flags << false end atoms << Atom.new(elements[elem_index], pos, mov_flags) else atoms << Atom.new(elements[elem_index], pos) end end end rescue EOFError raise ParseError, "end of file reached" end cell = Cell.new(axes, atoms) cell.comment = comment cell end |