Source code for AtomicAI.descriptors.generate_force_descriptor

# -*- coding: utf-8 -*-
import warnings
warnings.filterwarnings("ignore")
from AtomicAI.descriptors.force_descriptor_functions import *
import argparse, math, os, random, copy, sys
from time import time
import numpy as np
from AtomicAI.tools.select_snapshots import select_snapshots

FP_TYPES = ['BP2b', 'Split2b3b_ss']


def _parse_force_args():
    parser = argparse.ArgumentParser(
        description='Generate force descriptors from a trajectory.',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='Available fingerprint types:\n  ' + '\n  '.join(FP_TYPES),
    )
    parser.add_argument('input_file', help='Trajectory file (.xyz)')
    parser.add_argument(
        '--fp-type', '-f',
        choices=FP_TYPES,
        default='Split2b3b_ss',
        dest='fp_type',
        help='Force fingerprint type (default: Split2b3b_ss)',
    )
    parser.add_argument(
        '--rc', '-r',
        type=float,
        default=10.5,
        help='Cutoff radius in Angstrom for 2-body and 3-body terms (default: 10.5)',
    )
    parser.add_argument(
        '--n2b',
        type=int,
        default=20,
        help='Number of 2-body eta functions (default: 20)',
    )
    parser.add_argument(
        '--n3b',
        type=int,
        default=10,
        help='Number of 3-body eta functions (default: 10)',
    )
    return parser.parse_args()


[docs] def generate_force_descriptors(): args = _parse_force_args() out_directory = './descriptors/' os.makedirs(out_directory, exist_ok=True) selected_frames, _ = select_snapshots() force_descriptor(selected_frames, fp_type=args.fp_type, rc=args.rc, n2b=args.n2b, n3b=args.n3b) return
[docs] def writeout_fp(Xv,Fv,atomic_symbols, nfout): if len(Fv)==len(Xv): with open(nfout,mode='w') as nf: lines = [] for i in range(len(Fv)): tmp_lst = copy.deepcopy(Xv[i]) tmp_lst.append(Fv[i]) V_str_list = ["{0: >30.16e}".format(v) for v in tmp_lst] lines.append("".join(V_str_list) +' '+atomic_symbols[i]+'\n') nf.writelines(lines) nf.close() else: print('Sizes of Fv and Xv are not same!\n') exit() return None
# make random vector for force projection
[docs] def prepare_vforce(data_num_rand): vforce=[] for _ in range(data_num_rand): zr = random.uniform(0.0, 1.0) * 2 - 1 pr = random.uniform(0.0, 1.0) * 2 * pi vx = math.sqrt(1 - zr ** 2) * math.cos(pr) vy = math.sqrt(1 - zr ** 2) * math.sin(pr) vz = zr vforce.append([vx,vy,vz]) return vforce
[docs] def force_descriptor(selected_frames, fp_type='Split2b3b_ss', rc=10.5, n2b=20, n3b=10): """Compute force descriptors for all atoms in selected_frames. Parameters ---------- fp_type : str Fingerprint type — 'BP2b' (2-body Behler-Parrinello) or 'Split2b3b_ss' (split 2+3-body). rc : float Cutoff radius in Angstrom applied to both 2-body and 3-body terms. n2b : int Number of 2-body eta decay functions. n3b : int Number of 3-body eta decay functions. """ if fp_type not in FP_TYPES: print(f'Unknown fingerprint type {fp_type!r}. Choose from: {FP_TYPES}') sys.exit(1) parameters = { 'Rc2b': rc, 'Rc3b': rc, 'Reta': rc, '2b': [-3.0, 1.0, n2b, 2.5], '3b': [-3.0, 1.0, n3b, rc, 3, 10], 'split3b': [-3.0, 1.0, n3b], } seed_ran = 16835 fp_flag = fp_type main_start = time() nfout = './descriptors/force_descriptors.dat' #nf_all_list[nfi] if os.path.isfile(nfout): os.remove(nfout) # calculate the features with the atomic environment and G1G2 parameters #print('Now calculating the features...') count_vtime = 0.0 count_mtime = 0.0 # deal with input parameters param_dict, nfp = set_param_dict(parameters, fp_flag) # initialize random seed seed_rand = seed_ran random.seed(seed_rand) # random selected atom matrix with elements of (n_frame, i_atom) before_time = time() num_frames = len(selected_frames) selected_frames = selected_frames print("Selected no. of frames are", len(selected_frames)) data_num = 0 for frame_i in range(0, num_frames): data_num += len(selected_frames[frame_i].numbers) data_num += len(selected_frames[frame_i].numbers) print ("Total data: ", data_num) #choice_random = prepare_choice_normal(data_num, frames) # get random choices from the setting #data_num = 10000 vforce = prepare_vforce(data_num) #random_choice_time = time() - before_time diter = 1000 # collect results of fingerprint Xv, Fv, atomic_pairs = [], [], [] before_time = time() ID_vector = 0 diter_local = 0 for i_frame in range(0, num_frames): atoms_local = selected_frames[i_frame] cell = atoms_local.cell numbers = atoms_local.numbers symbols = atoms_local.symbols positions = atoms_local.positions atomcforces = atoms_local.arrays.get('forces') natoms = len(numbers) if ID_vector >= diter_local: print('Process : %d' % ID_vector) diter_local += diter # symbols_ = np.array(list(symbols)) sorted_symbols_ = list(set(symbols_)) for i in range(natoms): before_time = time() # prepare force Forcex = atomcforces[i] v = np.array(vforce[ID_vector]) # get random vector Fvtmp = np.dot(Forcex, v) # Fv : atomic force projection along the random vector # prepare feature: fingerprint value(descriptor value) before_time = time() Xvtmp = [] for target_atom in sorted_symbols_: #base_atom = symbols_[i] positions_ = positions[symbols_ == target_atom] vij0 = positions_ - positions[i] xij0, yij0, zij0 = vij0[:, 0], vij0[:, 1], vij0[:, 2] Rc2b = param_dict.get('Rc2b') Rc3b = param_dict.get('Rc3b') Rc = max(Rc2b, Rc3b) m_x, m_y, m_z = define_mirror_cubic(positions[i], cell, Rc) if (fp_flag == 'BP2b'): Xvtmp.extend(make_BP2b(xij0,yij0,zij0,m_x,m_y,m_z, v, param_dict)) elif fp_flag == 'Split2b3b_ss': Xvtmp.extend(make_Split2b3b_ss(xij0,yij0,zij0,m_x,m_y,m_z, v, param_dict)) else: print('Wrong V_flag!\n') exit() count_vtime = count_vtime + time() - before_time Xv.append(Xvtmp) Fv.append(Fvtmp) atomic_pairs.append(f'{symbols_[i]}') # update id of force vector ID_vector += 1 writeout_fp(Xv, Fv, atomic_pairs, nfout=nfout) print("prepare matrix cost: {0:.2f} 秒".format(time() - before_time)) print("read matrix cost: {0:.2f} 秒".format(count_mtime)) print("make_V cost: {0:.2f} 秒".format(count_vtime)) #fp_time = time() - main_start print("fingerprint cost:{0:.2f} 秒".format(time() - main_start)) print("Total cost:{0:.2f} 秒".format(time() - main_start)) return