def test_gulp(): # flake8: noqa from ase.calculators.gulp import GULP, Conditions from ase import Atoms import numpy as np cluster = Atoms(symbols='O4SiOSiO2SiO2SiO2SiOSiO2SiO3SiO3H8', pbc=np.array([False, False, False], dtype=bool), cell=np.array( [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]]), positions=np.array( [[-1.444348, -0.43209 , -2.054785], [-0.236947, 2.98731 , 1.200025], [ 3.060238, -1.05911 , 0.579909], [ 2.958277, -3.289076, 2.027579], [-0.522747, 0.847624, -2.47521 ], [-2.830486, -2.7236 , -2.020633], [-0.764328, -1.251141, 1.402431], [ 3.334801, 0.041643, -4.168601], [-1.35204 , -2.009562, 0.075892], [-1.454655, -1.985635, -1.554533], [ 0.85504 , 0.298129, -3.159972], [ 1.75833 , 1.256026, 0.690171], [ 2.376446, -0.239522, -2.881245], [ 1.806515, -4.484208, -2.686456], [-0.144193, -2.74503 , -2.177778], [ 0.167583, 1.582976, 0.47998 ], [-1.30716 , 1.796853, -3.542121], [ 1.441364, -3.072993, -1.958788], [-1.694171, -1.558913, 2.704219], [ 4.417516, 1.263796, 0.563573], [ 3.066366, 0.49743 , 0.071898], [-0.704497, 0.351869, 1.102318], [ 2.958884, 0.51505 , -1.556651], [ 1.73983 , -3.161794, -0.356577], [ 2.131519, -2.336982, 0.996026], [ 0.752313, -1.788039, 1.687183], [-0.142347, 1.685301, -1.12086 ], [ 2.32407 , -1.845905, -2.588202], [-2.571557, -1.937877, 2.604727], [ 2.556369, -4.551103, -3.2836 ], [ 3.032586, 0.591698, -4.896276], [-1.67818 , 2.640745, -3.27092 ], [ 5.145483, 0.775188, 0.95687 ], [-2.81059 , -3.4492 , -2.650319], [ 2.558023, -3.594544, 2.845928], [ 0.400993, 3.469148, 1.733289]])) c = Conditions(cluster) c.min_distance_rule('O', 'H', 'O2', 'H', 'O1') cluster.calc = GULP( keywords='opti conp phon noden distance molq compare angle nono', shel=['O1','O2'], conditions=c) print(cluster.get_potential_energy())
def GULPRelaxation(inputStr): ##for gulp to work. gulp folder must be in the same folder as the script environ["GULP_LIB"] = "\"" + getcwd() + "/Gulp_40/Libraries/\"" environ["ASE_GULP_COMMAND"] = "\"" + getcwd( ) + "/Gulp_40/Exe/gulp.exe\" < PREFIX.gin > PREFIX.got" ##takes string inputStr and turns it into stepNb, shouldRestartFromScratch listOfAtoms if len(inputStr) % 4 != 2: print("Args nb " + str(len(inputStr))) print(inputStr) print( "Not enough args. Args order : stepNb, shouldRestartFromScratch (0 or 1), \n atom list formatted as Name Xpos Ypos Zpos for each atom (example CO2 would be C 0 0 0 O 0 1 1 O 0 1 -1)" ) return "", False atomNames = [] atomXYZ = [] stepNb = int(inputStr[0]) shouldRestartFromScratch = int(inputStr[1]) #if restart from scratch, destroy previously known trajectory if (shouldRestartFromScratch == 1): my_file = Path('tmp.pckl') if my_file.is_file(): remove('tmp.pckl') #create Atoms object to optimize for i in range(0, math.floor(len(inputStr) / 4)): atomNames.append(inputStr[4 * i + 2]) atomXYZ.append((float(inputStr[4 * i + 3]), float(inputStr[4 * i + 4]), float(inputStr[4 * i + 5]))) atoms = Atoms(atomNames, positions=atomXYZ) c = Conditions(atoms) #attach calculator calc = GULP(keywords='conp', library="./Gulp_40/Libraries/reaxff.lib") atoms.calc = calc calc.set(keywords='conp opti') #optimize opt = calc.get_optimizer(atoms) opt.run(fmax=0.05) #io.write('../MoleculeLibrary/tmp.xyz', atoms, format='xyz') pos = atoms.get_positions() outStr = "" for i in range(0, len(atomNames)): outStr += atomNames[i] + " " outStr += str(pos[i][0]) + " " outStr += str(pos[i][1]) + " " outStr += str(pos[i][2]) + " " return outStr, True
[-0.144193, -2.74503, -2.177778], [0.167583, 1.582976, 0.47998], [-1.30716, 1.796853, -3.542121], [1.441364, -3.072993, -1.958788], [-1.694171, -1.558913, 2.704219], [4.417516, 1.263796, 0.563573], [3.066366, 0.49743, 0.071898], [-0.704497, 0.351869, 1.102318], [2.958884, 0.51505, -1.556651], [1.73983, -3.161794, -0.356577], [2.131519, -2.336982, 0.996026], [0.752313, -1.788039, 1.687183], [-0.142347, 1.685301, -1.12086], [2.32407, -1.845905, -2.588202], [-2.571557, -1.937877, 2.604727], [2.556369, -4.551103, -3.2836], [3.032586, 0.591698, -4.896276], [-1.67818, 2.640745, -3.27092], [5.145483, 0.775188, 0.95687], [-2.81059, -3.4492, -2.650319], [2.558023, -3.594544, 2.845928], [0.400993, 3.469148, 1.733289]])) c = Conditions(cluster) c.min_distance_rule('O', 'H', 'O2', 'H', 'O1') cluster.set_calculator( GULP(keywords='opti conp phon noden distance molq compare angle nono', shel=['O1', 'O2'], conditions=c)) print(cluster.get_potential_energy())
def multi_stage_gulp_calc(structure, num_calcs, gulp_files, main_keywords, additional_keywords, main_options, additional_options, max_gnorms, gulp_shells=[], gulp_library="", gulp_conditions=None, remove_vacancies=True): """ Run a GULP calculation that consists of many stages, which can involve different keywords and options. Parameters ---------- structure : ChemDASH structure The structure class containing ASE atoms object and properties. num_calcs : integer The number of GULP calculations to run gulp_files : string Name used for input and output files for each GULP calculation main_keywords : list List of GULP keywords. Default is "sing" for a single point energy calculation. additional_keywords : list List of extra GULP keywords for each calculation. Default is None main_options : list List of GULP options. Default is None additional_options : list List of extra GULP options for each calculation. Default is None max_gnorms : list List of maximum values of the final gnorm for each calculation. gulp_shells : dictionary, optional A dictionary with atom labels as keys and charges as values for each atomic species to have a shell attached. gulp_library : string, optional The library file containing the forcefield to be used in the calculation. gulp_conditions : ASE Conditions, optional The conditions used to determine the label given to particular atoms if the forcefield has different atom types. Returns ------- atoms : ase atoms The structure after the split calculation. result : string The result of the GULP calculation, either "converged", "unconverged", "gulp failure", or "timed out" energy : float Energy of the structure in eV/atom. outcome : string GULP outcome of the final stage of this calculation. calc_time : float Time taken for this GULP calculation. potentials : float Site potentials for each atom. derivs : float Magnitude of the derivatives of the potential for each atom. --------------------------------------------------------------------------- Paul Sharp 28/01/2021 """ assert len( gulp_files ) >= num_calcs, 'ERROR in gulp_calc.multi_stage_gulp_calc() -- number of GULP calculations is set to {0:d}, but only {1:d} filenames are provided.'.format( num_calcs, len(gulp_files)) assert len( additional_keywords ) >= num_calcs, 'ERROR in gulp_calc.multi_stage_gulp_calc() -- number of GULP calculations is set to {0:d}, but only {1:d} sets of additional keywords are provided.'.format( num_calcs, len(additional_keywords)) assert len( additional_options ) >= num_calcs, 'ERROR in gulp_calc.multi_stage_gulp_calc() -- number of GULP calculations is set to {0:d}, but only {1:d} sets of additional options are provided.'.format( num_calcs, len(additional_options)) gulp_start_time = time.time() failed_outcome = "Too many failed attempts to optimise " calc_files = { "input": "", "output": "", "restart": "", } structure.potentials = [] structure.derivs = [] # Strip out vacancies from the structure if remove_vacancies: vacancy_positions = determine_vacancy_positions(structure.atoms.copy()) del structure.atoms[[ atom.index for atom in structure.atoms if atom.symbol == "X" ]] if structure.labels is not None: gulp_conditions = Conditions(structure.atoms) gulp_conditions.atoms_labels = structure.labels for i in range(0, num_calcs): composite_keys = (main_keywords + " " + additional_keywords[i]).split() gulp_keywords = " ".join( sorted(set(composite_keys), key=composite_keys.index)) composite_options = main_options + additional_options[i] composite_options.append("dump " + gulp_files[i] + ".res") gulp_options = list( sorted(set(composite_options), key=composite_options.index)) structure.atoms, structure.energy, gnorm, result, calc_files = run_gulp( structure.atoms, gulp_files[i], calc_files["restart"], gulp_keywords, gulp_options, gulp_shells, gulp_library, gulp_conditions) # Continue only if the calculation was successfully performed without timing out if result == "timed out" or result == "gulp failure": outcome = result if os.path.isfile(calc_files["output"]): outcome = read_outcome(calc_files["output"]) if outcome == "": outcome = "Bash timeout" break outcome = read_outcome(calc_files["output"]) # We abandon the calculation if the outcome "Too many failed attempts to optimise" occurs, # the energy and gradient norm have blown up such that they are not representable as floats, # or the max gnorm for this calculation, if provided, is exceeded. # if (outcome == failed_outcome) or (not check_float(structureenergy)) or (not check_float(gnorm)): if (not check_float(structure.energy)) or (not check_float(gnorm)): result = "unconverged" break if isinstance(max_gnorms[i], float) and isinstance(gnorm, float): if gnorm > max_gnorms[i]: result = "unconverged" break # Update atoms object before continuing # This is necessary because of a bug in ASE, where it only updates atomic positions if they are given in cartesian coordinates try: structure.atoms, structure.energy = update_atoms_from_restart_file( structure.atoms, structure.energy, calc_files["restart"]) except ValueError: result = "unconverged" break else: if os.path.isfile(calc_files["output"]): if any(pot_keyword in gulp_keywords for pot_keyword in ["pot", "potential"]): structure.potentials, structure.derivs = read_potentials( calc_files["output"]) if check_convergence(calc_files["output"], gulp_keywords): result = "converged" else: result = "unconverged" else: outcome = "" result = "unconverged" # Replace the vacancies in the atoms object if remove_vacancies: structure.atoms = populate_points_with_vacancies( structure.atoms, vacancy_positions) structure.volume = structure.atoms.get_volume() calc_time = time.time() - gulp_start_time return structure, result, outcome, calc_time