class SiteNameLabeledCell
原子に一意のサイト名がついていることを前提とする幾つかのメソッドのためのクラス。 このクラスになってさえいれば、この前提はクリアしたものとして扱える。 また、サイト名が unique に原子につけられることを new するときにチェックする。
このクラスがなかったら、このプログラム用の雑多なメソッドを CrystalCell::PeriodicCell に 入れなければならなくなるので、名前空間の切り分け的な機能も期待。
通常の CrystalCell::Cell
系クラスとの大きな違いとして、 モデル構造のサイト名と座標をハッシュとしてインスタンス変数に持つ。
new されたときに最近接のサイトでサイト名を原子につけるが、 その後操作を加えたら、 つけられたサイト名がその時点で最近接であることは保証されない。 このクラスはあまり汎用性を考えない。 厳密な定義とか、他の CrystalCell::Cell
系クラスとの整合性よりも 早いプログラミングを目的とする。
Constants
- TOLERANCE
Public Class Methods
sites はサイト名を鍵、内部座標を値とするハッシュ。 内部座標は Mageo::Vector3DInternal クラスインスタンスであることを前提とする。
サイト名の数(sites.size)と保持している原子の数が違えば例外。
一対一対応しなければ例外。 例外は比較的頻繁に生じるだろうから、 外部で例外をキャッチする必要があることに注意。
# File lib/crysna/sitenamelabeledcell.rb, line 41 def initialize(axes, atoms, sites) unless atoms.size == sites.size raise InitializeError, "atoms.size is #{atoms.size}, while sites.size is #{sites.size}" end #super(axes) @axes = axes @sites = sites self.class.check_inside_all_sites(@sites) atoms = self.class.label_sitenames(axes, atoms, sites) unless self.class.labeled_all_atoms?(atoms, sites) raise InitializeError, "Not labeled site names for every atom." end @atoms = self.class.periodically_translate_atoms_to_nearest_site(axes, atoms, sites) unless self.class.unique_sitenames?(@atoms) raise InitializeError, "Not unique site names for atoms." end end
Private Class Methods
各サイトについて内部座標が 0以上1未満でなければ 例外 SiteNameLabeledCell::OutOfCellError
を生じる。
# File lib/crysna/sitenamelabeledcell.rb, line 169 def self.check_inside_all_sites(sites) sites.each do |name, vec| vec.to_a.each do |val| if (val < 0.0-TOLERANCE) || (1.0+TOLERANCE <= val) raise OutOfCellError, "#{name}, #{vec.inspect}" end end end end
与えられた原子のリストのそれぞれの原子について、 周期境界条件的に最も近いサイトを判定し 原子にサイト名をつけるた原子に map した配列を返す。
# File lib/crysna/sitenamelabeledcell.rb, line 127 def self.label_sitenames(axes, atoms, sites) atoms.each do |atom| name = SiteNameLabeledCell.nearest_site(axes, atom.position, sites) atom.name = name end return atoms end
# File lib/crysna/sitenamelabeledcell.rb, line 179 def self.labeled_all_atoms?(atoms, sites) atoms.each do |atom| return false unless sites.keys.include?(atom.name) end return true end
引数で与えられた 格子の軸、サイト名ハッシュに対して、 与えられた内部座標 に最も近いサイト名の文字列を返す。
# File lib/crysna/sitenamelabeledcell.rb, line 150 def self.nearest_site(axes, internal_coord, sites) pc = CrystalCell::PeriodicCell.new(axes) results = sites.min_by do |key, val| pc.nearest_distance(val, internal_coord) end return results[0] end
与えられた原子のリストのそれぞれの原子につけられたサイト名から、 サイトの座標に最も近くなるように周期的並進移動した原子に map した配列を返す。 原子の内部座標は 0〜1 の間になるとは限らない。
# File lib/crysna/sitenamelabeledcell.rb, line 138 def self.periodically_translate_atoms_to_nearest_site(axes, atoms, sites) cell = CrystalCell::PeriodicCell.new(axes, atoms) atoms = cell.atoms atoms.map! do |atom| translation = cell.nearest_direction(atom.position, sites[atom.name]) atom.translate(translation * (-1.0)) end return atoms end
原子についているサイト名が uniq なら true
# File lib/crysna/sitenamelabeledcell.rb, line 160 def self.unique_sitenames?(atoms) sitenames = atoms.map{|atom| atom.name} return false if sitenames.include?(nil) return sitenames.uniq.size == atoms.size end
Public Instance Methods
原子座標の相加平均を内部座標で返す。
# File lib/crysna/sitenamelabeledcell.rb, line 87 def center_of_atoms sum = Mageo::Vector3DInternal[0.0, 0.0, 0.0] @atoms.each do |atom| sum += atom.position end sum = sum * (1.0/(@sites.size.to_f)) end
モデルサイト座標の相加平均を内部座標で返す。
# File lib/crysna/sitenamelabeledcell.rb, line 96 def center_of_sites sum = Mageo::Vector3DInternal[0.0, 0.0, 0.0] @sites.each do |sitename, vec| sum += vec end sum = sum * (1.0/(@sites.size.to_f)) end
サイト名を鍵、その原子の元素を値とするハッシュ を返す。
# File lib/crysna/sitenamelabeledcell.rb, line 114 def sitenames_elements results = {} @atoms.each do |i| results[i.name] = i.element end return results end
サイト名を鍵、その原子の内部座標を値とするハッシュ を返す。
# File lib/crysna/sitenamelabeledcell.rb, line 105 def sitenames_positions results = {} @atoms.each do |i| results[i.name] = i.position end return results end
各原子に付いているサイト名を見て、 そのサイト座標と原子座標の空間的な距離の二乗を全ての原子について和を取り、 その値を返す。
# File lib/crysna/sitenamelabeledcell.rb, line 69 def sum_square_distances @atoms.inject(0.0) do |result, atom| result += (self.to_pcell.nearest_distance(@sites[atom.name] , atom.position))**2 end end
CrystalCell::Cell
クラスインスタンスに変換したものを返す。 原子の座標はそのまま変換しない。
# File lib/crysna/sitenamelabeledcell.rb, line 77 def to_cell result = CrystalCell::Cell.new(@axes) result.comment = self.comment @atoms.each do |atom| result.add_atom(atom) end return result end
Private Instance Methods
引数で与えられたサイト名に対して最も近い原子の @atoms 内の index を返す。 サイト名 site_name は文字列であることを前提とする。
# File lib/crysna/sitenamelabeledcell.rb, line 188 def nearest_atom_index(site_name) raise SiteNameLabeledCell::TypeError if site_name.class != String min_d = self.to_pcell.nearest_distance(@sites[site_name], @atoms[0].position) min_id = 0 @atoms.size.times do |i| tmp = self.to_pcell.nearest_distance(@sites[site_name], @atoms[i].position) if tmp < min_d min_d = tmp min_id = i end end return min_id end