"""
xyz2cif.py: XYZファイルと設定ファイルからCIFファイルを生成するスクリプト。
概要:
XYZ形式の原子座標ファイルと、格子定数などの結晶情報を記述した設定ファイル(CFG)を読み込み、
国際結晶学連合(IUCr)が定めたCIF (Crystallographic Information File) 形式のファイルを出力します。
詳細説明:
本スクリプトは、特定のフォーマットのXYZファイルとCFGファイルを解釈し、
内部的に`tkCrystal`オブジェクトを構築します。
CFGファイルはサンプル名と格子ベクトルを定義し、XYZファイルは原子の数と各原子のカートン座標を定義します。
読み込まれたカートン座標は、指定された格子ベクトルに基づいて分数座標に変換され、
必要に応じて[0, 1)の範囲に正規化されます。
最終的に、構築された結晶情報は`tkCIFData`オブジェクトを通じてCIFファイルとして保存されます。
関連リンク:
:doc:`xyz2cif_usage`
"""
import os
import sys
import shutil
import glob
import csv
import numpy as np
from numpy import exp, log, sin, cos, tan, arcsin, arccos, arctan, pi
from scipy.interpolate import interp1d
from pprint import pprint
from matplotlib import pyplot as plt
sys.path.append("c:/Programs/python/lib")
sys.path.append("d:/Programs/python/lib")
from tklib.tkfile import tkFile
from tklib.tkutils import IsDir, IsFile, SplitFilePath
from tklib.tksci.tksci import Reduce01, Round
from tklib.tkutils import terminate, pint, pfloat, getarg, getintarg, getfloatarg
from tklib.tksci.tkmatrix import make_matrix1, make_matrix2, make_matrix3
from tklib.tkcrystal.tkcif import tkCIF, tkCIFData
from tklib.tkcrystal.tkcrystal import tkCrystal
from tklib.tkcrystal.tkatomtype import tkAtomType
#================================
# global parameters
#================================
debug = 0
cfgfile = 'STD0.cfg'
xyzfile = 'STD0.xyz'
ciffile = 'STD0.cif'
freduce01 = 1
#=============================
# Treat argments
#=============================
[ドキュメント]
def usage():
"""
概要: スクリプトの正しい使用方法を標準出力に表示します。
詳細説明:
コマンドライン引数の正しい形式と、`reduce01`パラメータの意味について説明します。
主に、引数が不足している場合や不正な場合に呼び出されます。
"""
global cfgfile, xyzfile
global freduce01
print("")
print("Usage:")
print(" (i) python {} xyzfile (reduce01)".format(sys.argv[0]))
print(" reduce01: Reduce fractional coordinates to [0, 1} if reduce01 == 1")
print(" ex: python {} {} {}"
.format(sys.argv[0], xyzfile, freduce01))
[ドキュメント]
def updatevars():
"""
概要: コマンドライン引数を解析し、グローバル変数を更新します。
詳細説明:
`sys.argv`からXYZファイル名と`freduce01`フラグを読み取ります。
XYZファイル名に基づいて、対応する設定ファイル(CFG)名と出力CIFファイル名を派生させ、
これらのグローバル変数を更新します。
"""
global cfgfile, xyzfile, ciffile
global freduce01
argv = sys.argv
# if len(argv) == 1:
# terminate(usage = usage)
xyzfile = getarg (1, xyzfile)
freduce01 = getintarg (2, freduce01)
header, ext = os.path.splitext(xyzfile)
filebody = os.path.basename(header)
xyzfile = filebody + '.xyz'
cfgfile = filebody + '.cfg'
ciffile = filebody + '.cif'
[ドキュメント]
def read_xyzfile(cfgfile, xyzfile):
"""
概要: 設定ファイルとXYZファイルから結晶構造データを読み込み、tkCrystalオブジェクトを生成します。
詳細説明:
まず、`cfgfile`からサンプル名と3つの格子ベクトルを読み込みます。
次に、`xyzfile`からサイト数と各原子サイトの元素名とカートン座標を読み込みます。
読み込んだ情報をもとに`tkCrystal`オブジェクトを構築し、
原子のカートン座標を分数座標に変換して`tkCrystal`オブジェクトに追加します。
`freduce01`フラグが真の場合、分数座標は[0, 1)の範囲に正規化されます。
:param cfgfile: str: 設定ファイル(.cfg)のパス。格子ベクトルやサンプル名を定義します。
:param xyzfile: str: XYZフォーマットの原子座標ファイル(.xyz)のパス。原子種とカートン座標を定義します。
:returns: tkCrystal: 読み込まれた結晶構造データを含むtkCrystalオブジェクト。
"""
cfg = tkFile(cfgfile, 'r')
if not cfg:
terminate("Error in read_xyzfile: Can not read [{}]".format(cfgfile), usage = usage)
line = cfg.ReadLine()
sample_name = cfg.ReadLine().strip()
print("sample name: [{}]".format(sample_name))
line = cfg.SkipTo("Defining vectors")
aij = np.empty([3, 3])
aij[0] = cfg.ReadLine().split()
aij[1] = cfg.ReadLine().split()
aij[2] = cfg.ReadLine().split()
cfg.Close()
for i in range(3):
for j in range(3):
aij[i][j] = pfloat(aij[i][j])
# print("")
# print("Lattice vectors:")
# for i in range(3):
# print(" {:16.12f} {:16.12f} {:16.12f}".format(*aij[i]))
xyz = tkFile(xyzfile, 'r')
if not xyz:
terminate("Error in read_xyzfile: Can not read [{}]".format(xyzfile), usage = usage)
nsites = pint(xyz.ReadLine())
print("nsites = ", nsites)
# blank line
# line = xyz.ReadLine()
site = []
idx = 0
for i in range(nsites):
idx += 1
line = xyz.ReadLine()
if not line:
break
ret = line.split()
# skip blank line
if ret is None or len(ret) < 4:
continue
name, xc, yc, zc = ret
xc = pfloat(xc)
yc = pfloat(yc)
zc = pfloat(zc)
# print("{:04d} {:2} ({:8.4f}, {:8.4f}, {:8.4f})".format(idx, name, xc, yc, zc))
site.append([name, xc, yc, zc])
xyz.Close()
print("")
print("Build Crystal object:")
cry = tkCrystal()
cry.SetSampleName(sample_name)
cry.SetCrystalName(sample_name)
cry.SetLatticeVectors(aij)
latt = cry.LatticeParameters()
for i in range(len(site)):
x, y, z = cry.CartesianToFractional(site[i][1], site[i][2], site[i][3])
if freduce01:
x, y, z = Reduce01(x), Reduce01(y), Reduce01(z)
# print("xyz {}:{}: {},{},{} => {},{},{}".format(i+1, site[i][0], site[i][1], site[i][2], site[i][3], x, y, z))
cry.AddAtomSite(name = site[i][0], pos = [x, y, z])
cry.ExpandCoordinates()
# cry.PrintInf()
return cry
[ドキュメント]
def xyz2cif():
"""
概要: XYZファイルと設定ファイルからCIFファイルを生成するメイン処理を実行します。
詳細説明:
グローバル変数`cfgfile`と`xyzfile`で指定されたファイルパスを使用して、
`read_xyzfile`関数を呼び出し、結晶構造データを含む`tkCrystal`オブジェクトを取得します。
取得した結晶情報を標準出力に表示した後、
グローバル変数`ciffile`で指定されたパスにCIFファイルを生成・保存します。
処理が完了すると、`terminate`関数を呼び出してスクリプトを終了します。
"""
global cfgfile, xyzfile
print("CFG file: {}".format(cfgfile))
print("XYZ file: {}".format(xyzfile))
print("")
print("Read [{}] and [{}]".format(cfgfile, xyzfile))
# if not tkutils.IsFile(infile):
# terminate("Error: Invalid infile [{}]".format(infile), usage = usage)
cry = read_xyzfile(cfgfile, xyzfile)
# Note: 'infile' in the original code's terminate message likely refers to cfgfile or xyzfile.
# Adhering to rule 1, the message is kept as is.
if not cry:
terminate("Error: Could not get crystal object from infile [{}]".format(cfgfile + " or " + xyzfile), usage = usage)
print("")
print("==============================================")
print(" Crystal inf")
print("==============================================")
cry.PrintInf()
print("")
print("Save to [{}]".format(ciffile))
cif = tkCIFData()
cif.CreateCIFFileFromCCrystal(cry, ciffile)
terminate(usage = usage)
[ドキュメント]
def main():
"""
概要: スクリプトのエントリーポイントです。
詳細説明:
コマンドライン引数を解析してグローバル変数を更新し(`updatevars`関数)、
その後、XYZファイルと設定ファイルからCIFファイルを生成する主要な処理(`xyz2cif`関数)を呼び出します。
"""
updatevars()
print("")
print("=============== Convert XYZ+CFG files to CIF file ============")
xyz2cif()
if __name__ == "__main__":
main()