class SiteNameLabeledCell

原子に一意のサイト名がついていることを前提とする幾つかのメソッドのためのクラス。 このクラスになってさえいれば、この前提はクリアしたものとして扱える。 また、サイト名が unique に原子につけられることを new するときにチェックする。

このクラスがなかったら、このプログラム用の雑多なメソッドを CrystalCell::PeriodicCell に 入れなければならなくなるので、名前空間の切り分け的な機能も期待。

通常の CrystalCell::Cell 系クラスとの大きな違いとして、 モデル構造のサイト名と座標をハッシュとしてインスタンス変数に持つ。

new されたときに最近接のサイトでサイト名を原子につけるが、 その後操作を加えたら、 つけられたサイト名がその時点で最近接であることは保証されない。 このクラスはあまり汎用性を考えない。 厳密な定義とか、他の CrystalCell::Cell系クラスとの整合性よりも 早いプログラミングを目的とする。

Constants

TOLERANCE

Public Class Methods

new(axes, atoms, sites) click to toggle source

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

check_inside_all_sites(sites) click to toggle source

各サイトについて内部座標が 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
label_sitenames(axes, atoms, sites) click to toggle source

与えられた原子のリストのそれぞれの原子について、 周期境界条件的に最も近いサイトを判定し 原子にサイト名をつけるた原子に 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
labeled_all_atoms?(atoms, sites) click to toggle source
# 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
nearest_site(axes, internal_coord, sites) click to toggle source

引数で与えられた 格子の軸、サイト名ハッシュに対して、 与えられた内部座標 に最も近いサイト名の文字列を返す。

# 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
periodically_translate_atoms_to_nearest_site(axes, atoms, sites) click to toggle source

与えられた原子のリストのそれぞれの原子につけられたサイト名から、 サイトの座標に最も近くなるように周期的並進移動した原子に 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
unique_sitenames?(atoms) click to toggle source

原子についているサイト名が 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

center_of_atoms() click to toggle source

原子座標の相加平均を内部座標で返す。

# 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
center_of_sites() click to toggle source

モデルサイト座標の相加平均を内部座標で返す。

# 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
sitenames_elements() click to toggle source

サイト名を鍵、その原子の元素を値とするハッシュ を返す。

# File lib/crysna/sitenamelabeledcell.rb, line 114
def sitenames_elements
  results = {}
  @atoms.each do |i|
    results[i.name] = i.element
  end
  return results
end
sitenames_positions() click to toggle source

サイト名を鍵、その原子の内部座標を値とするハッシュ を返す。

# File lib/crysna/sitenamelabeledcell.rb, line 105
def sitenames_positions
  results = {}
  @atoms.each do |i|
    results[i.name] = i.position
  end
  return results
end
sum_square_distances() click to toggle source

各原子に付いているサイト名を見て、 そのサイト座標と原子座標の空間的な距離の二乗を全ての原子について和を取り、 その値を返す。

# 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
to_cell() click to toggle source

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

nearest_atom_index(site_name) click to toggle source

引数で与えられたサイト名に対して最も近い原子の @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