機能のサブセクション

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_1mindist_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
...

fig_mindist fig_mindist

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.0 1.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回ずつ実行して,平均を線で結んでいる.

fig_MPI fig_MPI

Run

mpiexec -n 4 cryspy -p

Enthalpy

2023/10/18

情報

Requirements:

  • CrySPY 1.2.2 or later
  • VASP or QE

高圧化における構造探索を行う時に, エネルギーの代わりにエンタルピーを使うことができる. VASPとQE以外はまだ未対応.

cryspy_rsltcryspy_rslt_energy_ascE_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からエネルギー(エンタルピー)を読んでいる. これはPSTRESSINCAR_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オプションでエンタルピーを読むことにまだ未対応.

Example: CrySPY Utility > Examples > qe_Sr4O4_RS_pv_term

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', ...}