def testBondFilter(self): """ Test the molecular formula creator, which is basically a RDKit feature, but used in KinBot for postprocessing """ smi = 'CCC=CCC' motif = ['C', 'C', 'C', 'C'] bondpattern = [2, 'X', 'X'] exp = 2 st_pt = StationaryPoint(smi, 0, 1, smiles=smi) st_pt.characterize() bond = st_pt.bond natom = st_pt.natom atom = st_pt.atom # do not use any equivalencies eqv = [[k] for k in range(natom)] hits = find_motif.start_motif(motif, natom, bond, atom, -1, eqv) count = 0 for hit in hits: if find_motif.bondfilter(hit, bond, bondpattern) == 0: count += 1 warn = 'Unexpected number of motif hits for ' warn += '{}, expected {}, calculated {}'.format(smi, exp, count) self.assertEqual(exp, count, warn)
def testAll(self): with open('symmetry_data.json') as f: data = json.load(f) messages = [ 'Expected external symmetry: {}, calculated: {}', 'Expected internal symmetry: {}, calculated: {}', 'Expected number of single events symmetry: {}, calculated: {}', ] for name in data: par = Parameters() qc = QuantumChemistry(par) mol = StationaryPoint(name, 0, 1, smiles=name) mol.characterize() kinbot.symmetry.calculate_symmetry(mol) sigma_int = 1 for row in mol.sigma_int: for at in row: sigma_int *= at calc = [mol.sigma_ext, sigma_int, mol.nopt] for i in range(3): cal = calc[i] exp = data[name]['expected_values'][i] self.assertEqual(exp, cal, name + ': ' + messages[i].format(exp, cal))
def main(): smi = '[CH2]CC' mult = 1 charge = 0 mol = StationaryPoint('well0', charge, mult, smiles=smi) mol.characterize() reactions = generate_all_product_bond_matrices(mol)
def irc2stationary_pt(self): """ Read the irc files There are three possible scenarios: 1. One of the ircs leads the initial well and the other to another well or bimolecular product 2. Neither of the ircs lead to the inital well, transition state structure is not the one kinbot was looking for 3. Both the ircs lead to the initial well, KinBot found either an identical reaction or the ts is not correct """ instance_name = self.rxn.instance_name directions = ['Forward', 'Reverse'] ini_well_hits = 0 prod_hit = -1 st_pts = [-1, -1] for i, direction in enumerate(directions): irc_name = '{}_IRC_{}_prod'.format(instance_name, direction[0]) err, geom = self.rxn.qc.get_qc_geom(irc_name, self.rxn.species.natom, allow_error=1) if err == -1: return 0 if self.problem_in_geom(geom): # this happens seldomly that all the atoms are # very close to one another (problem in Gaussian) logging.info('\tProblem with product geometry for {}'.format( instance_name)) return 0 temp = StationaryPoint(irc_name, self.rxn.species.charge, self.rxn.species.mult, atom=self.rxn.species.atom, geom=geom) temp.calc_chemid() st_pts[i] = temp if temp.chemid == self.rxn.species.chemid: ini_well_hits += 1 else: prod_hit = i if ini_well_hits == 0: logging.info( '\tNeither IRC leads to the well for {}'.format(instance_name)) return 0 elif ini_well_hits == 2: logging.info( '\tBoth IRCs lead to the well, identical reaction found: {}'. format(instance_name)) return 0 else: # ircs OK: well and product found logging.info('\tIRCs successful for {}'.format(instance_name)) return st_pts[prod_hit]
def testNumberOfHitsWithStartAtom(self): """ Test the molecular formula creator, which is basically a RDKit feature, but used in KinBot for postprocessing """ # the data contains the smiles as key and as value: # 1. the multiplicity # 2. start atom # 3. the motif which will be searched for # 4. the expected number of hits of the motif data = { 'CCCO[O]': [2, 0, ['C', 'C', 'C', 'O', 'O'], 1], 'C=C': [1, 0, ['X', 'X', 'X'], 2], 'S=S': [1, 0, ['S', 'S'], 1], } for smi in data: mult = data[smi][0] start = data[smi][1] motif = data[smi][2] exp = data[smi][3] st_pt = StationaryPoint(smi, 0, mult, smiles=smi) st_pt.characterize() bond = st_pt.bond natom = st_pt.natom atom = st_pt.atom # do not use any equivalencies eqv = [[k] for k in range(natom)] hits = find_motif.start_motif(motif, natom, bond, atom, start, eqv) cal = len(hits) warn = 'Unexpected number of motif hits for ' warn += '{}, expected {}, calculated {}'.format(smi, exp, cal) self.assertEqual(exp, cal, warn)
def testDihedralChangeHeptyl(self): """ The generation of ring conformers requires qc calculations and is therefore slow! """ if not os.path.exists('conf/'): os.mkdir('conf/') par = Parameters() qc = QuantumChemistry(par) smi = '[CH2]CCCCC' mol = StationaryPoint(smi, 0, 2, smiles=smi) mol.characterize() changes = [ [0, 3, 4, 5, 25.], [3, 4, 5, 6, 25.], [4, 5, 6, 7, 25.], [5, 6, 7, 16, 25.], ] name = 'hexyl_dihedral' success, new_geom = kinbot.modify_geom.modify_coordinates( mol, name, mol.geom, changes, mol.bond, write_files=self.write_files)
def test_conformer(self, conf): """ Test whether a conformer has the same bond matrix as the original structure. Returns the conformer object and -1 if not yet finished, 0 if same, and 1 if not. """ add = '' if self.semi_emp: add = 'semi_emp_' job = self.get_job_name(conf, add=add) status, geom = self.qc.get_qc_geom(job, self.species.natom) if status == 1: # still running return np.zeros((self.species.natom, 3)), -1 elif status == -1: # conformer search failed return np.zeros((self.species.natom, 3)), 1 else: # check if all the bond lenghts are withing 10% of the original bond lengths temp = StationaryPoint('temp', self.species.charge, self.species.mult, atom=self.species.atom, geom=geom) temp.bond_mx() if geometry.equal_geom(self.species, temp, 0.10): return geom, 0 else: return np.zeros((self.species.natom, 3)), 1
def testAll(self): data = { 'CC': [1, 0], 'CCC': [2, 0], 'CCCC': [3, 1], 'C=C': [0, 0], 'C=CC': [1, 0], 'C=C[CH2]': [0, 0], 'CC=C[CH2]': [1, 0], 'C1CCCC1': [0, 0], 'CO': [1, 0], 'C=CO': [1, 1], } for name in data: par = Parameters() qc = QuantumChemistry(par) mol = StationaryPoint(name, 0, 1, smiles=name) mol.characterize() hir_exp = data[name][0] conf_exp = data[name][1] hir_calc = len(mol.dihed) conf_calc = len(mol.conf_dihed) self.assertEqual( hir_exp, hir_calc, name + ': HIR, expected: {}, calculated: {}'.format( hir_exp, hir_calc)) self.assertEqual( conf_exp, conf_calc, name + ': CONF, expected: {}, calculated: {}'.format( conf_exp, conf_calc))
def test_hir(self): for rotor in range(len(self.species.dihed)): for ai in range(self.nrotation): success = None if self.hir_status[rotor][ai] == -1: if self.species.wellorts: job = 'hir/' + self.species.name + '_hir_' + str( rotor) + '_' + str(ai).zfill(2) else: job = 'hir/' + str( self.species.chemid) + '_hir_' + str( rotor) + '_' + str(ai).zfill(2) err, geom = self.qc.get_qc_geom(job, self.species.natom) if err == 1: # still running continue elif err == -1: # failed success = -1 else: # check if all the bond lenghts are within # 15% or the original bond lengths temp = StationaryPoint('temp', self.species.charge, self.species.mult, atom=self.species.atom, geom=geom) temp.bond_mx() if geometry.equal_geom(self.species, temp, 0.15): err, energy = self.qc.get_qc_energy(job) if ai == 0: success = 1 # cut off barriers above 20 kcal/mol to prevent the Fourier fit to oscillate elif (energy - self.hir_energies[rotor][0] ) < 20. / constants.AUtoKCAL: success = 1 else: success = -1 else: success = -1 if success == 1: err, energy = self.qc.get_qc_energy(job) self.hir_status[rotor][ai] = 0 self.hir_energies[rotor][ai] = energy self.hir_geoms[rotor][ai] = geom elif success == -1: logging.warning( "Hindered rotor optimization not successful for {}". format(job)) self.hir_status[rotor][ai] = 1 self.hir_energies[rotor][ai] = -1 self.hir_geoms[rotor][ai] = geom return 0
def testAll(self): with open('multimolecular_data.json') as f: data = json.load(f) for name in data: print name par = Parameters() qc = QuantumChemistry(par) structure = data[name]['structure'] mol = StationaryPoint(name,0,1,structure = structure) mol.characterize() mols = mol.start_multi_molecular() calculated = len(mols) expected = data[name]['expected_value'] self.assertEqual(calculated,expected, name + ': expected: {}, calculated: {}'.format(expected,calculated))
def create_geometries(self): """ Cut the species in two parts and save the geometries of both parts into new stationary point objects """ # copy the reactant stationary point atom = copy.deepcopy(self.species.atom) geom = copy.deepcopy(self.species.geom) temp = StationaryPoint('temp', self.species.charge, self.species.mult, atom=atom, geom=geom) temp.characterize() # set the bond order of the breaking bond to 0 temp.bond[self.bond[0]][self.bond[1]] = 0 temp.bond[self.bond[1]][self.bond[0]] = 0 self.products, maps = temp.start_multi_molecular()
def testAll(self): data = {"C1=CC=CC=C1":2, "C1=CC=C(C)C=C1":2, "C=C[CH2]":2, "C=C=C":1, "C#C[CH2]":2, "S=S":1, "O=S=C":1, "O=S(C)[CH2]":3, "C1CC=CC=C1":1 } for name in data: par = Parameters() qc = QuantumChemistry(par) mol = StationaryPoint(name,0,1,smiles = name) mol.characterize() cal = len(mol.bonds) exp = data[name] self.assertEqual(exp ,cal ,name + ': expected: {}, calculated: {}'.format(exp,cal))
def testBondChangeEthane(self): """ The generation of a longer C-C bond in ethane """ if not os.path.exists('conf/'): os.mkdir('conf/') par = Parameters() qc = QuantumChemistry(par) smi = 'CC' mol = StationaryPoint(smi, 0, 1, smiles=smi) mol.characterize() changes = [ [0, 1, 1.8], ] name = 'ethane_bond_length_test' success, new_geom = kinbot.modify_geom.modify_coordinates( mol, name, mol.geom, changes, mol.bond, write_files=self.write_files)
def test_ring_conformer(self, index): """ Test whether a conformer has the same bond matrix as the original structure. Returns the conformer object and -1 if not yet finished, 0 if same, and 1 if not. """ job = self.get_job_name(index, cyc=1) status, geom = self.qc.get_qc_geom(job, self.species.natom) if status == 1: # still running return np.zeros((self.species.natom, 3)), -1 elif status == -1: # conformer search failed logging.debug( 'Conformer search failed for scan point {}'.format(job)) return np.zeros((self.species.natom, 3)), 1 else: if self.start_ring_conformer_search(index, geom): logging.debug( 'Running the next dihedral for conformer {}'.format(job)) return geom, -1 else: # check if all the bond lenghts are withing 10% or the original bond lengths temp = StationaryPoint('temp', self.species.charge, self.species.mult, atom=self.species.atom, geom=geom) temp.bond_mx() if geometry.equal_geom(self.species, temp, 0.10): logging.debug( 'Successfullly finished conformer {}'.format(job)) return geom, 0 else: logging.debug( 'Conformer too far from original structure {}'.format( job)) return np.zeros((self.species.natom, 3)), 1
def main(): try: input_file = sys.argv[1] except IndexError: print('To use KinBot, supply one argument being the input file!') sys.exit(-1) # print the license message to the console print(license_message.message) # initialize the parameters for this run masterpar = Parameters(input_file) par = masterpar.par input_file = masterpar.input_file # set up the logging environment if par['verbose']: logging.basicConfig(filename='kinbot.log', level=logging.DEBUG) else: logging.basicConfig(filename='kinbot.log', level=logging.INFO) # write the license message to the log file logging.info(license_message.message) logging.info('Input parameters') for param in par: logging.info('{} {}'.format(param, par[param])) # time stamp of the KinBot start logging.info('Starting KinBot at {}'.format(datetime.datetime.now())) # Make the necessary directories if not os.path.exists('perm'): os.makedirs('perm') if not os.path.exists('scratch'): os.makedirs('scratch') if not os.path.exists(par['single_point_qc']): os.mkdir(par['single_point_qc']) if par['rotor_scan'] == 1: if not os.path.exists('hir'): os.mkdir('hir') if not os.path.exists('hir_profiles'): os.mkdir('hir_profiles') if not os.path.exists('perm/hir/'): os.makedirs('perm/hir/') if par['conformer_search'] == 1: if not os.path.exists('conf'): os.mkdir('conf') if not os.path.exists('perm/conf'): os.makedirs('perm/conf') if not os.path.exists('me'): os.mkdir('me') # initialize the reactant well0 = StationaryPoint('well0', par['charge'], par['mult'], smiles=par['smiles'], structure=par['structure']) well0.short_name = 'w1' # write the initial reactant geometry to a file for visualization geom_out = open('geometry.xyz', 'w') geom_out.write('{}\n\n'.format(well0.natom)) for i, at in enumerate(well0.atom): x, y, z = well0.geom[i] geom_out.write('{} {:.6f} {:.6f} {:.6f}\n'.format(at, x, y, z)) geom_out.write('\n\n') geom_out.close() # characterize the initial reactant well0.characterize(dimer=par['dimer']) well0.name = str(well0.chemid) start_name = well0.name # initialize the qc instance qc = QuantumChemistry(par) # only run filecopying if PES is turned on # if par['pes']: # check if this well was calcualted before in another directory # this flag indicates that this kinbot run # should wait for the information from another # kinbot run to become available and copy the necessary information # wait_for_well = 1 # while wait_for_well: # wait_for_well = filecopying.copy_from_database_folder(well0.chemid, well0.chemid, qc) # if wait_for_well: # time.sleep(1) # start the initial optimization of the reactant logging.info('Starting optimization of intial well') qc.qc_opt(well0, well0.geom) err, well0.geom = qc.get_qc_geom(str(well0.chemid) + '_well', well0.natom, wait=1) err, well0.freq = qc.get_qc_freq(str(well0.chemid) + '_well', well0.natom, wait=1) if err < 0: logging.error('Error with initial structure optimization.') return if any(well0.freq[i] <= 0 for i in range(len(well0.freq))): logging.error('Found imaginary frequency for initial structure.') return # characterize again and look for differences well0.characterize(dimer=par['dimer']) well0.name = str(well0.chemid) if well0.name != start_name: logging.error( 'The first well optimized to a structure different from the input.' ) return # do an MP2 optimization of the reactant, # to compare some scan barrier heigths to if par['families'] == ['all'] or \ 'birad_recombination_R' in par['families'] or \ 'r12_cycloaddition' in par['families'] or \ 'r14_birad_scission' in par['families'] or \ 'R_Addition_MultipleBond' in par['families'] or \ (par['skip_families'] != ['none'] and \ ('birad_recombination_R' not in par['skip_families'] or \ 'r12_cycloaddition' not in par['skip_families'] or \ 'r14_birad_scission' not in par['skip_families'] or \ 'R_Addition_MultipleBond' not in par['skip_families'])) or \ par['reaction_search'] == 0: logging.info('Starting MP2 optimization of intial well') qc.qc_opt(well0, well0.geom, mp2=1) err, geom = qc.get_qc_geom( str(well0.chemid) + '_well_mp2', well0.natom, 1) # comparison for barrierless scan if par['barrierless_saddle']: logging.info( 'Optimization of intial well for barrierless at {}/{}'.format( par['barrierless_saddle_method'], par['barrierless_saddle_basis'])) qc.qc_opt(well0, well0.geom, bls=1) err, geom = qc.get_qc_geom( str(well0.chemid) + '_well_bls', well0.natom, 1) # characterize again and look for differences well0.characterize(dimer=par['dimer']) well0.name = str(well0.chemid) err, well0.energy = qc.get_qc_energy(str(well0.chemid) + '_well', 1) err, well0.zpe = qc.get_qc_zpe(str(well0.chemid) + '_well', 1) well_opt = Optimize(well0, par, qc, wait=1) well_opt.do_optimization() if well_opt.shigh == -999: logging.error( 'Error with high level optimization of initial structure.') return if par['pes']: filecopying.copy_to_database_folder(well0.chemid, well0.chemid, qc) if par['reaction_search'] == 1: logging.info('Starting reaction searches of intial well') rf = ReactionFinder(well0, par, qc) rf.find_reactions() rg = ReactionGenerator(well0, par, qc, input_file) rg.generate() if par['homolytic_scissions'] == 1: logging.info('Starting the search for homolytic scission products') well0.homolytic_scissions = HomolyticScissions(well0, par, qc) well0.homolytic_scissions.find_homolytic_scissions() if par['me'] > 0: # it will be 2 for kinbots when the mess file is needed but not run mess = MESS(par, well0) mess.write_input(qc) if par['me'] == 1: logging.info('Starting Master Equation calculations') if par['me_code'] == 'mess': mess.run() postprocess.createSummaryFile(well0, qc, par) postprocess.createPESViewerInput(well0, qc, par) postprocess.creatMLInput(well0, qc, par) logging.info('Finished KinBot at {}'.format(datetime.datetime.now())) print("Done!")
def main(): try: input_file = sys.argv[1] except IndexError: print( 'To use the pes script, supply one argument being the input file!') sys.exit(-1) # TODO: write information about the arguments # change this to nice argument parsers with # dashes etc. no_kinbot = 0 task = 'all' names = [] if len(sys.argv) > 2: if sys.argv[2] == 'no-kinbot': no_kinbot = 1 if len(sys.argv) > 3: # possible tasks are: # 1. all: This is the default showing all pathways # 2. lowestpath: show the lowest path between the species # corresponding to the names # 3. allpaths: show all paths between the species # corresponding to the names # 4. wells: show all reactions of one wells # corresponding to the names task = sys.argv[3] names = sys.argv[4:] # print the license message to the console print(license_message.message) # initialize the parameters par = Parameters(input_file) # set up the logging environment logging.basicConfig(filename='pes.log', level=logging.INFO) logging.info(license_message.message) msg = 'Starting the PES search at {}'.format(datetime.datetime.now()) logging.info(msg) if par.par['pes'] and par.par['specific_reaction']: logging.error('Specific reaction cannot be searched in PES mode.') return well0 = StationaryPoint('well0', par.par['charge'], par.par['mult'], smiles=par.par['smiles'], structure=par.par['structure']) well0.characterize(dimer=par.par['dimer']) write_input(par, well0, par.par['barrier_threshold'], os.getcwd()) # add the initial well to the chemids with open('chemids', 'w') as f: f.write(str(well0.chemid) + '\n') # create a directory for the L3 single point calculations # directory has the name of the code, e.g., molpro try: os.mkdir(par.par['single_point_qc']) except OSError: pass #List of chemids to skip KinBot submissions for. skipChemids = par.par['skip_chemids'] # maximum number of kinbot jobs that run simultaneously max_running = par.par['simultaneous_kinbot'] # jobs that are running running = [] # jobs that are finished finished = [] # list of all jobs jobs = [] # dict of the pid's for all jobs pids = {} a = 0 b = 0 c = 0 while 1: j = len(jobs) if j != a: logging.info('{0} {1} {2}'.format("len(jobs): ", j, "\n")) a = j with open('chemids', 'r') as f: jobs = f.read().split('\n') jobs = [ji for ji in jobs if ji != ''] if len(jobs) > j: logging.info('\tPicked up new jobs: ' + ' '.join(jobs[j:])) k = len(running) l = len(finished) if b != k: logging.info('{0} {1} {2}'.format("len(running): ", len(running), "\n")) b = k if c != l: logging.info('{0} {1} {2}'.format("len(finished): ", len(finished), "\n")) c = l if len(finished) == len(jobs): time.sleep(2) if len(finished) == len(jobs): break while (len(running) < max_running and len(running) + len(finished) < len(jobs)): # start a new job job = jobs[len(running) + len(finished)] kb = 1 logging.info('Job: {}'.format(job)) if 'none' in skipChemids: logging.info('No KinBot runs to be skipped') else: if job in skipChemids: kb = 0 logging.info('kb: {}'.format(kb)) if kb == 1: pid = 0 if not no_kinbot: pid = submit_job(job, par) # kinbot is submitted here else: get_wells(job) pids[job] = pid t = datetime.datetime.now() logging.info('\tStarted job {} at {}'.format(job, t)) running.append(job) elif kb == 0: logging.info('Skipping Kinbot for {}'.format(job)) finished.append(job) else: logging.info('kb value not 0 or 1') # check if a thread is done for job in running: if not check_status(job, pids[job]): t = datetime.datetime.now() logging.info('\tFinished job {} at {}'.format(job, t)) finished.append(job) if not no_kinbot: # write a temporary pes file # remove old xval and im_extent files try: os.remove('{}_xval.txt'.format(par.par['title'])) except OSError: pass try: os.remove('{}_im_extent.txt'.format(par.par['title'])) except OSError: pass # remove the finished threads for job in finished: if job in running: running.remove(job) if not no_kinbot: # write a summary of what is running and finished summary_lines = [] summary_lines.append('Total\t\t{}'.format(len(jobs))) summary_lines.append('Running\t\t{}'.format(len(running))) summary_lines.append('Finished\t{}'.format(len(finished))) summary_lines.append('') summary_lines.append('Running:') for job in running: summary_lines.append('\t{}'.format(job)) summary_lines.append('') summary_lines.append('Finished:') for job in finished: summary_lines.append('\t{}'.format(job)) with open('pes_summary.txt', 'w') as f: f.write('\n'.join(summary_lines)) time.sleep(1) # delete skipped jobs from the jobs before sending to postprocess for skip in skipChemids: try: jobs.pop(jobs.index(skip)) except ValueError: pass postprocess(par, jobs, task, names) # make molpro inputs for all keys above # place submission script in the directory for offline submission # read in the molpro energies for the keys in the above three dicts # for key in newdict.keys(): # print(key) # if all energies are there # do something like postprocess, but with new energies # postprocess_L3(saddle_zpe, well_zpe, prod_zpe, saddle_energy, well_energy, prod_energyi, conn) # Notify user the search is done logging.info('PES search done!') print('PES search done!')
def create_mess_input(par, wells, products, reactions, barrierless, well_energies, prod_energies, parent): """ When calculating a full pes, the files from the separate wells are read and concatenated into one file Two things per file need to be updated 1. the names of all the wells, bimolecular products and ts's 2. all the zpe corrected energies """ # generate short names for all startionary points well_short, pr_short, fr_short, ts_short, nobar_short = create_short_names( wells, products, reactions, barrierless) # list of the strings to write to mess input file s = [] #create mess0 label for mess header well0 = StationaryPoint('well0', par.par['charge'], par.par['mult'], smiles=par.par['smiles'], structure=par.par['structure']) well0.characterize(dimer=par.par['dimer']) """ Create the header block for MESS """ # Read the header template header_file = pkg_resources.resource_filename('tpl', 'mess_header.tpl') with open(header_file) as f: tpl = f.read() header = tpl.format( TemperatureList=' '.join( [str(ti) for ti in par.par['TemperatureList']]), PressureList=' '.join([str(pi) for pi in par.par['PressureList']]), EnergyStepOverTemperature=par.par['EnergyStepOverTemperature'], ExcessEnergyOverTemperature=par.par['ExcessEnergyOverTemperature'], ModelEnergyLimit=par.par['ModelEnergyLimit'], CalculationMethod=par.par['CalculationMethod'], ChemicalEigenvalueMax=par.par['ChemicalEigenvalueMax'], Reactant=well_short[wells[0]], EnergyRelaxationFactor=par.par['EnergyRelaxationFactor'], EnergyRelaxationPower=par.par['EnergyRelaxationPower'], EnergyRelaxationExponentCutoff=par. par['EnergyRelaxationExponentCutoff'], e_coll=constants.epsilon[par.par['collider']], s_coll=constants.sigma[par.par['collider']], m_coll=constants.mass[par.par['collider']], e_well=par.par['epsilon'], s_well=par.par['sigma'], m_well=well0.mass, ) # write the wells s.append('######################') s.append('# WELLS') s.append('######################') for well in wells: name = well_short[well] + ' ! ' + well energy = well_energies[well] with open(parent[well] + '/' + well + '.mess') as f: s.append(f.read().format(name=name, zeroenergy=energy)) s.append('!****************************************') # write the products s.append('######################') s.append('# BIMOLECULAR PRODUCTS') s.append('######################') a = 0 for prod in products: name = pr_short[prod] + ' ! ' + prod energy = prod_energies[prod] fr_names = {} for fr in prod.split('_'): key = 'fr_name_{}'.format(fr) value = fr_short[fr] + ' ! ' + fr fr_names[key] = value with open(parent[prod] + '/' + prod + '.mess') as f: s.append(f.read().format(name=name, ground_energy=energy, **fr_names)) a = a + 1 s.append('!****************************************') # write the barrier s.append('######################') s.append('# BARRIERS') s.append('######################') for rxn in reactions: name = [ts_short[rxn[1]]] name.append(well_short[rxn[0]]) if len(rxn[2]) == 1: name.append(well_short[rxn[2][0]]) else: name.append(pr_short['_'.join(sorted(rxn[2]))]) name.append('!') name.append(rxn[1]) energy = rxn[3] try: with open(rxn[0] + '/' + rxn[1] + '.mess') as f: s.append(f.read().format(name=' '.join(name), zeroenergy=energy)) s.append('!****************************************') except: logging.info(('{0} {1} {2} {3}'.format(rxn[0], "/", rxn[1], ".mess not found\n"))) # add last end statement s.append('!****************************************') for rxn in barrierless: name = [nobar_short] name.append(rxn[0]) if len(rxn[2]) > 1: name.append(pr_short['_'.join(sorted(rxn[2]))]) else: name.append(rxn[2]) energy = rxn[3] s.append('! BARRIERLESS REACTIONS !') try: with open(rxn[0] + '/' + rxn[2] + '.mess') as f: s.append(f.read().format(name=' '.join(name), zeroenergy=energy)) s.append('!****************************************') except: logging.info('{0} {1} {2} {3}'.format(rxn[0], "/", rxn[2], ".mess not found\n")) # add last end statement s.append('!****************************************') s.append('End ! end kinetics\n') if not os.path.exists('me'): os.mkdir('me') # write everything to a file with open('me/mess.inp', 'w') as f: f.write(header) f.write('\n'.join(s)) dummy = StationaryPoint('dummy', par.par['charge'], par.par['mult'], smiles=par.par['smiles'], structure=par.par['structure']) well0.characterize(dimer=par.par['dimer'])
def generate(self): """ Creates the input for each reaction, runs them, and tests for success. If successful, it creates the barrier and product objects. It also then does the conformational search, and finally, the hindered rotor scans. To make the code the most efficient, all of these happen in parallel, in a sense that the jobs are not waiting for each other. E.g., one reaction can still be in the stage of TS search, while the other can be already at the hindered rotor scan. This way, all cores are occupied efficiently. The switching between the various stages are done via the reac_ts_done variable. 0: initiate the TS search 1: check barrier height and errors in TS, and initiates normal mode displacement test, start the irc calculations 2: submit product optimization 3: submit the frequency calculation 4: do the optimization of the ts and the products 5: follow up on the optimizations 6: finalize calculations, check for wrong number of negative frequencies If at any times the calculation fails, reac_ts_done is set to -999. If all steps are successful, reac_ts_done is set to -1. """ deleted = [] if len(self.species.reac_inst) > 0: alldone = 1 else: alldone = 0 # status to see of kinbot needs to wait for the product optimizations # from another kinbot run, to avoid duplication of calculations products_waiting_status = [[] for i in self.species.reac_inst] count = 0 for i in self.species.reac_inst: count = count + 1 frag_unique = [] while alldone: for index, instance in enumerate(self.species.reac_inst): obj = self.species.reac_obj[index] # START REACTION SEARCH if self.species.reac_ts_done[ index] == 0 and self.species.reac_step[index] == 0: # verify after restart if search has failed in previous kinbot run status = self.qc.check_qc(obj.instance_name) if status == 'error' or status == 'killed': logging.info( '\tRxn search failed (error or killed) for {}'. format(obj.instance_name)) self.species.reac_ts_done[index] = -999 if self.species.reac_type[ index] == 'hom_sci' and self.species.reac_ts_done[ index] == 0: # no matter what, set to 2 # somewhat messy manipulation to force the new bond matrix for hom_sci obj.products = copy.deepcopy(obj.species) obj.products.bonds = copy.deepcopy( obj.species.bond) # plural/non plural! obj.products.bonds[obj.instance[0]][ obj.instance[1]] = 0 # delete bond obj.products.bonds[obj.instance[1]][ obj.instance[0]] = 0 # delete bond obj.products.bond[obj.instance[0]][ obj.instance[1]] = 0 # delete bond obj.products.bond[obj.instance[1]][ obj.instance[0]] = 0 # delete bond obj.product_bonds = copy.deepcopy( obj.species.bonds[0]) # the first resonance structure obj.product_bonds[obj.instance[0]][ obj.instance[1]] = 0 # delete bond obj.product_bonds[obj.instance[1]][ obj.instance[0]] = 0 # delete bond self.species.reac_ts_done[index] = 2 if self.species.reac_ts_done[ index] == 0: # ts search is ongoing if obj.scan == 0: # don't do a scan of a bond if self.species.reac_step[index] == obj.max_step + 1: status, freq = self.qc.get_qc_freq( obj.instance_name, self.species.natom) if status == 0 and freq[0] < 0. and freq[1] > 0.: self.species.reac_ts_done[index] = 1 elif status == 0 and freq[0] > 0.: logging.info( '\tRxn search failed for {}, no imaginary freq.' .format(obj.instance_name)) self.species.reac_ts_done[index] = -999 elif status == 0 and freq[1] < 0.: logging.info( '\tRxn search failed for {}, more than one imaginary freq.' .format(obj.instance_name)) self.species.reac_ts_done[index] = -999 elif status == -1: logging.info( '\tRxn search failed for {}'.format( obj.instance_name)) self.species.reac_ts_done[index] = -999 else: self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par['qc_command']) else: # do a bond scan if self.species.reac_step[ index] == self.par['scan_step'] + 1: status, freq = self.qc.get_qc_freq( obj.instance_name, self.species.natom) if status == 0 and freq[0] < 0. and freq[1] > 0.: self.species.reac_ts_done[index] = 1 elif status == 0 and freq[0] > 0.: logging.info( '\tRxn search failed for {}, no imaginary freq.' .format(obj.instance_name)) self.species.reac_ts_done[index] = -999 elif status == 0 and freq[1] < 0.: logging.info( '\tRxn search failed for {}, more than one imaginary freq.' .format(obj.instance_name)) self.species.reac_ts_done[index] = -999 elif status == -1: logging.info( '\tRxn search using scan failed for {} in TS optimization stage.' .format(obj.instance_name)) self.species.reac_ts_done[index] = -999 else: if self.species.reac_step[index] == 0: self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par['qc_command']) elif self.species.reac_step[index] < self.par[ 'scan_step']: status = self.qc.check_qc(obj.instance_name) if status == 'error' or status == 'killed': logging.info( '\tRxn search using scan failed for {} in step {}' .format(obj.instance_name, self.species.reac_step[index])) self.species.reac_ts_done[index] = -999 else: err, energy = self.qc.get_qc_energy( obj.instance_name) if err == 0: self.species.reac_scan_energy[ index].append(energy) # need at least 3 points for a maximum if len(self.species. reac_scan_energy[index]) >= 3: ediff = np.diff( self.species. reac_scan_energy[index]) if ediff[-1] < 0 and ediff[ -2] > 0: # max self.species.reac_step[ index] = self.par[ 'scan_step'] # ending the scan if len(ediff) >= 3: if 10. * ( ediff[-3] / ediff[-2] ) < ( ediff[-2] / ediff[-1] ): # sudden change in slope self.species.reac_step[ index] = self.par[ 'scan_step'] # ending the scan logging.info( '\tCurrent raw scan energy for {}: {} Hartree.' .format( obj.instance_name, self.species. reac_scan_energy[index][-1])) # scan continues, and if reached scan_step, then goes for full optimization self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par['qc_command']) else: # the last step was reached, and no max or inflection was found logging.info( '\tRxn search using scan failed for {}, no saddle guess found.' .format(obj.instance_name)) db = connect('{}/kinbot.db'.format( os.getcwd())) rows = db.select(name=obj.instance_name) for row in self.reversed_iterator(rows): row.data['status'] = 'error' break # only write error to the last calculation self.species.reac_ts_done[index] = -999 elif self.species.reac_ts_done[index] == 1: status = self.qc.check_qc(obj.instance_name) if status == 'running': continue elif status == 'error': logging.info( '\tRxn search failed (gaussian error) for {}'. format(obj.instance_name)) self.species.reac_ts_done[index] = -999 else: # check the barrier height: ts_energy = self.qc.get_qc_energy(obj.instance_name)[1] ts_zpe = self.qc.get_qc_zpe(obj.instance_name)[1] if self.species.reac_type[ index] == 'R_Addition_MultipleBond': ending = 'well_mp2' elif self.species.reac_type[ index] == 'barrierless_saddle': ending = 'well_bls' else: ending = 'well' sp_energy = self.qc.get_qc_energy('{}_{}'.format( str(self.species.chemid), ending))[1] sp_zpe = self.qc.get_qc_zpe('{}_{}'.format( str(self.species.chemid), ending))[1] try: barrier = (ts_energy + ts_zpe - sp_energy - sp_zpe) * constants.AUtoKCAL except TypeError: logging.error( f'Faulty calculations, check or delete files for {obj.instance_name}.' ) sys.exit(-1) if barrier > self.par['barrier_threshold']: logging.info( '\tRxn barrier too high ({0:.2f} kcal/mol) for {1}' .format(barrier, obj.instance_name)) self.species.reac_ts_done[index] = -999 else: obj.irc = IRC( obj, self.par ) # TODO: this doesn't seem like a good design irc_status = obj.irc.check_irc() if 0 in irc_status: logging.info( '\tRxn barrier is {0:.2f} kcal/mol for {1}' .format(barrier, obj.instance_name)) # No IRC started yet, start the IRC now logging.info( '\tStarting IRC calculations for {}'. format(obj.instance_name)) obj.irc.do_irc_calculations() elif irc_status[0] == 'running' or irc_status[ 1] == 'running': continue else: # IRC's have successfully finished, have an error or were killed, in any case # read the geometries and try to make products out of them # verify which of the ircs leads back to the reactant, if any prod = obj.irc.irc2stationary_pt() if prod == 0: logging.info( '\t\tNo product found for {}'.format( obj.instance_name)) self.species.reac_ts_done[index] = -999 else: obj.products = prod obj.product_bonds = prod.bond self.species.reac_ts_done[index] = 2 elif self.species.reac_ts_done[index] == 2: if len(products_waiting_status[index]) == 0: # identify bimolecular products and wells fragments, maps = obj.products.start_multi_molecular() obj.products = [] a = [] for frag in fragments: a.append(frag) if len(frag_unique) == 0: frag_unique.append(frag) elif len(frag_unique) > 0: new = 1 for fragb in frag_unique: if frag.chemid == fragb.chemid: e, geom2 = self.qc.get_qc_geom( str(fragb.chemid) + '_well', fragb.natom) if e == 0: a.pop() frag = fragb a.append(frag) new = 0 break if new: frag_unique.append(frag) obj.products_final = [] for frag in a: self.qc.qc_opt(frag, frag.geom) e, geom2 = self.qc.get_qc_geom( str(frag.chemid) + '_well', frag.natom) obj.products_final.append(frag) # check products make sure they are the same for i, st_pt_i in enumerate(obj.products_final): for j, st_pt_j in enumerate(obj.products_final): if st_pt_i.chemid == st_pt_j.chemid and i < j: obj.products_final[j] = obj.products_final[ i] # print products generated by IRC products = [] for i, st_pt in enumerate(obj.products_final): products.append(st_pt.chemid) products.extend([' ', ' ', ' ']) logging.info( '\tReaction {} leads to products {} {} {}'.format( obj.instance_name, products[0], products[1], products[2])) for i, st_pt in enumerate(obj.products_final): chemid = st_pt.chemid e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: logging.info( '\tProduct optimization failed for {}, product {}' .format(obj.instance_name, st_pt.chemid)) self.species.reac_ts_done[index] = -999 err = -1 elif e != 0: err = -1 else: e2, st_pt.energy = self.qc.get_qc_energy( str(st_pt.chemid) + '_well') e2, st_pt.zpe = self.qc.get_qc_zpe( str(st_pt.chemid) + '_well') st_pt.characterize( dimer=0 ) # not allowed to use the dimer option here if chemid != st_pt.chemid: obj.products_final.pop(i) newfrags, newmaps = st_pt.start_multi_molecular( ) # newfrags is list of stpt obj products_waiting_status[index] = [ 0 for frag in newfrags ] frag_chemid = [] for i, newfr in enumerate(newfrags): newfr.characterize(dimer=0) for prod in frag_unique: if newfr.chemid == prod.chemid: newfrags.pop(i) newfr = prod j = i - 1 newfrags.insert(j, newfr) j = i - 1 obj.products_final.insert(j, newfr) self.qc.qc_opt(newfr, newfr.geom, 0) frag_chemid.append(newfr.chemid) if len(frag_chemid) == 1: frag_chemid.append(" ") for i, frag in enumerate(newfrags): products_waiting_status[index][i] = 1 logging.info( '\ta) Product optimized to other structure for {}' ', product {} to {} {}'.format( obj.instance_name, chemid, frag_chemid[0], frag_chemid[1])) obj.products = [] for prod in obj.products_final: obj.products.append(prod) obj.products_final = [] if all([pi == 1 for pi in products_waiting_status[index]]): self.species.reac_ts_done[index] = 3 elif self.species.reac_ts_done[index] == 3: # wait for the optimization to finish # if two st_pt are the same in the products, we make them exactly identical otherwise # the different ordering of the atoms causes the chemid of the second to be seemingly wrong for i, st_pt_i in enumerate(obj.products): for j, st_pt_j in enumerate(obj.products): if st_pt_i.chemid == st_pt_j.chemid and i < j: obj.products[j] = obj.products[i] err = 0 for st_pt in obj.products: chemid = st_pt.chemid e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: logging.info( '\tProduct optimization failed for {}, product {}' .format(obj.instance_name, st_pt.chemid)) self.species.reac_ts_done[index] = -999 err = -1 elif e != 0: err = -1 else: e2, st_pt.energy = self.qc.get_qc_energy( str(st_pt.chemid) + '_well') e2, st_pt.zpe = self.qc.get_qc_zpe( str(st_pt.chemid) + '_well') st_pt.characterize( dimer=0 ) # not allowed to use the dimer option here if chemid != st_pt.chemid: # product was optimized to another structure, give warning but don't remove reaction logging.info( '\tb) Product optimized to other structure for {}' ', product {} to {}'.format( obj.instance_name, chemid, st_pt.chemid)) e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: err = -1 if err == 0: self.species.reac_ts_done[index] = 4 elif self.species.reac_ts_done[index] == 4: # Do the TS and product optimization # make a stationary point object of the ts bond_mx = np.zeros( (self.species.natom, self.species.natom), dtype=int) for i in range(self.species.natom): for j in range(self.species.natom): bond_mx[i][j] = max(self.species.bond[i][j], obj.product_bonds[i][j]) if self.species.reac_type[index] != 'hom_sci': err, geom = self.qc.get_qc_geom( obj.instance_name, self.species.natom) ts = StationaryPoint(obj.instance_name, self.species.charge, self.species.mult, atom=self.species.atom, geom=geom, wellorts=1) err, ts.energy = self.qc.get_qc_energy( obj.instance_name) err, ts.zpe = self.qc.get_qc_zpe( obj.instance_name) # NEW STOPS HERE err, ts.freq = self.qc.get_qc_freq( obj.instance_name, self.species.natom) ts.distance_mx() ts.bond = bond_mx ts.find_cycle() ts.find_conf_dihedral() obj.ts = ts # do the ts optimization obj.ts_opt = Optimize(obj.ts, self.par, self.qc) obj.ts_opt.do_optimization() else: obj.ts = copy.deepcopy( obj.species ) # the TS will be for now the species itself obj.ts.wellorts = 1 # do the products optimizations for st_pt in obj.products: # do the products optimizations # check for products of other reactions that are the same as this product # in the case such products are found, use the same Optimize object for both for i, inst_i in enumerate(self.species.reac_inst): new = 1 if not i == index: obj_i = self.species.reac_obj[i] if self.species.reac_ts_done[i] > 3: for j, st_pt_i in enumerate( obj_i.products): if st_pt_i.chemid == st_pt.chemid: if len(obj_i.prod_opt) > j: prod_opt = obj_i.prod_opt[j] new = 0 break if new: prod_opt = Optimize(st_pt, self.par, self.qc) prod_opt.do_optimization() obj.prod_opt.append(prod_opt) for st_pt in obj.products: # section where comparing products in same reaction occurs if len(obj.prod_opt) > 0: for j, st_pt_opt in enumerate(obj.prod_opt): if st_pt.chemid == st_pt_opt.species.chemid: if len(obj.prod_opt) > j: prod_opt = obj.prod_opt[j] break self.species.reac_ts_done[index] = 5 elif self.species.reac_ts_done[index] == 5: # check up on the TS and product optimizations opts_done = 1 fails = 0 # check if ts is done if self.species.reac_type[index] != 'hom_sci': if not obj.ts_opt.shir == 1: # last stage in optimize opts_done = 0 obj.ts_opt.do_optimization() if obj.ts_opt.shigh == -999: logging.info( "Reaction {} ts_opt_shigh failure".format( obj.instance_name)) fails = 1 for pr_opt in obj.prod_opt: if not pr_opt.shir == 1: opts_done = 0 pr_opt.do_optimization() if pr_opt.shigh == -999: logging.info( "Reaction {} pr_opt_shigh failure".format( obj.instance_name)) fails = 1 break if fails: self.species.reac_ts_done[index] = -999 elif opts_done: self.species.reac_ts_done[index] = 6 elif self.species.reac_ts_done[index] == 6: # Finilize the calculations # continue to PES search in case a new well was found if self.par['pes']: # verify if product is monomolecular, and if it is new if len(obj.products) == 1: st_pt = obj.prod_opt[0].species chemid = st_pt.chemid new_barrier_threshold = self.par[ 'barrier_threshold'] - ( st_pt.energy - self.species.energy) * constants.AUtoKCAL dirwell = os.path.dirname(os.getcwd()) jobs = open(dirwell + '/chemids', 'r').read().split('\n') jobs = [ji for ji in jobs] if not str(chemid) in jobs: # this well is new, add it to the jobs while 1: try: # try to open the file and write to it pes.write_input( self.inp, obj.products[0], new_barrier_threshold, dirwell) with open(dirwell + '/chemids', 'a') as f: f.write('{}\n'.format(chemid)) break except IOError: # wait a second and try again time.sleep(1) pass # copy the files of the species to an upper directory frags = obj.products for frag in frags: filecopying.copy_to_database_folder( self.species.chemid, frag.chemid, self.qc) # check for wrong number of negative frequencies neg_freq = 0 for st_pt in obj.products: if any([fi < 0. for fi in st_pt.reduced_freqs]): neg_freq = 1 if any([fi < 0. for fi in obj.ts.reduced_freqs[1:]]): neg_freq = 1 if neg_freq: logging.info('\tFound negative frequency for ' + obj.instance_name) self.species.reac_ts_done[index] = -999 else: # the reaction search is finished self.species.reac_ts_done[ index] = -1 # this is the success code # write a temporary pes input file # remove old xval and im_extent files if os.path.exists('{}_xval.txt'.format( self.species.chemid)): os.remove('{}_xval.txt'.format( self.species.chemid)) if os.path.exists('{}_im_extent.txt'.format( self.species.chemid)): os.remove('{}_im_extent.txt'.format( self.species.chemid)) postprocess.createPESViewerInput( self.species, self.qc, self.par) elif self.species.reac_ts_done[index] == -999: if self.par['delete_intermediate_files'] == 1: if not self.species.reac_obj[ index].instance_name in deleted: self.delete_files( self.species.reac_obj[index].instance_name) deleted.append( self.species.reac_obj[index].instance_name) alldone = 1 for index, instance in enumerate(self.species.reac_inst): if any(self.species.reac_ts_done[i] >= 0 for i in range(len(self.species.reac_inst))): alldone = 1 break else: alldone = 0 # write a small summary while running with open('kinbot_monitor.out', 'w') as f_out: for index, instance in enumerate(self.species.reac_inst): if self.species.reac_ts_done[index] == -1: prodstring = [] for pp in self.species.reac_obj[index].products: prodstring.append(str(pp.chemid)) f_out.write('{}\t{}\t{}\t{}\n'.format( self.species.reac_ts_done[index], self.species.reac_step[index], self.species.reac_obj[index].instance_name, ' '.join(prodstring))) else: f_out.write('{}\t{}\t{}\n'.format( self.species.reac_ts_done[index], self.species.reac_step[index], self.species.reac_obj[index].instance_name)) time.sleep(1) # Create molpro file for the BLS products for index, instance in enumerate(self.species.reac_inst): if self.species.reac_type[index] == 'barrierless_saddle': obj = self.species.reac_obj[index] if len(obj.products) == 2: blsprodatom = np.append(obj.products[0].atom, obj.products[1].atom) # vector connecting the centers # assumed: the two structures are naturally separated at the end of the IRC x0 = 0 y0 = 0 z0 = 0 for g in obj.products[0].geom: x0 += g[0] y0 += g[1] z0 += g[1] x0 /= obj.products[0].natom y0 /= obj.products[0].natom z0 /= obj.products[0].natom x1 = 0 y1 = 0 z1 = 0 for g in obj.products[1].geom: x1 += g[0] y1 += g[1] z1 += g[1] x1 /= obj.products[1].natom y1 /= obj.products[1].natom z1 /= obj.products[1].natom center_vec = [x1 - x0, y1 - y0, z1 - z0] blsprodgeom = np.append(obj.products[0].geom, obj.products[1].geom) blsprodgeom = np.reshape(blsprodgeom, (-1, 3)) bps = list(zip(blsprodatom, blsprodgeom)) bps1 = [item for sublist in bps for item in sublist] blsprodstruct = [ item for sublist in bps1 for item in sublist ] blsprod = StationaryPoint('blsprod', self.par['charge'], self.par['mult'], structure=blsprodstruct) blsprod.characterize() molp = Molpro(blsprod, self.par) molpname = '{}_prod'.format(obj.instance_name) molp.create_molpro_input(bls=1, name=molpname, shift_vec=center_vec, natom1=len(obj.products[1].geom)) molp.create_molpro_submit(name=molpname) s = [] for index, instance in enumerate(self.species.reac_inst): obj = self.species.reac_obj[index] # Write a summary on the combinatorial exploration if 'combinatorial' in obj.instance_name: s.append('NAME\t' + obj.instance_name) # Write the bonds that were broken and formed s.append('BROKEN_BONDS\t' + '\t'.join('[{}, {}]'.format(re[0], re[1]) for re in obj.reac)) s.append('FORMED_BONDS\t' + '\t'.join('[{}, {}]'.format(pr[0], pr[1]) for pr in obj.prod)) # Populate the ts_bond_lengths dict with the values # of this reaction if self.species.reac_ts_done[index] == -1: for i in range(self.species.natom - 1): for j in range(i + 1, self.species.natom): if self.species.bond[i][j] != obj.product_bonds[i][ j]: if (self.species.bond[i][j] == 0 or obj.product_bonds[i][j] == 0): syms = [] syms.append(self.species.atom[i]) syms.append(self.species.atom[j]) syms = ''.join(sorted(syms)) dist = np.linalg.norm(obj.ts.geom[i] - obj.ts.geom[j]) s.append('TS_BOND_LENGTHS\t{}\t{}'.format( syms, dist)) # write the expected inchis s.append('EXPECTED_INCHIS\t' + '\t'.join(inchi for inchi in obj.prod_inchi)) # get the inchis the reaction found if self.species.reac_ts_done[index] == -1: inchis = obj.get_final_inchis() s.append('FOUND_INCHIS\t' + '\t'.join(inchis)) s.append('\n') with open('combinatorial.txt', 'w') as f: f.write('\n'.join(s) + '\n') logging.info("Reaction generation done!")
def generate(self): """ Creates the input for each reaction, runs them, and tests for success. If successful, it creates the barrier and product objects. It also then does the conformational search, and finally, the hindered rotor scans. To make the code the most efficient, all of these happen in parallel, in a sense that the jobs are not waiting for each other. E.g., one reaction can still be in the stage of TS search, while the other can be already at the hindered rotor scan. This way, all cores are occupied efficiently. The switching between the various stages are done via the reac_ts_done variable. 0: initiate the TS search 1: check barrier height and errors in TS, and initiates normal mode displacement test, start the irc calculations 2: submit product optimization 3: submit the frequency calculation 4: do the optimization of the ts and the products 5: follow up on the optimizations 6: finalize calculations, check for wrong number of negative frequencies If at any times the calculation fails, reac_ts_done is set to -999. If all steps are successful, reac_ts_done is set to -1. """ deleted = [] if len(self.species.reac_inst) > 0: alldone = 1 else: alldone = 0 # status to see of kinbot needs to wait for the product optimizations # from another kinbot run, to avoid duplication of calculations products_waiting_status = [[] for i in self.species.reac_inst] count = 0 for i in self.species.reac_inst: count = count + 1 all_unique_prod = [] frag_unique = [] nameUnique = [] stpt_inchis = [] while alldone: for index, instance in enumerate(self.species.reac_inst): obj = self.species.reac_obj[index] instance_name = obj.instance_name # START REACTION SEARCH if self.species.reac_ts_done[ index] == 0 and self.species.reac_step[index] == 0: #verify after restart if search has failed in previous kinbot run status = self.qc.check_qc(instance_name) if status == 'error' or status == 'killed': logging.info( '\tRxn search failed (error or killed) for {}'. format(instance_name)) self.species.reac_ts_done[index] = -999 if self.species.reac_ts_done[ index] == 0: # ts search is ongoing if obj.scan == 0: #don't do a scan of a bond if self.species.reac_step[index] == obj.max_step + 1: status = self.qc.get_qc_freq( instance_name, self.species.natom)[0] if status == 0: self.species.reac_ts_done[index] = 1 elif status == -1: logging.info( '\tRxn search failed for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par.par['qc_command']) else: # do a bond scan if self.species.reac_step[ index] == self.par.par['scan_step'] + 1: status = self.qc.get_qc_freq( instance_name, self.species.natom)[0] if status == 0: self.species.reac_ts_done[index] = 1 elif status == -1: logging.info( '\tRxn search failed for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: if self.species.reac_step[index] == 0: self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par.par['qc_command']) elif self.species.reac_step[index] > 0: status = self.qc.check_qc(instance_name) if status == 'error' or status == 'killed': logging.info( '\tRxn search failed for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: err, energy = self.qc.get_qc_energy( instance_name) if err == 0: self.species.reac_scan_energy[ index].append(energy) if len(self.species. reac_scan_energy[index]) > 1: if self.species.reac_scan_energy[ index][ -1] < self.species.reac_scan_energy[ index][-2]: self.species.reac_step[ index] = self.par.par[ 'scan_step'] #ts search restarted w/ next line? self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par.par['qc_command']) elif self.species.reac_ts_done[index] == 1: status = self.qc.check_qc(instance_name) if status == 'running': continue elif status == 'error': logging.info( '\tRxn search failed (gaussian error) for {}'. format(instance_name)) self.species.reac_ts_done[index] = -999 else: #check the barrier height: if self.species.reac_type[ index] == 'R_Addition_MultipleBond': sp_energy = self.qc.get_qc_energy( str(self.species.chemid) + '_well_mp2')[1] barrier = (self.qc.get_qc_energy(instance_name)[1] - sp_energy) * constants.AUtoKCAL else: sp_energy = self.qc.get_qc_energy( str(self.species.chemid) + '_well')[1] barrier = (self.qc.get_qc_energy(instance_name)[1] - sp_energy) * constants.AUtoKCAL if barrier > self.par.par['barrier_threshold']: logging.info( '\tRxn barrier too high ({0:.2f} kcal/mol) for {1}' .format(barrier, instance_name)) self.species.reac_ts_done[index] = -999 else: obj.irc = IRC( obj, self.par ) #TODO: this doesn't seem like a good design irc_status = obj.irc.check_irc() if 0 in irc_status: # No IRC started yet, start the IRC now logging.info( '\tStarting IRC calculations for {}'. format(instance_name)) obj.irc.do_irc_calculations() elif irc_status[0] == 'running' or irc_status[ 1] == 'running': continue else: #IRC's have successfully finished, have an error or were killed, in any case #read the geometries and try to make products out of them #verify which of the ircs leads back to the reactant, if any prod = obj.irc.irc2stationary_pt() if prod == 0: logging.info( '\t\tNo product found for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: obj.products = prod obj.product_bonds = prod.bond self.species.reac_ts_done[index] = 2 elif self.species.reac_ts_done[index] == 2: if len(products_waiting_status[index]) == 0: #identify bimolecular products and wells fragments, maps = obj.products.start_multi_molecular() obj.products = [] a = [] for frag in fragments: a.append(frag) if len(frag_unique) == 0: frag_unique.append(frag) elif len(frag_unique) > 0: new = 1 for fragb in frag_unique: if frag.chemid == fragb.chemid: e, geom2 = self.qc.get_qc_geom( str(fragb.chemid) + '_well', fragb.natom) if e == 0: a.pop() frag = fragb a.append(frag) new = 0 break if new: frag_unique.append(frag) obj.products_final = [] for frag in a: self.qc.qc_opt(frag, frag.geom) e, geom2 = self.qc.get_qc_geom( str(frag.chemid) + '_well', frag.natom) obj.products_final.append(frag) #check products make sure they are the same for i, st_pt_i in enumerate(obj.products_final): for j, st_pt_j in enumerate(obj.products_final): if st_pt_i.chemid == st_pt_j.chemid and i < j: obj.products_final[j] = obj.products_final[ i] #print products generated by IRC products = [] for i, st_pt in enumerate(obj.products_final): products.append(st_pt.chemid) products.extend([' ', ' ', ' ']) barrier = (self.qc.get_qc_energy(instance_name)[1] - sp_energy) * constants.AUtoKCAL logging.info( '\tReaction {0} has a barrier of {1:.2f} kcal/mol and leads to products {2} {3} {4}' .format(instance_name, barrier, products[0], products[1], products[2])) for i, st_pt in enumerate(obj.products_final): chemid = st_pt.chemid e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: logging.info( '\tProduct optimization failed for {}, product {}' .format(instance_name, st_pt.chemid)) self.species.reac_ts_done[index] = -999 err = -1 elif e != 0: err = -1 else: e2, st_pt.energy = self.qc.get_qc_energy( str(st_pt.chemid) + '_well') e2, st_pt.zpe = self.qc.get_qc_zpe( str(st_pt.chemid) + '_well') st_pt.characterize( dimer=0 ) # not allowed to use the dimer option here if chemid != st_pt.chemid: obj.products_final.pop(i) newfrags, newmaps = st_pt.start_multi_molecular( ) # newfrags is list of stpt obj products_waiting_status[index] = [ 0 for frag in newfrags ] fragChemid = [] for i, newfr in enumerate(newfrags): for prod in frag_unique: if newfr.chemid == prod.chemid: newfrags.pop(i) newfr = prod j = i - 1 newfrags.insert(j, newfr) #add new frag to frag_unique somehow? j = i - 1 obj.products_final.insert(j, newfr) self.qc.qc_opt(newfr, newfr.geom, 0) fragChemid.append(newfr.chemid) if len(fragChemid) == 1: fragChemid.append(" ") for i, frag in enumerate(newfrags): products_waiting_status[index][i] = 1 logging.info( '\ta) Product optimized to other structure for {}, product {} to {} {}' .format(instance_name, chemid, fragChemid[0], fragChemid[1])) obj.products = [] for prod in obj.products_final: obj.products.append(prod) obj.products_final = [] if all([pi == 1 for pi in products_waiting_status[index]]): self.species.reac_ts_done[index] = 3 elif self.species.reac_ts_done[index] == 3: # wait for the optimization to finish # if two st_pt are the same in the products, we make them exactly identical otherwise # the different ordering of the atoms causes the chemid of the second to be seemingly wrong for i, st_pt_i in enumerate(obj.products): for j, st_pt_j in enumerate(obj.products): if st_pt_i.chemid == st_pt_j.chemid and i < j: obj.products[j] = obj.products[i] ''' # generate and compare inchis if len(stpt_inchis) == 0: well0_inchi = cheminfo.create_inchi_from_geom(self.species.atom,self.species.geom) well0_chemicalFormula = well0_inchi.split('S/')[1].split('/')[0] well0_stereochem = '' if "/t" in str(well0_inchi): well0_stereochem = well0_inchi.split('/t')[1].split('/')[0] well0_info = [self.species.chemid, well0_chemicalFormula, well0_inchi, well0_stereochem] stpt_inchis.append(well0_info) for st_pt in obj.products: prod_chemid = st_pt.chemid prod_inchi = cheminfo.create_inchi_from_geom(st_pt.atom,st_pt.geom) prod_chemicalFormula = prod_inchi.split('S/')[1].split('/')[0] prod_stereochem = '' if "/t" in str(prod_inchi): prod_stereochem = prod_inchi.split('/t')[1].split('/')[0] prod_info = [prod_chemid, prod_chemicalFormula, prod_inchi, prod_stereochem] stpt_inchis.append(prod_info) inchiFile = open('inchis.log','w') well0_chemid = stpt_inchis[0][0] well0_chemicalFormula = stpt_inchis[0][1] well0_stereochem = stpt_inchis[0][3] for inchi in stpt_inchis: inchiFile.write("{}\t|{}\t|{}\t|{}\n".format(inchi[0],inchi[1],inchi[2],inchi[3])) prod_chemid = inchi[0] prod_stereochem = inchi[3] prod_chemicalFormula = inchi[1] if well0_chemicalFormula == prod_chemicalFormula: if str(well0_stereochem) != str(prod_stereochem): logging.warning("\t\t!WARNING! Stereochemistry for product {} differs from the initial well ({}) for reaction {}".format(prod_chemid, well0_chemid, instance_name)) inchiFile.close() ''' err = 0 for st_pt in obj.products: chemid = st_pt.chemid e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: logging.info( '\tProduct optimization failed for {}, product {}' .format(instance_name, st_pt.chemid)) self.species.reac_ts_done[index] = -999 err = -1 elif e != 0: err = -1 else: e2, st_pt.energy = self.qc.get_qc_energy( str(st_pt.chemid) + '_well') e2, st_pt.zpe = self.qc.get_qc_zpe( str(st_pt.chemid) + '_well') st_pt.characterize( dimer=0 ) # not allowed to use the dimer option here if chemid != st_pt.chemid: # product was optimized to another structure, give warning but don't remove reaction logging.info( '\tb) Product optimized to other structure for {}, product {} to {}' .format(instance_name, chemid, st_pt.chemid)) e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: err = -1 if err == 0: self.species.reac_ts_done[index] = 4 elif self.species.reac_ts_done[index] == 4: # Do the TS and product optimization # make a stationary point object of the ts bond_mx = np.zeros( (self.species.natom, self.species.natom)) for i in range(self.species.natom): for j in range(self.species.natom): bond_mx[i][j] = max(self.species.bond[i][j], obj.product_bonds[i][j]) err, geom = self.qc.get_qc_geom(instance_name, self.species.natom) ts = StationaryPoint(instance_name, self.species.charge, self.species.mult, atom=self.species.atom, geom=geom, wellorts=1) err, ts.energy = self.qc.get_qc_energy(instance_name) err, ts.zpe = self.qc.get_qc_zpe( instance_name) # NEW STOPS HERE ts.bond = bond_mx ts.find_cycle() ts.find_conf_dihedral() obj.ts = ts #do the ts optimization obj.ts_opt = Optimize(obj.ts, self.par, self.qc) obj.ts_opt.do_optimization() #do the products optimizations for st_pt in obj.products: #do the products optimizations #check for products of other reactions that are the same as this product #in the case such products are found, use the same Optimize object for both for i, inst_i in enumerate(self.species.reac_inst): new = 1 if not i == index: obj_i = self.species.reac_obj[i] if self.species.reac_ts_done[i] > 3: for j, st_pt_i in enumerate( obj_i.products): if st_pt_i.chemid == st_pt.chemid: if len(obj_i.prod_opt) > j: prod_opt = obj_i.prod_opt[j] new = 0 break if new: prod_opt = Optimize(st_pt, self.par, self.qc) prod_opt.do_optimization() obj.prod_opt.append(prod_opt) for st_pt in obj.products: #section where comparing products in same reaction occurs if len(obj.prod_opt) > 0: for j, st_pt_opt in enumerate(obj.prod_opt): if st_pt.chemid == st_pt_opt.species.chemid: if len(obj.prod_opt) > j: prod_opt = obj.prod_opt[j] break elog = open("energy.log", 'a') for prod_opt in obj.prod_opt: elog.write("prod_opt: {} |\tenergy: {}\n".format( prod_opt.species.chemid, prod_opt.species.energy)) elog.close() self.species.reac_ts_done[index] = 5 elif self.species.reac_ts_done[index] == 5: #check up on the TS and product optimizations opts_done = 1 fails = 0 #check if ts is done if not obj.ts_opt.shir == 1: opts_done = 0 obj.ts_opt.do_optimization() if obj.ts_opt.shigh == -999: logging.info("Reaction {} ts_opt_shigh failure".format( instance_name)) fails = 1 for pr_opt in obj.prod_opt: if not pr_opt.shir == 1: opts_done = 0 pr_opt.do_optimization() if pr_opt.shigh == -999: logging.info( "Reaction {} pr_opt_shigh failure".format( instance_name)) fails = 1 if fails: self.species.reac_ts_done[index] = -999 elif opts_done: self.species.reac_ts_done[index] = 6 elif self.species.reac_ts_done[index] == 6: #Finilize the calculations #continue to PES search in case a new well was found if self.par.par['pes']: #verify if product is monomolecular, and if it is new if len(obj.products) == 1: st_pt = obj.prod_opt[0].species chemid = st_pt.chemid energy = st_pt.energy well_energy = self.species.energy new_barrier_threshold = self.par.par[ 'barrier_threshold'] - ( energy - well_energy) * constants.AUtoKCAL dir = os.path.dirname(os.getcwd()) jobs = open(dir + '/chemids', 'r').read().split('\n') jobs = [ji for ji in jobs] if not str(chemid) in jobs: #this well is new, add it to the jobs while 1: try: #try to open the file and write to it pes.write_input( self.par, obj.products[0], new_barrier_threshold, dir) f = open(dir + '/chemids', 'a') f.write('{}\n'.format(chemid)) f.close() break except IOError: #wait a second and try again time.sleep(1) pass # copy the files of the species to an upper directory frags = obj.products for frag in frags: filecopying.copy_to_database_folder( self.species.chemid, frag.chemid, self.qc) #check for wrong number of negative frequencies neg_freq = 0 for st_pt in obj.products: if any([fi < 0. for fi in st_pt.reduced_freqs]): neg_freq = 1 if any([fi < 0. for fi in obj.ts.reduced_freqs[1:]]): neg_freq = 1 if neg_freq: logging.info('\tFound negative frequency for ' + instance_name) self.species.reac_ts_done[index] = -999 else: #the reaction search is finished self.species.reac_ts_done[ index] = -1 # this is the success code # write a temporary pes input file # remove old xval and im_extent files if os.path.exists('{}_xval.txt'.format( self.species.chemid)): os.remove('{}_xval.txt'.format( self.species.chemid)) if os.path.exists('{}_im_extent.txt'.format( self.species.chemid)): os.remove('{}_im_extent.txt'.format( self.species.chemid)) postprocess.createPESViewerInput( self.species, self.qc, self.par) elif self.species.reac_ts_done[index] == -999: if self.par.par['delete_intermediate_files'] == 1: if not self.species.reac_obj[ index].instance_name in deleted: self.delete_files( self.species.reac_obj[index].instance_name) deleted.append( self.species.reac_obj[index].instance_name) alldone = 1 for index, instance in enumerate(self.species.reac_inst): if any(self.species.reac_ts_done[i] >= 0 for i in range(len(self.species.reac_inst))): alldone = 1 break else: alldone = 0 # write a small summary while running wr = 1 if wr: f_out = open('kinbot_monitor.out', 'w') for index, instance in enumerate(self.species.reac_inst): f_out.write('{}\t{}\t{}\n'.format( self.species.reac_ts_done[index], self.species.reac_step[index], self.species.reac_obj[index].instance_name)) f_out.close() time.sleep(1) s = [] for index, instance in enumerate(self.species.reac_inst): obj = self.species.reac_obj[index] instance_name = obj.instance_name # Write a summary on the combinatorial exploration if 'combinatorial' in instance_name: s.append('NAME\t' + instance_name) # Write the bonds that were broken and formed s.append('BROKEN_BONDS\t' + '\t'.join('[{}, {}]'.format(re[0], re[1]) for re in obj.reac)) s.append('FORMED_BONDS\t' + '\t'.join('[{}, {}]'.format(pr[0], pr[1]) for pr in obj.prod)) # Populate the ts_bond_lengths dict with the values # of this reaction if self.species.reac_ts_done[index] == -1: for i in range(self.species.natom - 1): for j in range(i + 1, self.species.natom): if self.species.bond[i][j] != obj.product_bonds[i][ j]: if (self.species.bond[i][j] == 0 or obj.product_bonds[i][j] == 0): syms = [] syms.append(self.species.atom[i]) syms.append(self.species.atom[j]) syms = ''.join(sorted(syms)) dist = np.linalg.norm(obj.ts.geom[i] - obj.ts.geom[j]) s.append('TS_BOND_LENGTHS\t{}\t{}'.format( syms, dist)) # write the expected inchis s.append('EXPECTED_INCHIS\t' + '\t'.join(inchi for inchi in obj.prod_inchi)) # get the inchis the reaction found if self.species.reac_ts_done[index] == -1: inchis = obj.get_final_inchis() s.append('FOUND_INCHIS\t' + '\t'.join(inchis)) s.append('\n') with open('combinatorial.txt', 'w') as f: f.write('\n'.join(s) + '\n') logging.info("Reaction generation done!")
def create_mess_input(par, wells, products, reactions, well_energies, prod_energies, parent): """ When calculating a full pes, the files from the separate wells are read and concatenated into one file Two things per file need to be updated 1. the names of all the wells, bimolecular products and ts's 2. all the zpe corrected energies """ # generate short names for all startionary points well_short, pr_short, fr_short, ts_short = create_short_names( wells, products, reactions) # list of the strings to write to mess input file s = [] # write the header s.append(write_header(par, well_short[wells[0]])) # write the wells s.append('######################') s.append('# WELLS') s.append('######################') for well in wells: name = well_short[well] + ' ! ' + well energy = well_energies[well] with open(parent[well] + '/' + well + '.mess') as f: s.append(f.read().format(name=name, zeroenergy=energy)) s.append('!****************************************') # write the products s.append('######################') s.append('# BIMOLECULAR PRODUCTS') s.append('######################') for prod in products: name = pr_short[prod] + ' ! ' + prod energy = prod_energies[prod] fr_names = {} for fr in prod.split('_'): key = 'fr_name_{}'.format(fr) value = fr_short[fr] + ' ! ' + fr fr_names[key] = value with open(parent[prod] + '/' + prod + '.mess') as f: s.append(f.read().format(name=name, ground_energy=energy, **fr_names)) s.append('!****************************************') # write the barrier s.append('######################') s.append('# BARRIERS') s.append('######################') for rxn in reactions: name = [ts_short[rxn[1]]] name.append(well_short[rxn[0]]) if len(rxn[2]) == 1: name.append(well_short[rxn[2][0]]) else: name.append(pr_short['_'.join(sorted(rxn[2]))]) name.append('!') name.append(rxn[1]) energy = rxn[3] with open(rxn[0] + '/' + rxn[1] + '.mess') as f: s.append(f.read().format(name=' '.join(name), zeroenergy=energy)) s.append('!****************************************') # add last end statement s.append('!****************************************') s.append('End ! end kinetics\n') if not os.path.exists('me'): os.mkdir('me') # write everything to a file with open('me/mess.inp', 'w') as f: f.write('\n'.join(s)) dummy = StationaryPoint('dummy', par.par['charge'], par.par['mult'], smiles=par.par['smiles'], structure=par.par['structure']) mess = MESS(par, dummy) if par.par['me']: mess.run()
def do_optimization(self): while 1: # do the conformational search if self.par['conformer_search'] == 1: if self.scycconf == -1 and self.sconf == -1: logging.info('\tStarting conformational search of {}'.format(self.name)) self.species.confs = Conformers(self.species, self.par, self.qc) # first do the cyclic part of the molecule if self.scycconf == -1: # start the ring conf search if len(self.species.cycle_chain) > 0: # there are rings in the molecule, do a search self.species.confs.generate_ring_conformers(copy.deepcopy(self.species.geom)) # set the cyclic conf status to running self.scycconf = 0 else: # there are no rings in the molecule, continue from the current geometry self.species.confs.cyc_conf_geoms = [copy.deepcopy(self.species.geom)] # no ring conf search has to be done, set status to finished self.scycconf = 1 if self.scycconf == 0: # ring conf search is running, check if finished status, self.species.confs.cyc_conf_geoms = self.species.confs.check_ring_conformers() if status: # ring conf search is finished self.scycconf = 1 # first do an semi empirical optimization if requested by the user if self.par['semi_emp_conformer_search'] == 1: logging.info('semi empirical conformer search is starting for {}'.format(self.name)) if self.ssemi_empconf == -1: # semi empirical part has not started yet self.species.semi_emp_confs = Conformers(self.species, self.par, self.qc, semi_emp=1) for geom in self.species.confs.cyc_conf_geoms: # take all the geometries from the cyclic part # generate the conformers for the current geometry self.species.semi_emp_confs.generate_conformers(0, geom) # set conf status to running self.ssemi_empconf = 0 if self.ssemi_empconf == 0: # semi empirical conformational search is running # check if the conformational search is done status, lowest_conf, geom, self.semi_emp_low_energy, self.semi_emp_conformers, self.semi_emp_energies = self.species.semi_emp_confs.check_conformers(wait=self.wait) if status == 1: logging.info("semi empirical lowest energy conformer for species {} is number {}".format(self.name, lowest_conf)) # set conf status to finished self.ssemi_empconf = 1 else: self.ssemi_empconf = 1 if self.ssemi_empconf == 1 and self.scycconf == 1: # do open chain part if cyclic (if there were any) and semi empirical (if requested) parts are done if self.sconf == -1: # open chain part has not started yet # if semi empirical conformer were searched for, start from those, # else start from cyclic conformers if self.par['semi_emp_conformer_search'] == 1: self.species.confs.nconfs = 1 for i, geom in enumerate(self.semi_emp_conformers): if (self.semi_emp_energies[i] - self.semi_emp_low_energy) * constants.AUtoKCAL < self.par['semi_emp_confomer_threshold']: self.species.confs.generate_conformers(-999, geom) logging.info("There are {} structures below the {} kcal/mol threshold for species {} in the semiempirical search.". \ format(i, self.par['semi_emp_confomer_threshold'], self.name)) else: print_warning = True for geom in self.species.confs.cyc_conf_geoms: # take all the geometries from the cyclic part # generate the conformers for the current geometry self.skip_conf_check = self.species.confs.generate_conformers(0, geom, print_warning=print_warning) print_warning = False # set conf status to running self.sconf = 0 if self.sconf == 0: # conformational search is running # check if the conformational search is done if self.skip_conf_check == 0: status, lowest_conf, geom, low_energy, conformers, energies = self.species.confs.check_conformers(wait=self.wait) if status == 1: logging.info("lowest energy conformer for species: {} is number {}".format(self.name, lowest_conf)) # save lowest energy conformer as species geometry self.species.geom = geom # save lowest energy conformer energy self.species.energy = low_energy # set conf status to finished self.sconf = 1 elif self.skip_conf_check == 1: self.species.geom, self.species.energy = self.species.confs.lowest_conf_info() logging.info('Conformers are not checked for {} to speed up calculations.'.format(self.name)) logging.info('They seem to have been done in a previous run.') logging.info('Energy and geometry updated based on conf/{}_low file.'.format(self.name)) self.sconf = 1 else: # no conf search necessary, set status to finished self.sconf = 1 if self.sconf == 1: # conf search is finished # if the conformers were already done in a previous run # not clear what the purpose of these lines were if self.par['conformer_search'] == 1: status, lowest_conf, geom, low_energy, conformers, energies = self.species.confs.check_conformers(wait=self.wait) while self.restart <= self.max_restart: # do the high level calculations if self.par['high_level'] == 1: if self.shigh == -1: if self.species.wellorts: name = self.species.name else: name = self.species.chemid # high level calculation did not start yet logging.info('\tStarting high level optimization of {}'.format(name)) if self.species.wellorts: # do the high level optimization of a ts self.qc.qc_opt_ts(self.species, self.species.geom, high_level=1) else: # do the high level optimization of a well self.qc.qc_opt(self.species, self.species.geom, high_level=1) self.shigh = 0 # set the high status to running if self.shigh == 0: # high level calculation is running # check if it is finished status = self.qc.check_qc(self.job_high) if status == 'error': # found an error logging.info('\tHigh level optimization failed for {}'.format(self.name)) self.shigh = -999 elif status == 'normal': # finished successfully err, new_geom = self.qc.get_qc_geom(self.job_high, self.species.natom, wait=self.wait) temp = StationaryPoint('temp', self.species.charge, self.species.mult, atom=self.species.atom, geom=new_geom) temp.bond_mx() if self.species.wellorts: # for TS we need reasonable geometry agreement and normal mode correlation if self.par['conformer_search'] == 0: fr_file = self.fr_file_name(0) # name of the original TS file else: if self.skip_conf_check == 0: fr_file = 'conf/{}_{}'.format(self.fr_file_name(0), lowest_conf) else: fr_file = 'conf/{}_low'.format(self.fr_file_name(0)) if self.qc.qc == 'gauss': imagmode = reader_gauss.read_imag_mode(fr_file, self.species.natom) fr_file = self.fr_file_name(1) if self.qc.qc == 'gauss': imagmode_high = reader_gauss.read_imag_mode(fr_file, self.species.natom) # either geom is roughly same with closely matching imaginary modes, or geometry is very close # maybe we need to do IRC at the high level as well... same_geom = ((geometry.matrix_corr(imagmode, imagmode_high) > 0.9) and \ (geometry.equal_geom(self.species, temp, 0.3))) \ or (geometry.equal_geom(self.species, temp, 0.15)) else: same_geom = geometry.equal_geom(self.species, temp, 0.1) err, fr = self.qc.get_qc_freq(self.job_high, self.species.natom) if self.species.natom == 1: freq_ok = 1 elif len(fr) == 1 and fr[0] == 0: freq_ok = 0 elif self.species.wellorts == 0 and fr[0] > 0.: freq_ok = 1 elif self.species.wellorts == 1 and fr[0] < 0. and fr[1] > 0.: freq_ok = 1 else: freq_ok = 0 if same_geom and freq_ok: # geometry is as expected and normal modes are the same for TS err, self.species.geom = self.qc.get_qc_geom(self.job_high, self.species.natom) err, self.species.energy = self.qc.get_qc_energy(self.job_high) err, self.species.freq = self.qc.get_qc_freq(self.job_high, self.species.natom) err, self.species.zpe = self.qc.get_qc_zpe(self.job_high) self.shigh = 1 else: # geometry diverged to other structure if not same_geom: logging.info('\tHigh level optimization converged to different structure for {}, related channels are deleted.'.format(self.name)) if not freq_ok: logging.info('\tWrong number of imaginary frequencies for {}, related channels are deleted.'.format(self.name)) self.shigh = -999 else: # no high-level calculations necessary, set status to finished self.shigh = 1 if self.shigh == 1: # do the HIR calculation if self.par['rotor_scan'] == 1: if self.shir == -1: # hir not stated yet logging.info('\tStarting hindered rotor calculations of {}'.format(self.name)) self.species.hir = HIR(self.species, self.qc, self.par) self.species.hir.generate_hir_geoms(copy.deepcopy(self.species.geom), self.par['rigid_hir']) self.shir = 0 if self.shir == 0: # hir is running # check if it is done: status = self.species.hir.check_hir(wait=self.wait) if status: if len(self.species.hir.hir_energies) > 0: # check if along the hir potential a structure was found with a lower energy min = self.species.hir.hir_energies[0][0] min_rotor = -1 min_ai = -1 for rotor in range(len(self.species.dihed)): for ai in range(self.species.hir.nrotation): # use a 0.1kcal/mol cutoff for numerical noise if self.species.hir.hir_energies[rotor][ai] < min - 1.6E-4: min = self.species.hir.hir_energies[rotor][ai] min_rotor = rotor min_ai = ai if min_rotor > -1: self.restart += 1 if self.restart < self.max_restart: # lower energy structure found logging.info('\t\tLower energy found during hindered rotor scan for {}'.format(self.name)) logging.info('\t\tRestart number: ' + str(self.restart)) logging.info('\t\tRotor: ' + str(min_rotor)) logging.info('\t\tScan point: ' + str(min_ai)) job = self.job_hir + str(min_rotor) + '_' + str(min_ai).zfill(2) err, self.species.geom = self.qc.get_qc_geom(job, self.species.natom) # delete the high_level log file and the hir log files if os.path.exists(self.job_high + '.log'): # logging.info("\t\t\tRemoving file " + self.job_high + '.log') os.remove(self.job_high + '.log') for rotor in range(len(self.species.dihed)): for ai in range(self.species.hir.nrotation): if os.path.exists(self.job_hir + str(rotor) + '_' + str(ai).zfill(2) + '.log'): # logging.info("\t\t\tRemoving file " + self.job_hir + str(rotor) + '_' + str(ai).zfill(2) + '.log') os.remove(self.job_hir + str(rotor) + '_' + str(ai).zfill(2) + '.log') # set the status of high and hir back to not started self.shigh = -1 self.shir = -1 else: logging.info('\t\tLower energy found, but readched max restart for {}'.format(self.name)) self.shir = 1 else: self.shir = 1 else: self.shir = 1 else: # no hir calculations necessary, set status to finished self.shir = 1 if not self.wait or self.shir == 1 or self.shigh == -999: # break the loop if no waiting is required or # if the hir calcs are done or # if the high level calc failed break else: time.sleep(1) if self.shir == 1: # finalize if no waiting is required or if the hir calcs are done # calculate the symmetry numbers symmetry.calculate_symmetry(self.species) # calculate the new frequencies with the internal rotations projected out fr_file = self.name if not self.species.wellorts: fr_file += '_well' if self.par['high_level']: fr_file += '_high' fr_file = self.fr_file_name(self.par['high_level']) hess = self.qc.read_qc_hess(fr_file, self.species.natom) self.species.kinbot_freqs, self.species.reduced_freqs = frequencies.get_frequencies(self.species, hess, self.species.geom) # write the molpro input and read the molpro energy, if available if self.par['L3_calc'] == 1: if self.par['single_point_qc'] == 'molpro': molp = Molpro(self.species, self.par) if 'barrierless_saddle' in self.name: key = self.par['barrierless_saddle_single_point_key'] molp.create_molpro_input(bls=1) else: key = self.par['single_point_key'] molp.create_molpro_input() molp.create_molpro_submit() status, molpro_energy = molp.get_molpro_energy(key) # FIXME this might be wrong here: if status: self.species.energy = molpro_energy self.delete_files() if self.wait: if self.shir == 1 or self.shigh == -999: return 0 time.sleep(1) else: return 0
def generate(self): """ Creates the input for each reaction, runs them, and tests for success. If successful, it creates the barrier and product objects. It also then does the conformational search, and finally, the hindered rotor scans. To make the code the most efficient, all of these happen in parallel, in a sense that the jobs are not waiting for each other. E.g., one reaction can still be in the stage of TS search, while the other can be already at the hindered rotor scan. This way, all cores are occupied efficiently. The switching between the various stages are done via the reac_ts_done variable. 0: initiate the TS search 1: check barrier height and errors in TS, and initiates normal mode displacement test, start the irc calculations 2: submit product optimization 3: submit the frequency calculation 4: do the optimization of the ts and the products 5: follow up on the optimizations 6: finalize calculations, check for wrong number of negative frequencies If at any times the calculation fails, reac_ts_done is set to -999. If all steps are successful, reac_ts_done is set to -1. """ if len(self.species.reac_inst) > 0: alldone = 1 else: alldone = 0 while alldone: for index, instance in enumerate(self.species.reac_inst): obj = self.species.reac_obj[index] instance_name = obj.instance_name # START REATION SEARCH if self.species.reac_ts_done[ index] == 0 and self.species.reac_step[index] == 0: #verify after restart if search has failed in previous kinbot run status = self.qc.check_qc(instance_name) if status == 'error' or status == 'killed': logging.info( '\tRxn search failed (error or killed) for {}'. format(instance_name)) self.species.reac_ts_done[index] = -999 if self.species.reac_ts_done[ index] == 0: # ts search is ongoing if obj.scan == 0: #don't do a scan of a bond if self.species.reac_step[index] == obj.max_step + 1: status = self.qc.get_qc_freq( instance_name, self.species.natom)[0] if status == 0: self.species.reac_ts_done[index] = 1 elif status == -1: logging.info( '\tRxn search failed for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par.par['qc_command']) else: # do a bond scan if self.species.reac_step[ index] == self.par.par['scan_step'] + 1: status = self.qc.get_qc_freq( instance_name, self.species.natom)[0] if status == 0: self.species.reac_ts_done[index] = 1 elif status == -1: logging.info( '\tRxn search failed for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: if self.species.reac_step[index] == 0: self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par.par['qc_command']) elif self.species.reac_step[index] > 0: status = self.qc.check_qc(instance_name) if status == 'error' or status == 'killed': logging.info( '\tRxn search failed for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: err, energy = self.qc.get_qc_energy( instance_name) if err == 0: self.species.reac_scan_energy[ index].append(energy) if len(self.species. reac_scan_energy[index]) > 1: if self.species.reac_scan_energy[ index][ -1] < self.species.reac_scan_energy[ index][-2]: self.species.reac_step[ index] = self.par.par[ 'scan_step'] self.species.reac_step[ index] = reac_family.carry_out_reaction( obj, self.species.reac_step[index], self.par.par['qc_command']) elif self.species.reac_ts_done[index] == 1: status = self.qc.check_qc(instance_name) if status == 'running': continue elif status == 'error': logging.info( '\tRxn search failed (gaussian error) for {}'. format(instance_name)) self.species.reac_ts_done[index] = -999 else: #check the barrier height: if self.species.reac_type[ index] == 'R_Addition_MultipleBond': sp_energy = self.qc.get_qc_energy( str(self.species.chemid) + '_well_mp2')[1] barrier = (self.qc.get_qc_energy(instance_name)[1] - sp_energy) * constants.AUtoKCAL else: sp_energy = self.qc.get_qc_energy( str(self.species.chemid) + '_well')[1] barrier = (self.qc.get_qc_energy(instance_name)[1] - sp_energy) * constants.AUtoKCAL if barrier > self.par.par['barrier_threshold']: logging.info( '\tRxn barrier too high ({val}) for {name}'. format(val=barrier, name=instance_name)) self.species.reac_ts_done[index] = -999 else: obj.irc = IRC( obj, self.par ) #TODO: this doesn't seem like a good design irc_status = obj.irc.check_irc() if 0 in irc_status: # No IRC started yet, start the IRC now logging.info( '\tStarting IRC calculations for {}'. format(instance_name)) obj.irc.do_irc_calculations() elif irc_status[0] == 'running' or irc_status[ 1] == 'running': continue else: #IRC's have succesfully finished, have an error or were killed, in any case #read the geometries and try to make products out of them #verify which of the ircs leads back to the reactant, if any prod = obj.irc.irc2stationary_pt() if prod == 0: logging.info( '\t\tNo product found for {}'.format( instance_name)) self.species.reac_ts_done[index] = -999 else: #IRC's are done obj.products = prod obj.product_bonds = prod.bond self.species.reac_ts_done[index] = 2 elif self.species.reac_ts_done[index] == 2: #identify bimolecular products and wells fragments, maps = obj.products.start_multi_molecular() obj.products = [] for i, frag in enumerate(fragments): obj.products.append(frag) self.qc.qc_opt(frag, frag.geom) self.species.reac_ts_done[index] = 3 elif self.species.reac_ts_done[index] == 3: #wait for the optimization to finish err = 0 for st_pt in obj.products: chemid = st_pt.chemid orig_geom = copy.deepcopy(st_pt.geom) e, st_pt.geom = self.qc.get_qc_geom( str(st_pt.chemid) + '_well', st_pt.natom) if e < 0: logging.info( '\tProduct optimization failed for {}, product {}' .format(instance_name, st_pt.chemid)) self.species.reac_ts_done[index] = -999 err = -1 elif e != 0: err = -1 else: e2, st_pt.energy = self.qc.get_qc_energy( str(st_pt.chemid) + '_well') e2, st_pt.zpe = self.qc.get_qc_zpe( str(st_pt.chemid) + '_well') st_pt.bond_mx() st_pt.characterize( 0) # not allowed to use the dimer option here st_pt.calc_chemid() if chemid != st_pt.chemid: # product was optimized to another structure, give warning and remove this reaction logging.info( '\tProduct optimizatied to other structure for {}, product {} to {}' .format(instance_name, chemid, st_pt.chemid)) self.species.reac_ts_done[index] = -999 err = -1 if err == 0: self.species.reac_ts_done[index] = 4 elif self.species.reac_ts_done[index] == 4: # Do the TS and product optimization #make a stationary point object of the ts bond_mx = np.zeros( (self.species.natom, self.species.natom), dtype=int) for i in range(self.species.natom): for j in range(self.species.natom): bond_mx[i][j] = max(self.species.bond[i][j], obj.product_bonds[i][j]) err, geom = self.qc.get_qc_geom(instance_name, self.species.natom) ts = StationaryPoint(instance_name, self.species.charge, self.species.mult, atom=self.species.atom, geom=geom, wellorts=1) err, ts.energy = self.qc.get_qc_energy(instance_name) err, ts.zpe = self.qc.get_qc_zpe(instance_name) ts.bond = bond_mx ts.find_cycle() ts.find_conf_dihedral() obj.ts = ts #do the ts optimization obj.ts_opt = Optimize(obj.ts, self.par, self.qc) obj.ts_opt.do_optimization() #do the products optimizations for st_pt in obj.products: #check for products of other reactions that are the same as this product #in the case such products are found, use the same Optimize object for both new = 1 for i, inst_i in enumerate(self.species.reac_inst): if not i == index: obj_i = self.species.reac_obj[i] if self.species.reac_ts_done[i] > 3: for j, st_pt_i in enumerate( obj_i.products): if st_pt_i.chemid == st_pt.chemid: if len(obj_i.prod_opt) > j: prod_opt = obj_i.prod_opt[j] new = 0 break if new: prod_opt = Optimize(st_pt, self.par, self.qc) prod_opt.do_optimization() obj.prod_opt.append(prod_opt) self.species.reac_ts_done[index] = 5 elif self.species.reac_ts_done[index] == 5: #check up on the TS and product optimizations opts_done = 1 fails = 0 #check if ts is done if not obj.ts_opt.shir == 1: opts_done = 0 obj.ts_opt.do_optimization() if obj.ts_opt.shigh == -999: fails = 1 for pr_opt in obj.prod_opt: if not pr_opt.shir == 1: opts_done = 0 pr_opt.do_optimization() if pr_opt.shigh == -999: fails = 1 if fails: self.species.reac_ts_done[index] = -999 elif opts_done: self.species.reac_ts_done[index] = 6 elif self.species.reac_ts_done[index] == 6: #Finilize the calculations #continue to PES search in case a new well was found if self.par.par['pes']: #verify if product is monomolecular, and if it is new if len(obj.products) == 1: st_pt = obj.prod_opt[0].species chemid = st_pt.chemid energy = st_pt.energy well_energy = self.species.energy new_barrier_threshold = self.par.par[ 'barrier_threshold'] - ( energy - well_energy) * constants.AUtoKCAL dir = os.path.dirname(os.getcwd()) jobs = open(dir + '/chemids', 'r').read().split('\n') jobs = [ji for ji in jobs] if not str(chemid) in jobs: #this well is new, add it to the jobs while 1: try: #try to open the file and write to it pes.write_input( self.par, obj.products[0], new_barrier_threshold, dir) f = open(dir + '/chemids', 'a') f.write('{}\n'.format(chemid)) f.close() break except IOError: #wait a second and try again time.sleep(1) pass #check for wrong number of negative frequencies neg_freq = 0 for st_pt in obj.products: if any([fi < 0. for fi in st_pt.reduced_freqs]): neg_freq = 1 if any([fi < 0. for fi in obj.ts.reduced_freqs[1:]]): neg_freq = 1 if neg_freq: logging.info('\tFound negative frequency for ' + instance_name) self.species.reac_ts_done[index] = -999 else: #the reaction search is finished self.species.reac_ts_done[ index] = -1 # this is the success code # write a temporary pes input file # remove old xval and im_extent files if os.path.exists('{}_xval.txt'.format( self.species.chemid)): os.remove('{}_xval.txt'.format( self.species.chemid)) if os.path.exists('{}_im_extent.txt'.format( self.species.chemid)): os.remove('{}_im_extent.txt'.format( self.species.chemid)) postprocess.createPESViewerInput( self.species, self.qc, self.par) alldone = 1 for index, instance in enumerate(self.species.reac_inst): if any(self.species.reac_ts_done[i] >= 0 for i in range(len(self.species.reac_inst))): alldone = 1 break else: alldone = 0 # write a small summary while running wr = 1 if wr: f_out = open('kinbot_monitor.out', 'w') for index, instance in enumerate(self.species.reac_inst): f_out.write('{}\t{}\t{}\n'.format( self.species.reac_ts_done[index], self.species.reac_step[index], self.species.reac_obj[index].instance_name)) f_out.close() time.sleep(1) s = [] for index, instance in enumerate(self.species.reac_inst): obj = self.species.reac_obj[index] instance_name = obj.instance_name # Write a summary on the combinatorial exploration if 'combinatorial' in instance_name: s.append('NAME\t' + instance_name) # Write the bonds that were broken and formed s.append('BROKEN_BONDS\t' + '\t'.join('[{}, {}]'.format(re[0], re[1]) for re in obj.reac)) s.append('FORMED_BONDS\t' + '\t'.join('[{}, {}]'.format(pr[0], pr[1]) for pr in obj.prod)) # Populate the ts_bond_lengths dict with the values # of this reaction if self.species.reac_ts_done[index] == -1: for i in range(self.species.natom - 1): for j in range(i + 1, self.species.natom): if self.species.bond[i][j] != obj.product_bonds[i][ j]: if (self.species.bond[i][j] == 0 or obj.product_bonds[i][j] == 0): syms = [] syms.append(self.species.atom[i]) syms.append(self.species.atom[j]) syms = ''.join(sorted(syms)) dist = np.linalg.norm(obj.ts.geom[i] - obj.ts.geom[j]) s.append('TS_BOND_LENGTHS\t{}\t{}'.format( syms, dist)) # write the expected inchis s.append('EXPECTED_INCHIS\t' + '\t'.join(inchi for inchi in obj.prod_inchi)) # get the inchis the reaction found if self.species.reac_ts_done[index] == -1: inchis = obj.get_final_inchis() s.append('FOUND_INCHIS\t' + '\t'.join(inchis)) s.append('\n') with open('combinatorial.txt', 'w') as f: f.write('\n'.join(s) + '\n') logging.info("Reaction generation done!")
def testFrequencies(self): """ Test the frequency calculator based on the hessian by projecting out the translations, external rotations and internal rotations """ # smiles of the speciesdata smi = 'CCCC' # geometry of the species geom = [[0.91879892, -0.04331223, 0.12849174], [0.40326992, 1.40563299, 0.15982756], [0.89480303, 2.27635373, -1.01612317], [0.37978671, 1.82281002, -2.39283836], [0.56484506, -0.58104398, -0.75857814], [0.58013979, -0.60154787, 1.00923604], [2.01620768, -0.06868878, 0.11831706], [-0.69710354, 1.40285362, 0.16867873], [0.71679336, 1.87619548, 1.10252902], [0.58079101, 3.31524962, -0.84143554], [1.99516746, 2.28446562, -1.02104071], [-0.71762425, 1.80824531, -2.41526122], [0.72083567, 2.50053168, -3.18429864], [0.73195359, 0.81628395, -2.64600957]] geom = np.array(geom) # hessian matrix hess = [ [ 0.557479281000, 0.036110582900, -0.001644922990, -0.094996623900, 0.033793056500, 0.001227901360, 0.004435637720, -0.010301447300, -0.000714141524, -0.000402278745, 0.000207775781, 0.000217081305, -0.079155177000, -0.041443873100, -0.069861527200, -0.075582477100, -0.041043274800, 0.066112977000, -0.304832510000, 0.000618737475, 0.001591972160, -0.011587172100, 0.035782319500, 0.001443997110, 0.003566576500, -0.009402669700, -0.000876604471, -0.000457712074, -0.002463678640, 0.002595980330, 0.000811779351, -0.001430576500, 0.000032881273, 0.000129362928, -0.000033252298, 0.000111660638, 0.000157802640, -0.000276891050, 0.000074700177, 0.000433511158, -0.000116808738, -0.000311955226 ], [ 0.036110582900, 0.481460445000, -0.001497124110, 0.032529383300, -0.168787802000, -0.006867396700, 0.006092748400, -0.023937567300, 0.003730351660, -0.000262084184, 0.001441647380, 0.000316178114, -0.041989591900, -0.107986603000, -0.100880979000, -0.041503733500, -0.111783765000, 0.104729927000, 0.001080107490, -0.048474562500, -0.000241263827, -0.000265123753, -0.003449223290, -0.000371820596, 0.007618533730, -0.018717902300, 0.000837312337, -0.000555734072, -0.000078154904, 0.001999374050, 0.000646690960, 0.001260483370, -0.001360417570, 0.000088413780, -0.000085577196, 0.000164034911, -0.000076331932, -0.000238612455, -0.000622223468, 0.000486138870, -0.000622805294, 0.000064046666 ], [ -0.001644922990, -0.001497124110, 0.575851102000, 0.001964210840, -0.005551021620, -0.083609101600, -0.009286228620, 0.027728004900, 0.001373639180, -0.000137246872, 0.000910607647, 0.001051929890, -0.069899107500, -0.100194460000, -0.221142958000, 0.066308541300, 0.103907569000, -0.219256026000, 0.001583703380, -0.000080359730, -0.050839140900, -0.000325149456, 0.000352021138, 0.000321544325, 0.010807393200, -0.028918001700, -0.000253208170, 0.001475456680, 0.004079204780, -0.004016767400, -0.000771004699, -0.000846365220, 0.001019809380, -0.000285363620, 0.000091087635, -0.000075059137, -0.000051358279, -0.000192607794, 0.000123367411, 0.000261076583, 0.000211445408, -0.000549130393 ], [ -0.094996623900, 0.032529383300, 0.001964210840, 0.570648686000, 0.013726467600, 0.029803019800, -0.093894628800, -0.017540296600, 0.025240052300, 0.004430547620, 0.007089239030, -0.008470974800, 0.003985664600, -0.011160808500, -0.000344880024, 0.003352509560, -0.011319168200, -0.000141509338, -0.012312369900, 0.035615059900, 0.001341132350, -0.296633947000, -0.002814851200, -0.001857303680, -0.074252517800, -0.032055118900, -0.063305094900, 0.003016262880, 0.007165737430, -0.008147262180, -0.013171250400, -0.021050691300, 0.028389638100, 0.000515556167, 0.000833930927, -0.001531483210, -0.000733957654, -0.000834470892, -0.003543541800, 0.000046069520, -0.000184412716, 0.000603996490 ], [ 0.033793056500, -0.168787802000, -0.005551021620, 0.013726467600, 0.471256701000, 0.045550224600, -0.019055559200, -0.110456357000, 0.036788918500, 0.003690246720, 0.008042833690, -0.005946132620, 0.007450531200, -0.016991805700, 0.000566738577, 0.007662075620, -0.017473385800, -0.003434017560, -0.000361925575, -0.003081819410, 0.000169600942, -0.002141608270, -0.048419727000, -0.001543381080, -0.032001313400, -0.092648760200, -0.091748171900, -0.012965805500, -0.019490702300, 0.027544257800, 0.000385145313, -0.001607085100, 0.002202751810, 0.000097042391, 0.000342026851, -0.000085156640, -0.000935724242, -0.000536578498, -0.003946142400, 0.000657370855, -0.000147538049, -0.000568468443 ], [ 0.001227901360, -0.006867396700, -0.083609101600, 0.029803019800, 0.045550224600, 0.530185827000, 0.024067639100, 0.038254723800, -0.133557501000, 0.009656895150, 0.018083768400, -0.030339996500, 0.011176997800, -0.027940521700, 0.000197610447, -0.010718813500, 0.027683119400, 0.001610715360, -0.000005380242, 0.000353950668, -0.000058645732, -0.001385963250, -0.001490240310, -0.050945021400, -0.064025490200, -0.091980721200, -0.231554605000, -0.000068702298, -0.003001675120, 0.001414867140, 0.000375944632, 0.002432713030, -0.002619663450, 0.000967738003, 0.000578480710, 0.002131790000, -0.001665661510, -0.002059701750, -0.003910908180, 0.000593875240, 0.000403276118, 0.001054632250 ], [ 0.004435637720, 0.006092748400, -0.009286228620, -0.093894628800, -0.019055559200, 0.024067639100, 0.570900497000, -0.032595232800, -0.004232877500, -0.095277421800, -0.011406581600, -0.030607826800, 0.000043159915, -0.000514838503, 0.000373962854, -0.000738247952, 0.003637838290, -0.000237140037, 0.000536641625, 0.001192182950, -0.001206594120, -0.013027642100, -0.020980119300, 0.028551488200, 0.003004879320, 0.005695987090, -0.009218334250, -0.074383197800, 0.070019040800, 0.012170299900, -0.296727831000, 0.002527681320, 0.001997681770, -0.012251640800, -0.011694206300, -0.033682439000, 0.003373175160, 0.003467893310, 0.010833941000, 0.004006619800, 0.003613165550, 0.010476427500 ], [ -0.010301447300, -0.023937567300, 0.027728004900, -0.017540296600, -0.110456357000, 0.038254723800, -0.032595232800, 0.550390617000, 0.021569897200, -0.011111359900, -0.094250354100, -0.029239287500, -0.000711297419, 0.000972151769, 0.000156692325, 0.001860692500, -0.005293631350, -0.000606360776, -0.000954457648, 0.002153894160, 0.000019371190, -0.000397838529, -0.001228430010, 0.002336752460, 0.003859667870, 0.006484974130, -0.010940182100, 0.070740800200, -0.270987312000, -0.037645349500, 0.001896728730, -0.051464188100, -0.000592835086, 0.000107061175, -0.000144181197, -0.000504021609, 0.007980792090, 0.006761052700, 0.020233362800, -0.012833812400, -0.009000668610, -0.030770768100 ], [ -0.000714141524, 0.003730351660, 0.001373639180, 0.025240052300, 0.036788918500, -0.133557501000, -0.004232877500, 0.021569897200, 0.451154731000, -0.032090962200, -0.028197579400, -0.158290659000, -0.000492084585, -0.000980152816, 0.000034862639, 0.000407801351, -0.002484344690, 0.000853888771, 0.000202037882, -0.000630194064, 0.000364010457, -0.000276661410, 0.002092844910, -0.002923760270, 0.012375619200, 0.019611685600, -0.024571878400, 0.011914527900, -0.037319661200, -0.053342229400, 0.001505776140, -0.000642112942, -0.047826423400, 0.000374606934, -0.000789448823, -0.002922212160, -0.010438695000, -0.010818867900, -0.022572722700, -0.003774999570, -0.001931336020, -0.007773745060 ], [ -0.000402278745, -0.000262084184, -0.000137246872, 0.004430547620, 0.003690246720, 0.009656895150, -0.095277421800, -0.011111359900, -0.032090962200, 0.558209213000, -0.009125619780, -0.034709539800, 0.000415340383, 0.000358171193, 0.000000905828, 0.000159128422, 0.000009821173, 0.000284856041, 0.000131990037, -0.000097828362, 0.000069311231, 0.000786266725, 0.000375904422, 0.001427105050, -0.000456009865, -0.001763774920, 0.003115461590, 0.003579063430, 0.003594264790, 0.008763686330, -0.011547639900, -0.011824677300, -0.033753097500, -0.305000167000, -0.001072859680, -0.000565352953, -0.076013943900, -0.051443542800, 0.058887756100, -0.079014088600, 0.078673338600, 0.019050222000 ], [ 0.000207775781, 0.001441647380, 0.000910607647, 0.007089239030, 0.008042833690, 0.018083768400, -0.011406581600, -0.094250354100, -0.028197579400, -0.009125619780, 0.566853551000, -0.028314924300, -0.000405813331, -0.000316988707, 0.000087265018, 0.000073046030, -0.000135428465, -0.000227947707, 0.000240096907, -0.000003210597, 0.000052913364, 0.000562715807, 0.000386702658, -0.000586865840, -0.001249462100, -0.001984311450, 0.004661147410, -0.012569365100, -0.009659129560, -0.031620324000, 0.000388942723, -0.000027569785, -0.000685633791, -0.001195716590, -0.050831902500, 0.000607484566, -0.051498752000, -0.151306241000, 0.115957274000, 0.078889494300, -0.268209599000, -0.050727185300 ], [ 0.000217081305, 0.000316178114, 0.001051929890, -0.008470974800, -0.005946132620, -0.030339996500, -0.030607826800, -0.029239287500, -0.158290659000, -0.034709539800, -0.028314924300, 0.489796505000, -0.000391829054, 0.000142067560, -0.000688267160, 0.000058546643, -0.000657571583, 0.000021899914, -0.000169145634, 0.000141233266, -0.000156069524, -0.000870684066, -0.001083763300, 0.001824089140, 0.000966571121, 0.002585026930, -0.002110201450, -0.004138394740, -0.001918643950, -0.009243037780, 0.000150249840, -0.001426379210, -0.003164852780, -0.000834451580, 0.000361231775, -0.048518990600, 0.059364188600, 0.116743826000, -0.179560342000, 0.019436209100, -0.051702861200, -0.060622006300 ], [ -0.079155177000, -0.041989591900, -0.069899107500, 0.003985664600, 0.007450531200, 0.011176997800, 0.000043159915, -0.000711297419, -0.000492084585, 0.000415340383, -0.000405813331, -0.000391829054, 0.082170568700, 0.043883239500, 0.078044112600, 0.003495229520, 0.005401929110, 0.009954809490, -0.011350612800, -0.016458449400, -0.029453532500, 0.000665737135, -0.000625010895, 0.000511858440, 0.000059291070, 0.003007766240, 0.000159750828, -0.000060170797, -0.000108422372, 0.000205866966, 0.000026998545, -0.000052468999, -0.000060908234, -0.000223489041, 0.000140719611, -0.000038210872, -0.000144869281, 0.000150427844, 0.000065183444, 0.000072328995, 0.000316440754, 0.000217093184 ], [ -0.041443873100, -0.107986603000, -0.100194460000, -0.011160808500, -0.016991805700, -0.027940521700, -0.000514838503, 0.000972151769, -0.000980152816, 0.000358171193, -0.000316988707, 0.000142067560, 0.043883239500, 0.119840850000, 0.111814261000, 0.005906654280, 0.008066891770, 0.014503839500, 0.000290968064, -0.000150240230, 0.000002063185, 0.000111922593, 0.001514337600, 0.000276003926, 0.002702457800, -0.005775080730, 0.000445401249, 0.000111932829, 0.000347388012, 0.000177052371, -0.000006786294, -0.000145911482, 0.000108411307, 0.000058268378, -0.000061770157, 0.000096427007, -0.000010851744, 0.000535119260, 0.000099909733, -0.000286456542, 0.000151661591, 0.001449697830 ], [ -0.069861527200, -0.100880979000, -0.221142958000, -0.000344880024, 0.000566738577, 0.000197610447, 0.000373962854, 0.000156692325, 0.000034862639, 0.000000905828, 0.000087265018, -0.000688267160, 0.078044112600, 0.111814261000, 0.242817300000, -0.010493946400, -0.013936543100, -0.022850703000, 0.001401288830, 0.000811652521, 0.000387534637, 0.000611035395, -0.000326880526, 0.000202559149, 0.000448151560, 0.000430071969, 0.001316161050, -0.000015506148, -0.000226147940, 0.000124908040, 0.000053325603, 0.000066745555, -0.000005338059, 0.000029804814, -0.000043582456, -0.000002800832, 0.000036585620, 0.000161681863, 0.000229922299, -0.000283313413, 0.001319024070, -0.000620791338 ], [ -0.075582477100, -0.041503733500, 0.066308541300, 0.003352509560, 0.007662075620, -0.010718813500, -0.000738247952, 0.001860692500, 0.000407801351, 0.000159128422, 0.000073046030, 0.000058546643, 0.003495229520, 0.005906654280, -0.010493946400, 0.078647598400, 0.043929663400, -0.073931943100, -0.010722735000, -0.017236570000, 0.029041201600, 0.000394715293, -0.000537710690, -0.000362268343, 0.000241854679, -0.000788101770, 0.000060932686, 0.000467445735, 0.000365561370, -0.000302900477, 0.000423918964, 0.000300000013, -0.000134663171, 0.000006452519, -0.000023320384, 0.000023532240, -0.000000863259, 0.000025535986, 0.000019870589, -0.000144529814, -0.000033792868, 0.000024108483 ], [ -0.041043274800, -0.111783765000, 0.103907569000, -0.011319168200, -0.017473385800, 0.027683119400, 0.003637838290, -0.005293631350, -0.002484344690, 0.000009821173, -0.000135428465, -0.000657571583, 0.005401929110, 0.008066891770, -0.013936543100, 0.043929663400, 0.124958213000, -0.115530393000, 0.000325281332, -0.000125007354, -0.000129258723, 0.000384143980, 0.001259101570, 0.000001306272, -0.000870123215, 0.001042362100, -0.000426380057, -0.000426090514, -0.001300320690, 0.001591298870, 0.000048406439, 0.000287275840, -0.000388354266, 0.000055737630, 0.000018935809, 0.000059096657, -0.000026671850, 0.000148561268, 0.000149502306, -0.000107492816, 0.000330197117, 0.000160952609 ], [ 0.066112977000, 0.104729927000, -0.219256026000, -0.000141509338, -0.003434017560, 0.001610715360, -0.000237140037, -0.000606360776, 0.000853888771, 0.000284856041, -0.000227947707, 0.000021899914, 0.009954809490, 0.014503839500, -0.022850703000, -0.073931943100, -0.115530393000, 0.238426713000, -0.001172378760, -0.000473740575, -0.000085975425, -0.000598006922, 0.000347859264, -0.000022101354, -0.000104883229, 0.000359811438, 0.000893666466, 0.000047613768, -0.000039210588, -0.000025405264, 0.000008736166, -0.000126420940, -0.000048007771, -0.000081103354, 0.000034200394, 0.000014479678, -0.000018292858, 0.000237094498, 0.000030248075, -0.000123734870, 0.000225358158, 0.000436607680 ], [ -0.304832510000, 0.001080107490, 0.001583703380, -0.012312369900, -0.000361925575, -0.000005380242, 0.000536641625, -0.000954457648, 0.000202037882, 0.000131990037, 0.000240096907, -0.000169145634, -0.011350612800, 0.000290968064, 0.001401288830, -0.010722735000, 0.000325281332, -0.001172378760, 0.335968234000, -0.003796974450, -0.002196966940, 0.001014683130, 0.002301249850, 0.000503015956, 0.000603465592, 0.000253289215, 0.000532380180, 0.000412280046, -0.000005518885, -0.000002154967, 0.000632261852, 0.000727256027, -0.000699875116, 0.000142228293, -0.000106601886, 0.000148869356, 0.000006913742, 0.000060554518, -0.000076997589, -0.000230470931, -0.000053324956, -0.000048396325 ], [ 0.000618737475, -0.048474562500, -0.000080359730, 0.035615059900, -0.003081819410, 0.000353950668, 0.001192182950, 0.002153894160, -0.000630194064, -0.000097828362, -0.000003210597, 0.000141233266, -0.016458449400, -0.000150240230, 0.000811652521, -0.017236570000, -0.000125007354, -0.000473740575, -0.003796974450, 0.054324381900, 0.000328044615, 0.002236943710, -0.006269973860, -0.000090077542, -0.000556919926, 0.001404142770, -0.000144097996, -0.000333527294, 0.000376518698, -0.000398408893, -0.001046966920, -0.000163879470, 0.000271078925, -0.000111873714, -0.000047084158, -0.000192239409, -0.000015838536, 0.000041274254, 0.000051844795, -0.000007975487, 0.000015565803, 0.000051313421 ], [ 0.001591972160, -0.000241263827, -0.050839140900, 0.001341132350, 0.000169600942, -0.000058645732, -0.001206594120, 0.000019371190, 0.000364010457, 0.000069311231, 0.000052913364, -0.000156069524, -0.029453532500, 0.000002063185, 0.000387534637, 0.029041201600, -0.000129258723, -0.000085975425, -0.002196966940, 0.000328044615, 0.049536269700, 0.000009025212, -0.000188391390, 0.000859989334, 0.000485598736, 0.000167091798, -0.000050893837, 0.000128473971, -0.000065137481, -0.000104352963, 0.000159767814, 0.000051678617, 0.000154467411, 0.000145393609, -0.000107573025, 0.000044588785, 0.000030151342, 0.000025660583, -0.000005990485, -0.000144934523, -0.000084799847, -0.000045791452 ], [ -0.011587172100, -0.000265123753, -0.000325149456, -0.296633947000, -0.002141608270, -0.001385963250, -0.013027642100, -0.000397838529, -0.000276661410, 0.000786266725, 0.000562715807, -0.000870684066, 0.000665737135, 0.000111922593, 0.000611035395, 0.000394715293, 0.000384143980, -0.000598006922, 0.001014683130, 0.002236943710, 0.000009025212, 0.327078658000, 0.001908306410, -0.000098643877, -0.011211103000, -0.000096625978, 0.000161794067, 0.000445774654, -0.000675251910, -0.000001994717, 0.000919513287, -0.001690768780, 0.001598510130, 0.000698874397, 0.000144489938, 0.001199897110, 0.000425109666, -0.000023343949, -0.000045138440, 0.000030532015, -0.000057961271, 0.000021980223 ], [ 0.035782319500, -0.003449223290, 0.000352021138, -0.002814851200, -0.048419727000, -0.001490240310, -0.020980119300, -0.001228430010, 0.002092844910, 0.000375904422, 0.000386702658, -0.001083763300, -0.000625010895, 0.001514337600, -0.000326880526, -0.000537710690, 0.001259101570, 0.000347859264, 0.002301249850, -0.006269973860, -0.000188391390, 0.001908306410, 0.057676638400, -0.002012297070, -0.015037876400, -0.000231322031, -0.000293743748, 0.000076710051, 0.000337089674, -0.000732923797, -0.001033320970, -0.001677935690, 0.003357378420, 0.000462630311, 0.000228833858, 0.000196170553, 0.000041609570, -0.000164615301, -0.000252036680, 0.000080159392, 0.000038523433, 0.000034002544 ], [ 0.001443997110, -0.000371820596, 0.000321544325, -0.001857303680, -0.001543381080, -0.050945021400, 0.028551488200, 0.002336752460, -0.002923760270, 0.001427105050, -0.000586865840, 0.001824089140, 0.000511858440, 0.000276003926, 0.000202559149, -0.000362268343, 0.000001306272, -0.000022101354, 0.000503015956, -0.000090077542, 0.000859989334, -0.000098643877, -0.002012297070, 0.053996240600, -0.030319186800, -0.000675798642, -0.000572841147, -0.000653076701, -0.000463440047, 0.000816895682, 0.002084942010, 0.003132456320, -0.003659014380, -0.000911429020, -0.000039664076, -0.000139936846, -0.000326542275, 0.000011716933, 0.000402783060, 0.000006043879, 0.000025108980, -0.000161425910 ], [ 0.003566576500, 0.007618533730, 0.010807393200, -0.074252517800, -0.032001313400, -0.064025490200, 0.003004879320, 0.003859667870, 0.012375619200, -0.000456009865, -0.001249462100, 0.000966571121, 0.000059291070, 0.002702457800, 0.000448151560, 0.000241854679, -0.000870123215, -0.000104883229, 0.000603465592, -0.000556919926, 0.000485598736, -0.011211103000, -0.015037876400, -0.030319186800, 0.076908890300, 0.034393823600, 0.069678815000, 0.000280541835, 0.000499146782, -0.000714739428, 0.000437960626, 0.000608390526, -0.000262541603, 0.000410586032, -0.000025447089, 0.000355884856, 0.000467119865, 0.000078313296, 0.000422103376, -0.000061535147, -0.000019191454, -0.000113295827 ], [ -0.009402669700, -0.018717902300, -0.028918001700, -0.032055118900, -0.092648760200, -0.091980721200, 0.005695987090, 0.006484974130, 0.019611685600, -0.001763774920, -0.001984311450, 0.002585026930, 0.003007766240, -0.005775080730, 0.000430071969, -0.000788101770, 0.001042362100, 0.000359811438, 0.000253289215, 0.001404142770, 0.000167091798, -0.000096625978, -0.000231322031, -0.000675798642, 0.034393823600, 0.108705444000, 0.098282383300, 0.000536535704, 0.001045616250, -0.000233377753, 0.000197842819, 0.000436602581, -0.000746827584, 0.000002929675, -0.000191975080, -0.000225290437, 0.000183020208, 0.000300248641, 0.001103529870, -0.000164903323, 0.000129961184, 0.000240416270 ], [ -0.000876604471, 0.000837312337, -0.000253208170, -0.063305094900, -0.091748171900, -0.231554605000, -0.009218334250, -0.010940182100, -0.024571878400, 0.003115461590, 0.004661147410, -0.002110201450, 0.000159750828, 0.000445401249, 0.001316161050, 0.000060932686, -0.000426380057, 0.000893666466, 0.000532380180, -0.000144097996, -0.000050893837, 0.000161794067, -0.000293743748, -0.000572841147, 0.069678815000, 0.098282383300, 0.256012547000, -0.000695797842, 0.000405605652, 0.000999258380, 0.000659004856, -0.000503505707, 0.000708239491, 0.000002552083, 0.000110082904, 0.000462709809, -0.000439580294, -0.000527497416, -0.001625311350, 0.000164720405, -0.000158353984, 0.000346357198 ], [ -0.000457712074, -0.000555734072, 0.001475456680, 0.003016262880, -0.012965805500, -0.000068702298, -0.074383197800, 0.070740800200, 0.011914527900, 0.003579063430, -0.012569365100, -0.004138394740, -0.000060170797, 0.000111932829, -0.000015506148, 0.000467445735, -0.000426090514, 0.000047613768, 0.000412280046, -0.000333527294, 0.000128473971, 0.000445774654, 0.000076710051, -0.000653076701, 0.000280541835, 0.000536535704, -0.000695797842, 0.077003315500, -0.076817039100, -0.012542197900, -0.011205602800, 0.033354294600, 0.005531828340, 0.000601743047, -0.000294036321, 0.000670043314, 0.000236669508, 0.000359711857, 0.000799593785, 0.000063586822, -0.001218387310, -0.002453862220 ], [ -0.002463678640, -0.000078154904, 0.004079204780, 0.007165737430, -0.019490702300, -0.003001675120, 0.070019040800, -0.270987312000, -0.037319661200, 0.003594264790, -0.009659129560, -0.001918643950, -0.000108422372, 0.000347388012, -0.000226147940, 0.000365561370, -0.001300320690, -0.000039210588, -0.000005518885, 0.000376518698, -0.000065137481, -0.000675251910, 0.000337089674, -0.000463440047, 0.000499146782, 0.001045616250, 0.000405605652, -0.076817039100, 0.298274531000, 0.040406725300, -0.000136212824, -0.000795615621, -0.000114897060, -0.000586260703, 0.000093614097, 0.000252036708, 0.000174692057, 0.000878659823, -0.000383102689, -0.001026058750, 0.000957816966, -0.001611656380 ], [ 0.002595980330, 0.001999374050, -0.004016767400, -0.008147262180, 0.027544257800, 0.001414867140, 0.012170299900, -0.037645349500, -0.053342229400, 0.008763686330, -0.031620324000, -0.009243037780, 0.000205866966, 0.000177052371, 0.000124908040, -0.000302900477, 0.001591298870, -0.000025405264, -0.000002154967, -0.000398408893, -0.000104352963, -0.000001994717, -0.000732923797, 0.000816895682, -0.000714739428, -0.000233377753, 0.000999258380, -0.012542197900, 0.040406725300, 0.066461670300, 0.000111476779, -0.000463310086, -0.000005613339, -0.000083374773, 0.000585667105, 0.001289783720, 0.000768879885, 0.000408824903, 0.001044358070, -0.002821565820, -0.001619506420, -0.005414335160 ], [ 0.000811779351, 0.000646690960, -0.000771004699, -0.013171250400, 0.000385145313, 0.000375944632, -0.296727831000, 0.001896728730, 0.001505776140, -0.011547639900, 0.000388942723, 0.000150249840, 0.000026998545, -0.000006786294, 0.000053325603, 0.000423918964, 0.000048406439, 0.000008736166, 0.000632261852, -0.001046966920, 0.000159767814, 0.000919513287, -0.001033320970, 0.002084942010, 0.000437960626, 0.000197842819, 0.000659004856, -0.011205602800, -0.000136212824, 0.000111476779, 0.327319130000, -0.000522519027, -0.001747096940, 0.001019228930, -0.000665600374, -0.002131478270, 0.000410888095, 0.000459443519, -0.000527224047, 0.000650645014, -0.000611794096, 0.000067580103 ], [ -0.001430576500, 0.001260483370, -0.000846365220, -0.021050691300, -0.001607085100, 0.002432713030, 0.002527681320, -0.051464188100, -0.000642112942, -0.011824677300, -0.000027569785, -0.001426379210, -0.000052468999, -0.000145911482, 0.000066745555, 0.000300000013, 0.000287275840, -0.000126420940, 0.000727256027, -0.000163879470, 0.000051678617, -0.001690768780, -0.001677935690, 0.003132456320, 0.000608390526, 0.000436602581, -0.000503505707, 0.033354294600, -0.000795615621, -0.000463310086, -0.000522519027, 0.053211548800, -0.000605423301, -0.001149055730, 0.000174592071, -0.002056008930, 0.000508508927, 0.000184012806, 0.000337657158, -0.000305373851, 0.000327669725, 0.000648275660 ], [ 0.000032881273, -0.001360417570, 0.001019809380, 0.028389638100, 0.002202751810, -0.002619663450, 0.001997681770, -0.000592835086, -0.047826423400, -0.033753097500, -0.000685633791, -0.003164852780, -0.000060908234, 0.000108411307, -0.000005338059, -0.000134663171, -0.000388354266, -0.000048007771, -0.000699875116, 0.000271078925, 0.000154467411, 0.001598510130, 0.003357378420, -0.003659014380, -0.000262541603, -0.000746827584, 0.000708239491, 0.005531828340, -0.000114897060, -0.000005613339, -0.001747096940, -0.000605423301, 0.058534733700, -0.002049213140, -0.002165722420, -0.005580464400, 0.000418020512, 0.000671917929, 0.001075125330, 0.000738835582, 0.000048572694, 0.001417002250 ], [ 0.000129362928, 0.000088413780, -0.000285363620, 0.000515556167, 0.000097042391, 0.000967738003, -0.012251640800, 0.000107061175, 0.000374606934, -0.305000167000, -0.001195716590, -0.000834451580, -0.000223489041, 0.000058268378, 0.000029804814, 0.000006452519, 0.000055737630, -0.000081103354, 0.000142228293, -0.000111873714, 0.000145393609, 0.000698874397, 0.000462630311, -0.000911429020, 0.000410586032, 0.000002929675, 0.000002552083, 0.000601743047, -0.000586260703, -0.000083374773, 0.001019228930, -0.001149055730, -0.002049213140, 0.335981374000, 0.002561958750, 0.003297591000, -0.010801126300, 0.001048090670, -0.000668728837, -0.011228983200, -0.001439226010, 0.000095977887 ], [ -0.000033252298, -0.000085577196, 0.000091087635, 0.000833930927, 0.000342026851, 0.000578480710, -0.011694206300, -0.000144181197, -0.000789448823, -0.001072859680, -0.050831902500, 0.000361231775, 0.000140719611, -0.000061770157, -0.000043582456, -0.000023320384, 0.000018935809, 0.000034200394, -0.000106601886, -0.000047084158, -0.000107573025, 0.000144489938, 0.000228833858, -0.000039664076, -0.000025447089, -0.000191975080, 0.000110082904, -0.000294036321, 0.000093614097, 0.000585667105, -0.000665600374, 0.000174592071, -0.002165722420, 0.002561958750, 0.050149008600, 0.001623164620, -0.022680777200, -0.000201125886, -0.000105607558, 0.032915002300, 0.000556604861, -0.000132316779 ], [ 0.000111660638, 0.000164034911, -0.000075059137, -0.001531483210, -0.000085156640, 0.002131790000, -0.033682439000, -0.000504021609, -0.002922212160, -0.000565352953, 0.000607484566, -0.048518990600, -0.000038210872, 0.000096427007, -0.000002800832, 0.000023532240, 0.000059096657, 0.000014479678, 0.000148869356, -0.000192239409, 0.000044588785, 0.001199897110, 0.000196170553, -0.000139936846, 0.000355884856, -0.000225290437, 0.000462709809, 0.000670043314, 0.000252036708, 0.001289783720, -0.002131478270, -0.002056008930, -0.005580464400, 0.003297591000, 0.001623164620, 0.053631786900, 0.024986835900, -0.000480266327, 0.000069007009, 0.007154649910, 0.000544568335, -0.000404681882 ], [ 0.000157802640, -0.000076331932, -0.000051358279, -0.000733957654, -0.000935724242, -0.001665661510, 0.003373175160, 0.007980792090, -0.010438695000, -0.076013943900, -0.051498752000, 0.059364188600, -0.000144869281, -0.000010851744, 0.000036585620, -0.000000863259, -0.000026671850, -0.000018292858, 0.000006913742, -0.000015838536, 0.000030151342, 0.000425109666, 0.000041609570, -0.000326542275, 0.000467119865, 0.000183020208, -0.000439580294, 0.000236669508, 0.000174692057, 0.000768879885, 0.000410888095, 0.000508508927, 0.000418020512, -0.010801126300, -0.022680777200, 0.024986835900, 0.079112534200, 0.058103695900, -0.063986801200, 0.003504547540, 0.008252628830, -0.008677730390 ], [ -0.000276891050, -0.000238612455, -0.000192607794, -0.000834470892, -0.000536578498, -0.002059701750, 0.003467893310, 0.006761052700, -0.010818867900, -0.051443542800, -0.151306241000, 0.116743826000, 0.000150427844, 0.000535119260, 0.000161681863, 0.000025535986, 0.000148561268, 0.000237094498, 0.000060554518, 0.000041274254, 0.000025660583, -0.000023343949, -0.000164615301, 0.000011716933, 0.000078313296, 0.000300248641, -0.000527497416, 0.000359711857, 0.000878659823, 0.000408824903, 0.000459443519, 0.000184012806, 0.000671917929, 0.001048090670, -0.000201125886, -0.000480266327, 0.058103695900, 0.163615200000, -0.127320828000, -0.011175418200, -0.020016956200, 0.023139046100 ], [ 0.000074700177, -0.000622223468, 0.000123367411, -0.003543541800, -0.003946142400, -0.003910908180, 0.010833941000, 0.020233362800, -0.022572722700, 0.058887756100, 0.115957274000, -0.179560342000, 0.000065183444, 0.000099909733, 0.000229922299, 0.000019870589, 0.000149502306, 0.000030248075, -0.000076997589, 0.000051844795, -0.000005990485, -0.000045138440, -0.000252036680, 0.000402783060, 0.000422103376, 0.001103529870, -0.001625311350, 0.000799593785, -0.000383102689, 0.001044358070, -0.000527224047, 0.000337657158, 0.001075125330, -0.000668728837, -0.000105607558, 0.000069007009, -0.063986801200, -0.127320828000, 0.199467764000, -0.002254716580, -0.005303140270, 0.005232700240 ], [ 0.000433511158, 0.000486138870, 0.000261076583, 0.000046069520, 0.000657370855, 0.000593875240, 0.004006619800, -0.012833812400, -0.003774999570, -0.079014088600, 0.078889494300, 0.019436209100, 0.000072328995, -0.000286456542, -0.000283313413, -0.000144529814, -0.000107492816, -0.000123734870, -0.000230470931, -0.000007975487, -0.000144934523, 0.000030532015, 0.000080159392, 0.000006043879, -0.000061535147, -0.000164903323, 0.000164720405, 0.000063586822, -0.001026058750, -0.002821565820, 0.000650645014, -0.000305373851, 0.000738835582, -0.011228983200, 0.032915002300, 0.007154649910, 0.003504547540, -0.011175418200, -0.002254716580, 0.081871766900, -0.087120674300, -0.018952145900 ], [ -0.000116808738, -0.000622805294, 0.000211445408, -0.000184412716, -0.000147538049, 0.000403276118, 0.003613165550, -0.009000668610, -0.001931336020, 0.078673338600, -0.268209599000, -0.051702861200, 0.000316440754, 0.000151661591, 0.001319024070, -0.000033792868, 0.000330197117, 0.000225358158, -0.000053324956, 0.000015565803, -0.000084799847, -0.000057961271, 0.000038523433, 0.000025108980, -0.000019191454, 0.000129961184, -0.000158353984, -0.001218387310, 0.000957816966, -0.001619506420, -0.000611794096, 0.000327669725, 0.000048572694, -0.001439226010, 0.000556604861, 0.000544568335, 0.008252628830, -0.020016956200, -0.005303140270, -0.087120674300, 0.295489566000, 0.058022644000 ], [ -0.000311955226, 0.000064046666, -0.000549130393, 0.000603996490, -0.000568468443, 0.001054632250, 0.010476427500, -0.030770768100, -0.007773745060, 0.019050222000, -0.050727185300, -0.060622006300, 0.000217093184, 0.001449697830, -0.000620791338, 0.000024108483, 0.000160952609, 0.000436607680, -0.000048396325, 0.000051313421, -0.000045791452, 0.000021980223, 0.000034002544, -0.000161425910, -0.000113295827, 0.000240416270, 0.000346357198, -0.002453862220, -0.001611656380, -0.005414335160, 0.000067580103, 0.000648275660, 0.001417002250, 0.000095977887, -0.000132316779, -0.000404681882, -0.008677730390, 0.023139046100, 0.005232700240, -0.018952145900, 0.058022644000, 0.067104607900 ] ] hess = np.array(hess) st_pt = StationaryPoint(smi, 0, 1, smiles=smi) st_pt.characterize() natom = st_pt.natom freq, reduced_freqs = frequencies.get_frequencies(st_pt, hess, geom) # check the number of frequencies when neglecting internal rotors warn = 'Wrong number of frequencies for ' warn += '{}, expected {}, calculated {}'.format( smi, 3 * natom - 6, len(freq)) self.assertEqual(len(freq), 3 * natom - 6, warn) # check the number of freauencies when including internal rotors warn = 'Wrong number of frequencies for ' warn += '{}, expected {}, calculated {}'.format( smi, 3 * natom - 6 - 3, len(reduced_freqs)) self.assertEqual(len(reduced_freqs), 3 * natom - 6 - 3, warn) # check if the frequencies are as expected exps = [ 114.00308362581993, 217.27775429467988, 258.3569949257438, 324.95225959788496, 444.19934314923285, 775.6200599866132, 809.834778642176, 851.31690919327, 978.7594097713534, 1001.6985870040352, 1016.7427610310635, 1110.2892683008433, 1182.5149554411457, 1226.4874456219302, 1318.400582167711, 1338.054870101307, 1396.7770994771845, 1417.5721206176297, 1452.5015242293932, 1460.9939823348343, 1533.7500760993864, 1534.471579819868, 1544.1270899676583, 1549.977599644375, 1552.1602547884133, 1556.1540474667054, 3018.3546194275327, 3020.597688051164, 3036.615370205335, 3039.4844797216215, 3056.030309062557, 3060.954764774267, 3108.0034857725796, 3110.0837061265997, 3114.029978361547, 3121.6966999165047 ] for i, exp in enumerate(exps): warn = 'Frequency values have wrong number: ' warn += 'expected {}, calculated {}'.format(exp, freq[i]) self.assertAlmostEqual(exp, freq[i], places=2, msg=warn) # check if the reduced frequencies are as expected exps = [ 323.2231139328416, 443.06424130022316, 670.1999625377555, 765.4302138965138, 805.4817609384712, 923.6453995768678, 998.4208652995756, 1010.1550075636384, 1026.2590199716992, 1035.9563299669474, 1110.728140649036, 1237.3899533374413, 1297.0701335112522, 1319.639259548847, 1338.4248295874343, 1402.476769356911, 1417.8484347981505, 1476.7358681560938, 1487.8976160436305, 1525.2008164401302, 1544.0032443689747, 1547.12404969892, 1549.9807205743023, 2426.2794467384574, 2507.323795982035, 2864.813636413937, 3024.7798090881265, 3034.7484086579275, 3037.1066584298032, 3052.278595042064, 3107.809971415559, 3113.170533468414, 3113.8054919074493 ] for i, exp in enumerate(exps): warn = 'Frequency values have wrong number: ' warn += 'expected {}, calculated {}'.format(exp, reduced_freqs[i]) self.assertAlmostEqual(exp, reduced_freqs[i], places=2, msg=warn)
def main(): try: input_file = sys.argv[1] except IndexError: print('To use KinBot, supply one argument being the input file!') sys.exit(-1) # print the license message to the console print(license_message.message) # initialize the parameters for this run par = Parameters(input_file) # set up the logging environment if par.par['verbose']: logging.basicConfig(filename='kinbot.log', level=logging.DEBUG) else: logging.basicConfig(filename='kinbot.log', level=logging.INFO) # write the license message to the log file logging.info(license_message.message) # time stamp of the KinBot start logging.info('Starting KinBot at {}'.format(datetime.datetime.now())) # Make the necessary directories if not os.path.exists('perm'): os.makedirs('perm') if not os.path.exists('scratch'): os.makedirs('scratch') if not os.path.exists(par.par['single_point_qc']): os.mkdir(par.par['single_point_qc']) if par.par['rotor_scan'] == 1: if not os.path.exists('hir'): os.mkdir('hir') if not os.path.exists('hir_profiles'): os.mkdir('hir_profiles') if not os.path.exists('perm/hir/'): os.makedirs('perm/hir/') if par.par['conformer_search'] == 1: if not os.path.exists('conf'): os.mkdir('conf') if not os.path.exists('perm/conf'): os.makedirs('perm/conf') if not os.path.exists('me'): os.mkdir('me') if par.par['pes'] and par.par['specific_reaction']: logging.error('Specific reaction cannot be searched in PES mode.') return # initialize the reactant well0 = StationaryPoint('well0', par.par['charge'], par.par['mult'], smiles=par.par['smiles'], structure=par.par['structure']) well0.short_name = 'w1' # wrtie the initial reactant geometry to a file for visualization geom_out = open('geometry.xyz', 'w') geom_out.write('{}\n\n'.format(well0.natom)) for i, at in enumerate(well0.atom): x, y, z = well0.geom[i] geom_out.write('{} {:.6f} {:.6f} {:.6f}\n'.format(at, x, y, z)) geom_out.write('\n\n') geom_out.close() # characterize the initial reactant well0.characterize(par.par['dimer']) well0.name = str(well0.chemid) start_name = well0.name # initialize the qc instance qc = QuantumChemistry(par) # start the initial optimization of the reactant logging.info('Starting optimization of intial well') qc.qc_opt(well0, well0.geom) err, well0.geom = qc.get_qc_geom(str(well0.chemid) + '_well', well0.natom, wait=1) err, well0.freq = qc.get_qc_freq(str(well0.chemid) + '_well', well0.natom, wait=1) if err < 0: logging.error('Error with initial structure optimization.') return if any(well0.freq[i] <= 0 for i in range(len(well0.freq))): logging.error('Found imaginary frequency for initial structure.') return # characterize again and look for differences well0.characterize(par.par['dimer']) well0.name = str(well0.chemid) if well0.name != start_name: logging.error('The first well optimized to a structure different from the input.') return # do an MP2 optimization of the reactant, # to compare Beta scission barrier heigths to logging.info('Starting MP2 optimization of intial well') qc.qc_opt(well0, well0.geom, mp2=1) err, geom = qc.get_qc_geom(str(well0.chemid) + '_well_mp2', well0.natom, 1) # characterize again and look for differences well0.characterize(par.par['dimer']) well0.name = str(well0.chemid) # read the energy and the zpe corrected energy err, well0.energy = qc.get_qc_energy(str(well0.chemid) + '_well', 1) err, well0.zpe = qc.get_qc_zpe(str(well0.chemid) + '_well', 1) well_opt = Optimize(well0, par, qc, wait=1) well_opt.do_optimization() if well_opt.shigh == -999: logging.error('Error with high level optimization of initial structure.') return # do the reaction search using heuristics if par.par['reaction_search'] == 1: logging.info('Starting reaction searches of intial well') rf = ReactionFinder(well0, par, qc) rf.find_reactions() rg = ReactionGenerator(well0, par, qc) rg.generate() # do the homolytic scission products search if par.par['homolytic_scissions'] == 1: logging.info('Starting the search for homolytic scission products') well0.homolytic_scissions = HomolyticScissions(well0, par, qc) well0.homolytic_scissions.find_homolytic_scissions() # initialize the master equation instance mess = MESS(par, well0) mess.write_input() mesmer = MESMER(par, well0) mesmer.write_input() if par.par['me'] == 1: logging.info('Starting Master Equation calculations') if par.par['me_code'] == 'mess': mess.run() elif par.par['me_code'] == 'mesmer': mesmer.run() else: logging.error('Cannot recognize me code {}'.format(par.par['me_code'])) # postprocess the calculations postprocess.createSummaryFile(well0, qc, par) postprocess.createPESViewerInput(well0, qc, par) postprocess.creatMLInput(well0, qc, par) logging.info('Finished KinBot at {}'.format(datetime.datetime.now())) print("Done!")