Source code for ffio

"""This module provide methods to handle reading and writing forcefields"""
import numpy as np
import time
from ezff.utils.reaxff import reax_forcefield

[docs]def read_variable_bounds(filename, verbose=False): """Read permissible lower and upper bounds for decision variables used in forcefields optimization :param filename: Name of text file listing bounds for each decision variable that must be optimized :type filename: str :param verbose: Print all variables read-in :type verbose: bool """ variable_bounds = {} while True: # Force-read the parameter bounds file. This will loop until something is read-in. This is required if multiple ranks access the same file at the same time time.sleep(np.random.rand()) with open(filename, 'r') as variable_bounds_file: for line in variable_bounds_file: items = line.strip().split() key, values = items[0], items[1:] if key[0] == '_': variable_bounds[key] = list(map(int, values)) else: variable_bounds[key] = list(map(float, values)) if not variable_bounds == {}: break if verbose: allkeys = '' for key in variable_bounds: allkeys += str(key) + ', ' print('Keys: ' + allkeys[:-2] + ' read from ' + filename) return variable_bounds
[docs]def read_forcefield_template(template_filename): """Read-in the forcefield template. The template is constructed from a functional forcefield file by replacing all optimizable numerical values with variable names enclosed within dual angled brackets << and >>. :param template_filename: Name of the forcefield template file to be read-in :type template_filename: str """ while True: # Force-read the template forcefield. This will loop until something is read-in. This is required if multiple ranks read the same file at the same time time.sleep(np.random.rand()) with open(template_filename) as forcefield_template_file: template_string = forcefield_template_file.read() if len(template_string) > 0: break return template_string
[docs]def generate_forcefield(template_string, parameters, FFtype = None, outfile = None, MD = 'GULP'): """Generate a new forcefield from the template by replacing variables with numerical values :param template_string: Text of the forcefield template :type template_string: str :param parameters: Numerical value of all decision variables in the form of variable:value pairs :type parameters: dict :param FFtype: Type of forcefield being optimized. (e.g. reaxff, sw, lj, etc.) :type FFtype: string :param outfile: Optional filename to write out the forcefield :type outfile: string :param MD: MD Engine used for parameterization :type MD: string """ replaced_keys = '' for key, ranges in parameters.items(): pattern = '<<' + key + '>>' while pattern in template_string: template_string = template_string.replace(pattern, '%12.6f' % ranges) # Special handling for certain forcefield types if FFtype is not None: if (FFtype.strip().upper() == 'REAX') or (FFtype.strip().upper() == 'REAXFF'): if MD == 'GULP': template_string = reax_forcefield(filestring=template_string).write_gulp_library() elif MD == 'LAMMPS': template_string = reax_forcefield(filestring=template_string).write_formatted_forcefields() if outfile is not None: with open(outfile, 'w') as new_forcefield: new_forcefield.write(template_string) return else: return template_string