機能のサブセクション
Logging
2023 July 10
CrySPY 1.2.0からPython標準ライブラリのloggingを採用.
CrySPYのログは画面とファイル(log_cryspy
and err_cryspy
)の両方に出力される.
- log –> screen and
log_cryspy
- error and warning –> screen and
err_cryspy
ログの例:
[2023-07-10 18:40:54,389][cryspy_init][INFO]
Start CrySPY 1.2.0
[2023-07-10 18:40:54,389][cryspy_init][INFO] # ---------- Read input file, cryspy.in
[2023-07-10 18:40:54,390][read_input][INFO] Save input data in cryspy.stat
[2023-07-10 18:40:54,391][cryspy_init][INFO] # ---------- Initial structure generation
[2023-07-10 18:40:54,391][cryspy_init][INFO] Number of MPI processes: 1
[2023-07-10 18:40:54,391][gen_init_struc][INFO] # ------ mindist
[2023-07-10 18:40:54,395][struc_util][INFO] Cu - Cu: 1.32
[2023-07-10 18:40:54,395][gen_init_struc][INFO] # ------ generate structures
[2023-07-10 18:40:54,481][gen_pyxtal][INFO] Structure ID 0 was generated. Space group: 1 --> 1 P1
[2023-07-10 18:40:54,493][gen_pyxtal][INFO] Structure ID 1 was generated. Space group: 28 --> 28 Pma2
[2023-07-10 18:40:54,498][gen_pyxtal][INFO] Structure ID 2 was generated. Space group: 29 --> 29 Pca2_1
[2023-07-10 18:40:54,704][gen_pyxtal][INFO] Structure ID 3 was generated. Space group: 137 --> 137 P4_2/nmc
[2023-07-10 18:40:54,725][gen_pyxtal][INFO] Structure ID 4 was generated. Space group: 212 --> 214 I4_132
[2023-07-10 18:40:54,800][cryspy_init][INFO] Elapsed time for structure generation: 0:00:00.408367
CrySPYをバックグラウンドジョブとして実行する場合や,自動スクリプト(repeat_cryspy)を使う場合などで,画面に出力させたくないときは下記のように-n
オプションをつけて実行する.
cryspy -n
バックアップ
CrySPYはシンプルなバックアップ機能を備えている. バックアップの対象は以下のファイル:
- cryspy.in
- cryspy.stat
- log_cryspy
- err_cryspy
- calc_in/*
- data/*
- ext/*
work/* は含まれいないので注意.
- (v1.1.0以降) 上記ファイルが日付と時間で名前づけられたディレクトリにコピーされる.以前のバックアップは自動的には削除されない.
- (v1.0.0) バックアップは1世代分のみであり,それより古いものは削除される.
自動バックアップ
自動的にバックアップされるタイミングは次の通り:
- 次の選択に移るとき(BO, LAQA)か世代交代を行うとき (EA)
- 構造を追加するとき
手動バックアップ
手動でバックアップを行いたい場合は,-b
または --backup
オプションをつけて次のようにcryspyを実行する:
cryspy -b
このコマンドは通常の実行とは異なり,バックアップだけを行います.
クリーン
CrySPYはシンプルなクリーン機能を備えている. 初めからやり直したい時に便利となる. 以下のファイルがクリーン(実際はファイルを移動するだけ)される.
- cryspy.stat
- log_cryspy
- err_cryspy
- lock_cryspy
- data/*
- work/*
- ext/*
- tmp_calc_FP/*
- tmp_gen_struc/*
クリーンする場合は-c
または --clean
オプションをつけてcryspyを実行する:
$ ls
calc_in cryspy.in cryspy.stat data err_cryspy log_cryspy
$ cryspy -c
Are you sure you want to clean the data? 'yes' or 'no' [y/n]: y
$ ls
calc_in cryspy.in trash
$ ls trash
20230318_100728
calc_in/*
と cryspy.in
以外のファイルがtrashの中の日付と時間で名前づけられたディレクトリに移動します.
必要なければ手動で削除してください.
Restriction on interatomic distances
2024年4月23日 更新
構造生成時に原子間距離の制限を行うことができる. 下記はA-B 2元系における[structure]セクションの最低原子間距離の設定例.
[structure]
natot = 8
atype = A B
nat = 4 4
mindist_1 = 2.0 1.8
mindist_2 = 1.8 1.5
原子A-A,B-BおよびA-B間の最低原子間距離がそれぞれ2.0,1.8および1.5 Åに設定されている. 原子間距離がこの値よりも小さい構造は自動的に棄却される.
3元系では mindist_1
,mindist_2
およびmindist_3
が必要になる.
mindistの行列は対称行列でなければならない.
Example: Na8Cl8
Without mindist
cryspy.in
[basic]
algo = RS
calc_code = VASP
tot_struc = 5
nstage = 2
njob = 2
jobcmd = qsub
jobfile = job_cryspy
[structure]
natot = 16
atype = Na Cl
nat = 8 8
[VASP]
kppvol = 40 80
[option]
log_cryspy
[2024-04-23 13:46:28,598][cryspy_init][INFO]
Start CrySPY 1.2.3
[2024-04-23 13:46:28,598][cryspy_init][INFO] # ---------- Read input file, cryspy.in
[2024-04-23 13:46:28,598][read_input][INFO] Save input data in cryspy.stat
[2024-04-23 13:46:28,599][gen_init_struc][INFO] # ------ mindist
[2024-04-23 13:46:28,601][struc_util][INFO] Na - Na: 1.66
[2024-04-23 13:46:28,602][struc_util][INFO] Na - Cl: 1.3399999999999999
[2024-04-23 13:46:28,602][struc_util][INFO] Cl - Cl: 1.02
...
PyXtalのデフォルト設定では,上の図のように原子同士が近すぎる場合があるので,mindistを設定することをすすめる. DFT計算もやりやすくなるであろう.
With mindist
cryspy.in
[basic]
algo = RS
calc_code = VASP
tot_struc = 5
nstage = 2
njob = 2
jobcmd = qsub
jobfile = job_cryspy
[structure]
natot = 16
atype = Na Cl
nat = 8 8
mindist_1 = 2.5 1.5
mindist_2 = 1.5 2.5
[VASP]
kppvol = 40 80
[option]
log_cryspy
[2024-04-23 14:06:21,955][cryspy_init][INFO]
Start CrySPY 1.2.3
[2024-04-23 14:06:21,955][cryspy_init][INFO] # ---------- Read input file, cryspy.in
[2024-04-23 14:06:21,956][read_input][INFO] Save input data in cryspy.stat
[2024-04-23 14:06:21,956][gen_init_struc][INFO] # ------ mindist
[2024-04-23 14:06:21,956][struc_util][INFO] Na - Na: 2.5
[2024-04-23 14:06:21,956][struc_util][INFO] Na - Cl: 1.5
[2024-04-23 14:06:21,956][struc_util][INFO] Cl - Cl: 2.5
イオン結晶のような場合には,カチオン同士,アニオン同士が離れるような設定をしておくと良い.
ジョブファイルのCrySPY_ID
CrySPYのジョブファイルで,“CrySPY_ID"という文字列は自動的に構造IDに置換される.
PBSやSLURMなどのジョブスケジューラーを使う時,ジョブ名に構造IDを使うと便利である.
例えばPBSでは, #PBS -N Si_CrySPY_ID
が#PBS -N Si_10
に置き換わる
大抵の場合,ジョブ名は数字から始められないことが多いので,Si_
のように英字から始めておくと良い.
#!/bin/sh
#$ -cwd
#$ -V -S /bin/bash
####$ -V -S /bin/zsh
#$ -N Si8_CrySPY_ID
#$ -pe smp 8
####$ -q ibis1.q
####$ -q ibis2.q
mpirun -np $NSLOTS pw.x -nk 4 -nb 2 < pwscf.in > pwscf.out
if [ -e "CRASH" ]; then
exit 1
fi
sed -i -e '3 s/^.*$/done/' stat_job
MPI並列化を用いた構造生成
2023/10/21 update
CrySPYのバージョン1.1.0(1.2.3以上の利用を推奨)からは,MPIを用いたランダム構造生成が可能になった. MPIを使うにはPython環境にmpi4pyをインストールする必要がある. 当然,計算に利用するワークステーション等にMPIライブラリ(Open MPI,Intel MPI,MPICHなど)も必要である.
MPIを使うのに下記が必要
- CrySPY
1.1.01.2.3 or later - mpi4py
- MPI library (Open MPI, Intel MPI, MPICH, etc.)
1.1.0 <= CrySPY <=1.2.2ではバグがあった.
MPIを使ったジョブをbashやzshで実行するとき(e.g., jobcmd = zsh
, jobfile = job_cryspy
),MPIのジョブが流れない.
qsubやsbatchでジョブスケジューラーを使う場合は問題ない。
このバグはバージョン1.2.3で修正.
下の図にSi8原子1000構造をランダムに生成するのにかかった時間とMPIプロセス数の関係を示す.下記のセッティングを使った.
[basic]
algo = RS
calc_code = soiap
tot_struc = 1000
nstage = 1
njob = 2
jobcmd = zsh
jobfile = job_cryspy
[structure]
natot = 8
atype = Si
nat = 8
mindist_1 = 2.2
mindset_1 = 2.2
のように厳し目に設定して,わざと時間がかかるようにしてある.
それぞれのプロセス数において10回ずつ実行して,平均を線で結んでいる.
Run
mpiexec -n 4 cryspy -p
Enthalpy
2023/10/18
Requirements:
- CrySPY 1.2.2 or later
- VASP or QE
高圧化における構造探索を行う時に, エネルギーの代わりにエンタルピーを使うことができる. VASPとQE以外はまだ未対応.
cryspy_rslt
やcryspy_rslt_energy_asc
のE_eV_atom
の箇所がエンタルピー(eV/atom)に変わる.
下記は40 GPaにおけるSr4O4の構造探索の結果の例.
高圧下ではCsCl型構造(ID 5)がNaCl型構造よりも安定になっている.
Spg_num Spg_sym Spg_num_opt Spg_sym_opt E_eV_atom Magmom Opt
5 26 Pmc2_1 221 Pm-3m -2.276790 NaN done
6 225 Fm-3m 225 Fm-3m -2.244800 NaN done
1 101 P4_2cm 107 I4mm -2.181115 NaN done
4 123 P4/mmm 123 P4/mmm -2.034509 NaN not_yet
3 20 C222_1 63 Cmcm -0.686541 NaN done
2 75 P4 75 P4 -0.008713 NaN not_yet
9 51 Pmma 47 Pmmm 0.096430 NaN done
8 65 Cmmm 123 P4/mmm 1.099657 NaN done
0 187 P-6m2 187 P-6m2 1.292124 NaN done
7 53 Pmna 53 Pmna 5.153504 NaN not_yet
VASP
CrySPYではOSZICAR
からエネルギー(エンタルピー)を読んでいる.
これはPSTRESS
がINCAR_x
で以下のようにセットされると自動的にエンタルピーに変わる:
PSTRESS = 400
cryspy.in
では特に何もする必要はない.
energy_step_flag
のオプションも使用可能でエンタルピーを読み込める.
Example: CrySPY Utility > Examples > vasp_Sr4O4_RS_pv_term
QE
エンタルピーを読むためにはcryspy.in
のQEセクションでpv_term = True
をつける:
[QE]
qe_infile = pwscf.in
qe_outfile = pwscf.out
kppvol = 40 80
pv_term = True
QEの入力ファイルでもpress
の設定を忘れずに:
&cell
press = 400
/
QEではenergy_step_flag
オプションでエンタルピーを読むことにまだ未対応.
As library
2024 May 31
Requirements:
- CrySPY 1.3.0 or later
Cryspy can be used as a library to generate random structures or structures by evolutionary algoritym. The jupyter notebook is available in CrySPY utility > notebook > as_library.
Random structure generation
####
#### when you change set_logger(), you need to restart the kernel
####
from cryspy.util.utility import set_logger # optional
set_logger() # optional
#set_logger(noprint=True, logfile='log_cryspy', errfile='err_cryspy') # write log and err messages to files
from cryspy.RS.gen_struc_RS import gen_pyxtal
nstruc = 10
atype = ('Na', 'Cl')
nat = (4, 4)
mindist = ((2.0, 1.5),
(1.5, 2.0))
spgnum = 'all'
init_struc_data = gen_pyxtal.gen_struc(
nstruc=nstruc,
atype=atype,
nat=nat,
mindist=mindist,
spgnum=spgnum,
)
You can get init_struc_data (dict: {ID: pymatgen Strcture, …})
Structure generation by evolutionary algorithm
Situation: parent A (, parent B) –> child
Prepare two (one) parent structures as pymatgen Structure object.
In this example, just use the results of RS for Cu4Au4 (see, CrySPY utility > notebook > as_library).
import pickle
with open('./Cu4Au4_sample/opt_struc_data.pkl', 'rb') as f:
opt_struc_data = pickle.load(f)
Crossover
from cryspy.EA.gen_struc_EA import crossover
# you can change parent_A and parent_B
parent_A = opt_struc_data[0]
parent_B = opt_struc_data[1]
atype = ('Cu', 'Au')
nat = (4, 4)
mindist = ((1.5, 1.5),
(1.5, 1.5))
child = crossover.gen_child(
atype=atype,
nat=nat,
mindist=mindist,
parent_A=parent_A,
parent_B=parent_B,
)
# child: pymatgen Structure
Permutation
from cryspy.EA.gen_struc_EA import permutation
# you can change parent_A
parent_A = opt_struc_data[0]
atype = ('Cu', 'Au')
nat = (4, 4)
mindist = ((1.5, 1.5),
(1.5, 1.5))
ntimes = 1 # number of times to perform permutatio
child = permutation.gen_child(
atype=atype,
mindist=mindist,
parent_A=parent_A,
ntimes=ntimes,
)
# child: pymatgen Structure
Strain
from cryspy.EA.gen_struc_EA import strain
atype = ('Cu', 'Au')
nat = (4, 4)
mindist = ((1.5, 1.5),
(1.5, 1.5))
sigma_st = 0.05 # standard deviation of strain
child = strain.gen_child(
atype=atype,
mindist=mindist,
parent_A=parent_A,
sigma_st=sigma_st,
)
Situation: parent group, fitness –> children
Data set
Prepare structure and fitness (energy) data as dict. The key is structure ID. In this example, just use the results of RS for Cu4Au4 (see, CrySPY utility > notebook > as_library)..
e.g.
struc_data = {0: (pymatgen Structure), 1: (pymatgen Structure), …}
fitness = {0: 0.019632287242441926, 1: -0.005437509701440302, …}
import pickle
with open('./Cu4Au4_sample/opt_struc_data.pkl', 'rb') as f:
opt_struc_data = pickle.load(f)
with open('./Cu4Au4_sample/rslt_data.pkl', 'rb') as f:
rslt_data = pickle.load(f)
struc_data = opt_struc_data # dict
fitness = rslt_data['E_eV_atom'].to_dict() # you may include None or np.nan for values
Survival of the fittest
from cryspy.EA.survival import survival_fittest
from cryspy.EA.gen_struc_EA.select_parents import SelectParents
from cryspy.EA.gen_struc_EA import crossover, permutation, strain
n_fittest = 5 # number of survivors
ranking, _, _ = survival_fittest(
fitness=fitness,
struc_data=struc_data,
elite_struc=None,
elite_fitness=None,
n_fittest=n_fittest,
fit_reverse=False,
emax_ea=None,
emin_ea=None,
)
# ranking <-- e.g. [2, 1, 0, 7, 9] without structure duplicaiton
Select parents class
sp = SelectParents(ranking) # after set_xxx, we can use sp.get_parents(n_parent)
sp.set_tournament(t_size=2)
Crossover
atype = ('Cu', 'Au')
nat = (4, 4)
mindist = ((1.5, 1.5),
(1.5, 1.5))
n_crsov = 5 # number of structures to be generated by crossover
#id_start = len(init_struc_data) # next Structure ID
id_start = 10
co_children, co_parents, co_operation = crossover.gen_crossover(
atype=atype,
nat=nat,
mindist=mindist,
struc_data=struc_data,
sp=sp,
n_crsov=n_crsov,
id_start=id_start,
)
# co_children <-- dict {ID: pymatgen Structure, ID: pymatgen Structure, ...}
# co_parents <-- e.g. {10: (2, 7), 11: (2, 1), 12: (2, 1), 13: (0, 2), 14: (2, 1)}
# co_operation <-- e.g. {10: 'crossover', 11: 'crossover', ...}
Permutation
n_perm = 5 # number of structures to be generated by permutation
#id_start = len(init_struc_data) + n_crsov # next Structure ID
id_start = 15
ntimes = 1 # number of times to perform permutation
pm_children, pm_parents, pm_operation = permutation.gen_permutation(
atype=atype,
mindist=mindist,
struc_data=struc_data,
sp=sp,
n_perm=n_perm,
id_start=id_start,
ntimes=ntimes,
)
# pm_children <-- dict {ID: pymatgen Structure, ID: pymatgen Structure, ...}
# pm_parents <-- e.g. {15: (2,), 16: (1,), 17: (2,), 18: (1,), 19: (1,)}
# pm_operation <-- e.g. {15: 'permutaion', 16: 'permutation', ...}
Strain
n_strain = 5 # number of structures to be generated by strain
#id_start = len(init_struc_data) + n_crsov + n_perm # next Structure ID
id_start = 20
sigma_st = 0.05 # standard deviation of strain
st_children, st_parents, st_operation = strain.gen_strain(
atype=atype,
mindist=mindist,
struc_data=struc_data,
sp=sp,
n_strain=n_strain,
id_start=id_start,
sigma_st=sigma_st,
)
# st_children <-- dict {ID: pymatgen Structure, ID: pymatgen Structure, ...}
# st_parents <-- e.g. {20: (1,), 21: (2,), 22: (0,), 23: (2,), 24: (2,)}
# st_operation <-- e.g. {20: 'strain', 21: 'strain', ...}