class FrameInterstitialCell
Cell modeled by frame atoms and interstitial atoms. All atoms must be FrameAtom or InterstitialAtom class instance, not CrystalCell::Atom class instance.
class FrameInterstitialCell
< CrystalCell::PeriodicCell
Public Class Methods
new(axes, atoms = [])
click to toggle source
Argument ‘atoms’ must be Array of atoms whose class is FrameAtom
or InterstitialAtom
. If ‘atoms’ includes CrystalCell::Atom class instance, raise exception ‘FrameInterstitialCell::TypeError’
Calls superclass method
# File lib/crysna/frameinterstitialcell.rb, line 29 def initialize(axes, atoms = []) atoms.each_with_index do |atom, i| unless (atom.is_a?(FrameAtom) || (atom.is_a?(InterstitialAtom))) raise TypeError, "'atoms' includes #{atom.class} at #{i}." end end super(axes, atoms) end
Public Instance Methods
elements_names()
click to toggle source
保持する原子群について、 元素ごとに分類し、元素を鍵とするハッシュとする。 ハッシュの値はその元素の原子それぞれに付けられた名前で、ソート済の配列。
# File lib/crysna/frameinterstitialcell.rb, line 181 def elements_names results = {} @atoms.each do |atom| elem = atom.element if results[elem] results[elem] << atom.name else results[elem] = [atom.name] end end results.each_value do |val| val.sort! end return results end
frame_atoms()
click to toggle source
@atoms のうち、 FrameAtom
のものだけをまとめて Array にして返す。
# File lib/crysna/frameinterstitialcell.rb, line 153 def frame_atoms @atoms.select{|atom| atom.class == FrameAtom} end
frame_cell()
click to toggle source
@atoms のうち、 FrameAtom
のものだけを含んだ FrameInterstitialCell
を返す。
# File lib/crysna/frameinterstitialcell.rb, line 164 def frame_cell result = FrameInterstitialCell.new(@axes, frame_atoms) result.comment = self.comment return result end
interstitial_atoms()
click to toggle source
@atoms のうち、 InterstitialAtom
のものだけをまとめて Array にして返す。
# File lib/crysna/frameinterstitialcell.rb, line 158 def interstitial_atoms @atoms.select{|atom| atom.class == InterstitialAtom} end
interstitial_cell()
click to toggle source
@atoms のうち、 InterstitialAtom
のものだけを含んだ FrameInterstitialCell
を返す。
# File lib/crysna/frameinterstitialcell.rb, line 172 def interstitial_cell result = FrameInterstitialCell.new(@axes, interstitial_atoms) result.comment = self.comment return result end
optimized_cell( sites, log_io )
click to toggle source
サイト情報を参照して、骨格原子が最適になるように 48個の変換操作・並進移動を然るべく施したセル( self.class のインスタンス )を返す。 非破壊的 引数 sites はサイト情報を入れたハッシュ。キーがサイト名、値がサイトの内部座標。 サイトと原子が一対一対応する候補が見つからない場合は 例外 FrameInterstitialCell::NoMatchError を返す。 原子の順番は非保存。
def most_matching_cell_pair(sites, log_io )
# File lib/crysna/frameinterstitialcell.rb, line 47 def optimized_cell( sites, log_io ) # 48個のセルに対し、サイト数ごとに roughly translate したセルを作る。 # サイト数が 8 ならば 48*8 個の Array になる。 cells = equivalent_cells.map{ |cell| tmp = [] sites.each do |name, vec| translation_rough = vec - cell.frame_atoms[0].position t_cell = cell.translate(translation_rough) t_cell.comment += sprintf( "; Rough translation: (% 7.5f, % 7.5f, % 7.5f), 0th atom of frame to #{name}", * (translation_rough) ) tmp << t_cell end tmp }.flatten p_io = $stderr p_io = File.open(File::NULL, "w") if $test == true pbar = ProgressBar.new("FrameInterstitialCell::optimized_cell", cells.size, p_io) # 操作と評価を全てに対して行う。 min_cell = nil min_sum = nil cells.each do |cell| pbar.inc # SiteNameLabeledCell に変換できない cell が含まれるため、 # min_by メソッドは使えない。 log_io.puts(" #{cell.comment.sub("; ", " \\\n ")}") log_io.puts(" atom coordinates:") cell.atoms.each_with_index do |atom, index| log_io.printf(" (% 7.5f, % 7.5f, % 7.5f), Element:%s, %02i-th atom.\n", * (atom.position), atom.element, index ) end f_cell = cell.frame_cell i_cell = cell.interstitial_cell.to_pcell.to_cell.to_ficell([]) # SiteNameLabeledCell に変換 begin snlcell = f_cell.to_snlcell(sites) rescue SiteNameLabeledCell::InitializeError log_io.puts " Not correspond atoms for sitenames." log_io.puts next # 一対一対応しない場合、無視する。 end # 原子の重心とサイトの重心が一致するように # 精密化した translation を行う。 translation_prec = snlcell.center_of_sites - snlcell.center_of_atoms snlcell.translate!(translation_prec) i_cell.translate!(translation_prec) [snlcell, i_cell].each do |cell| cell.comment += sprintf( "; Precise translation: (% 7.5f, % 7.5f, % 7.5f)\n", * (translation_prec) ) end # log 出力 log_io.puts(" Found frame atoms:") frame_atoms.each do |atom| log_io.printf(" (% 7.5f, % 7.5f % 7.5f), #{atom.name}\n", * atom.position ) end # 二乗和で評価 sum = snlcell.sum_square_distances log_io.printf( " Sum of square distances: %8.4f.\n\n", sum ) if (min_sum == nil) || (sum < min_sum) min_sum = sum min_cell = snlcell.to_cell.to_ficell.unite(i_cell) end end pbar.finish unless min_cell.class == FrameInterstitialCell raise NoMatchError, "Class of min_cell is #{min_cell.class}" end log_io.puts( " Chosen cell: #{min_cell.comment}") log_io.puts( " sum of square distances: #{min_sum}") # サイト情報をここで全部書き出しておく。 log_io.puts(" Atoms:") min_cell.atoms.each do |atom| log_io.printf( " (% 7.5f, % 7.5f, % 7.5f), element %s, %s.\n", * atom.position, atom.element, atom.name, ) end #logs.each do |line| # log_io.puts line #end log_io.puts return min_cell end
Private Instance Methods
equivalent_cells()
click to toggle source
セルに対して格子ベクトルの反転・交換操作を組み合わせた結果生じる 全 48 個のセルを配列にして返す。 鏡像操作は含まれない。 交換 → 反転 の順で操作を施す。 返される配列内部の順序は、以下の組み合わせ。
範囲 a反転 b反転 c反転 00-05 x x x 06-11 o x x 12-17 x o x 18-23 o o x 24-29 x x o 30-35 o x o 36-41 x o o 42-47 o o o 各々の範囲中では、6要素が以下の順序。 00: a,b,c(a,b 交換→ a,b交換)(交換なし) 01: b,c,a(a,b 交換→ b,c交換) 02: c,a,b(a,b 交換→ c,a交換) 03: b,a,c(a,b 交換) 04: a,c,b(b,c 交換) 05: c,b,a(c,a 交換)
# File lib/crysna/frameinterstitialcell.rb, line 222 def equivalent_cells results = [] gen_size = 48 gen_size.times do |i| cell = Marshal.load(Marshal.dump(self)) comments = [ sprintf("Equivalent cell No.%02d: Original", i) ] case i % 6 when 0 #"do nothing" when 1 cell.exchange_axes!([0,1]) cell.exchange_axes!([1,2]) comments << "Axes exchanged(a,b,c -> b,c,a)" when 2 cell.exchange_axes!([0,1]) cell.exchange_axes!([2,0]) comments << "Axes exchanged(a,b,c -> c,a,b)" when 3 cell.exchange_axes!([0,1]) comments << "Axes exchanged(a,b,c -> b,a,c)" when 4 cell.exchange_axes!([1,2]) comments << "Axes exchanged(a,b,c -> a,c,b)" when 5 cell.exchange_axes!([2,0]) comments << "Axes exchanged(a,b,c -> c,b,a)" end if ((i / 6) % 2 == 1) cell.inverse_axis!(0) comments << "Axis 'a' inversed" end if ((i / 12) % 2 == 1) cell.inverse_axis!(1) comments << "Axis 'b' inversed" end if ((i / 24) % 2 == 1) cell.inverse_axis!(2) comments << "Axis 'c' inversed" end #if ((i / 48) % 2 == 1) # cell.reflect! # comments << "Reflected" #end cell.comment = comments.join(" -> ") + "." results << cell end return results end