def test_get_num_atoms(self): molecule = Molecule() # get_num_atoms() should return 0 before any atoms added to molecule self.assertEqual(molecule.get_num_atoms(), 0) fragment0 = Fragment(-1, 2) atom0 = Atom("F", 0, 0, 0) fragment0.add_atom(atom0) molecule.add_fragment(fragment0) # get_num_fragments() should return 1 after 1 atom added to molecule self.assertEqual(molecule.get_num_atoms(), 1) fragment1 = Fragment(-1, 2) atom1 = Atom("F", 0, 0, 3) atom2 = Atom("Cl", 0, 0, 0) fragment1.add_atom(atom1) fragment1.add_atom(atom2) molecule.add_fragment(fragment1) # get_num_fragments() should return 3 after 3 atoms added to molecule self.assertEqual(molecule.get_num_atoms(), 3)
def test_get_atoms(self): molecule = Molecule() # get_atoms() should return list of len 0 before any atoms added to Molecule self.assertEqual(len(molecule.get_atoms()), 0) fragment0 = Fragment(0, 1) atom0 = Atom("H", 0, 0, 0) fragment0.add_atom(atom0) molecule.add_fragment(fragment0) self.assertEqual(molecule.get_atoms()[0], atom0) # get_atoms() should return list of len 1 after 1 atom added to Molecule self.assertEqual(len(molecule.get_atoms()), 1) fragment1 = Fragment(0, 1) atom1 = Atom("H", 0, 0, 0) atom2 = Atom("He", 234, -0.1, 32) atom3 = Atom("He", 34, 43.53, 0) fragment1.add_atom(atom1) fragment1.add_atom(atom2) fragment1.add_atom(atom3) molecule.add_fragment(fragment1) self.assertEqual(molecule.get_atoms()[0], atom0) self.assertEqual(molecule.get_atoms()[1], atom1) self.assertEqual(molecule.get_atoms()[2], atom2) self.assertEqual(molecule.get_atoms()[3], atom3) # get_atoms() should return list of len 4 after 4 atoms added to molecule self.assertEqual(len(molecule.get_atoms()), 4)
def test_add_fragment_and_get_fragments(self): molecule = Molecule() # get_fragments() should return list of len 0 before any fragments added to Molecule self.assertEqual(len(molecule.get_fragments()), 0) fragment0 = Fragment(-3, 2) atom0 = Atom("H", 0, 0, 0) fragment0.add_atom(atom0) molecule.add_fragment(fragment0) self.assertEqual(molecule.get_fragments()[0], fragment0) # get_fragments() should return list of len 1 after 1 fragment added to Molecule self.assertEqual(len(molecule.get_fragments()), 1) fragment1 = Fragment(1, 1) atom1 = Atom("H", 0, 0, 0) atom2 = Atom("He", 234, -0.1, 32) atom3 = Atom("He", 34, 43.53, 0) fragment1.add_atom(atom1) fragment1.add_atom(atom2) fragment1.add_atom(atom3) molecule.add_fragment(fragment1) self.assertEqual(molecule.get_fragments()[0], fragment0) self.assertEqual(molecule.get_fragments()[1], fragment1) # get_fragments() should return list of len 2 after 2 fragments added to Molecule self.assertEqual(len(molecule.get_fragments()), 2)
def get_optimized_energies(self, method, basis, cp, tag): """ Returns a list of pairs of [molecule, energies] where energies is an array of the form [E0, ...] of molecules in the database with the given method, basis, cp and tag and optimized geometries % can be used as a wildcard to stand in for any method, basis, cp, or tag. Args: method - retrieve only energies computed with this method basis - retrieve only energies computed with this basis cp - retrieve only energies computed with this coutnerpoise correction tag - retrieve only energies with this tag Returns: a generator of [molecule, [E0, E1, E2, E01, ...]] pairs from the calculated energies in this database using the given model and tag of optimized geometries """ # get a list of all calculations that have the appropriate method, basis, and cp calculation_ids = [ elements[0] for elements in self.cursor.execute( "SELECT ROWID FROM Calculations WHERE model_id=(SELECT ROWID FROM Models WHERE method LIKE ? AND basis LIKE ? AND cp LIKE ? AND tag LIKE ? AND optimized=?)", (method, basis, cp, tag, 1)).fetchall() ] for calculation_id in calculation_ids: # get the molecule id corresponding to this calculation molecule_id = self.cursor.execute( "SELECT molecule_id FROM Calculations WHERE ROWID=?", (calculation_id, )).fetchone()[0] # Reconstruct the molecule from the information in this database molecule = Molecule() # loop over all rows in the Fragments table that correspond to this molecule for fragment_id, charge, spin in self.cursor.execute( "SELECT ROWID, charge, spin FROM Fragments WHERE molecule_id=?", (molecule_id, )).fetchall(): fragment = Fragment(charge, spin) # loop over all rows in the Atoms table that correspond to this fragment for symbol, x, y, z in self.cursor.execute( "SELECT symbol, x, y, z FROM Atoms WHERE fragment_id=?", (fragment_id, )).fetchall(): fragment.add_atom(Atom(symbol, x, y, z)) molecule.add_fragment(fragment) # get the energies corresponding to this calculation energies = [ energy_index_value_pair[1] for energy_index_value_pair in sorted( self.cursor.execute( "SELECT energy_index, energy FROM Energies WHERE calculation_id=?", (calculation_id, )).fetchall()) ] yield molecule, energies
def test_get_spin_multiplicity(self): molecule = Molecule() # get_spin_multiplicity() should return 1 before any fragments added to Molecule self.assertEqual(molecule.get_spin_multiplicity(), 1) fragment0 = Fragment(-1, 3) molecule.add_fragment(fragment0) # get_spin_multiplicity() should return 3 after first fragment added to Molecule self.assertEquals(molecule.get_spin_multiplicity(), 3) fragment1 = Fragment(3, 1) molecule.add_fragment(fragment1) # get_spin_multiplicity() should return 3 after second fragment added to Molecule self.assertEquals(molecule.get_spin_multiplicity(), 3)
def test_get_charge(self): molecule = Molecule() # get_charge() should return 0 before any fragments added to Molecule self.assertEqual(molecule.get_charge(), 0) fragment0 = Fragment(-1, 3) molecule.add_fragment(fragment0) # get_charge() should return -1 after first fragment added to Molecule self.assertEquals(molecule.get_charge(), -1) fragment1 = Fragment(3, 1) molecule.add_fragment(fragment1) # get_charge() should return 2 after second fragment added to Molecule self.assertEquals(molecule.get_charge(), 2)
def test_to_standard_xyz(self): molecule = Molecule() fragment0 = Fragment(-1, 1) fragment0.add_atom(Atom("H", 5, 3, 0.00343)) fragment0.add_atom(Atom("Cl", 2, 0, -13)) fragment0.add_atom(Atom("He", 6, 2, 0.343)) molecule.add_fragment(fragment0) self.assertEqual(molecule.to_xyz(), fragment0.to_xyz()[:-1]) fragment1 = Fragment(-2, 1) fragment1.add_atom(Atom("Ar", 0.23430523424, -34, -234.5235)) molecule.add_fragment(fragment1) self.assertEqual(molecule.to_xyz(), fragment1.to_xyz() + fragment0.to_xyz()[:-1]) fragment2 = Fragment(0, 2) fragment2.add_atom(Atom("Xe", 0, 0, 0)) fragment2.add_atom(Atom("Br", 62, 5, 0.001)) molecule.add_fragment(fragment2) self.assertEqual( molecule.to_xyz(), fragment1.to_xyz() + fragment2.to_xyz() + fragment0.to_xyz()[:-1])
def xyz_to_molecules(f, config): # Keep in mind that you're passing in a file from initializer, not a # directory! # number of atoms in each fragment atoms_per_fragment = [] # charge of each fragment charge_per_fragment = [] # spin of each fragment spin_per_fragment = [] # Don't try to find the settings.ini, we should now REQUIRE it instead ''' if "settings.ini" in dir_contents: # create config object config = configparser.SafeConfigParser(allow_no_value=False) # read the conflig file into the configuration config.read(directory + "/settings.ini") ''' # the for loop just changes the string array to an int array atoms_per_fragment = [ int(atom_count) for atom_count in config["molecule"]["fragments"].split(",") ] charge_per_fragment = [ int(charge) for charge in config["molecule"]["charges"].split(",") ] spin_per_fragment = [ int(spin) for spin in config["molecule"]["spins"].split(",") ] # define the list of molecules molecules = [] # Duplicate file openings ''' # loop thru all files in directory for file_name in dir_contents: # check if file_name is an xyz file if file_name[-4:] == ".xyz": # parse the xyz file xyz = open(directory + "/" + file_name, "r") ''' while True: # read first line of file, should be num of atoms atom_num_line = readline(f) # check for end of input if atom_num_line == "": break # check for consistance between number of atoms in xyz file # and number of atoms in fragments array if int(atom_num_line) != sum(atoms_per_fragment): raise ValueError( "Atom count specified in xyz file does not match count in ini file" ) # read and discard the comment line readline(f, True) # init Molecule object molecule = Molecule() molecule.natoms = atoms_per_fragment molecule.charges = charge_per_fragment molecule.spins = spin_per_fragment # start reading atom lines for atom_count, charge, spin in zip(atoms_per_fragment, charge_per_fragment, spin_per_fragment): # init Fragment object fragment = Fragment(charge, spin) for i in range(0, atom_count): # read a line atom_line = readline(f, True) # extract atom info from line symbol, x, y, z = atom_line.split() # add atom to fragment fragment.add_atom(Atom(symbol, float(x), float(y), float(z))) # add fragment to molecule molecule.add_fragment(fragment) # add molecule to list of molecules molecules.append(molecule) return molecules
def get_missing_energy(self): """ Returns a single Calculation object, which contains the info a user needs to calculate an energy missing in the table. The user should calculate the energy, then call either set_energy() or set_failed() Args: None Returns: A Calculation object describing the calculation to be performed """ # retrieve a pending job from the Jobs table try: job_id = self.cursor.execute( "SELECT ROWID FROM Jobs WHERE status=?", ("pending", )).fetchone()[0] except TypeError: # this error will be thrown if there are no more energies to calculate, because None[0] throws a TypeError return None # retrieve the calculation and energy to be calculated for this job from the Energies table calculation_id, energy_index = self.cursor.execute( "SELECT calculation_id, energy_index FROM Energies WHERE job_id=?", (job_id, )).fetchone() # retrieve the molecule and model from the Calculations table molecule_id, model_id, tag, optimized = self.cursor.execute( "SELECT molecule_id, model_id, tag, optimized FROM Calculations WHERE ROWID=?", (calculation_id, )).fetchone() # retrieve the method, basis, and cp for this model method, basis, cp = self.cursor.execute( "SELECT method, basis, cp FROM Models WHERE ROWID=?", (model_id, )).fetchone() # Reconstruct the molecule from the information in this database molecule = Molecule() # loop over all rows in the Fragments table that correspond to this molecule for fragment_id, charge, spin in self.cursor.execute( "SELECT ROWID, charge, spin FROM Fragments WHERE molecule_id=?", (molecule_id, )).fetchall(): fragment = Fragment(charge, spin) # loop over all rows in the Atoms table that correspond to this fragment for symbol, x, y, z in self.cursor.execute( "SELECT symbol, x, y, z FROM Atoms WHERE fragment_id=?", (fragment_id, )).fetchall(): fragment.add_atom(Atom(symbol, x, y, z)) molecule.add_fragment(fragment) # get the indicies of the fragments to include in this calculation fragment_indicies = energy_index_to_fragment_indicies( energy_index, molecule.get_num_fragments()) # update the job with its start date and running status self.cursor.execute( "UPDATE Jobs SET status=?, start_date=? WHERE ROWID=?", ("running", datetime.datetime.today().strftime('%Y/%m/%d'), job_id)) return Calculation(molecule, method, basis, True if cp == 1 else False, fragment_indicies, job_id)