Beispiel #1
0
 def get_CG_monomer_dict(self):
     CG_monomer_dictionary = {
         "position": [],
         "image": [],
         "mass": [],
         "diameter": [],
         "type": [],
         "body": [],
         "bond": [],
         "angle": [],
         "dihedral": [],
         "improper": [],
         "charge": [],
         "lx": 0,
         "ly": 0,
         "lz": 0,
         "xy": 0,
         "xz": 0,
         "yz": 0,
     }
     # First, do just the positions and find the newsiteIDs for each CG site
     for site_ID in self.site_IDs:
         CG_monomer_dictionary["position"].append(
             self.CG_dictionary["position"][site_ID]
         )
     # Now sort out the other one-per-atom properties
     for key in ["image", "mass", "diameter", "type", "body", "charge"]:
         if len(self.CG_dictionary[key]) != 0:
             for site_ID in self.site_IDs:
                 CG_monomer_dictionary[key].append(
                     self.CG_dictionary[key][site_ID]
                 )
     # Now rewrite the bonds based on the newsiteIDs
     for key in ["bond", "angle", "dihedral", "improper"]:
         for element in self.CG_dictionary[key]:
             for site_ID in self.site_IDs:
                 if (site_ID in element) and (
                     element not in CG_monomer_dictionary[key]
                 ):
                     CG_monomer_dictionary[key].append(element)
     # Now update the box parameters
     for key in ["lx", "ly", "lz"]:
         CG_monomer_dictionary[key] = self.CG_dictionary[key]
     CG_monomer_dictionary = hf.add_unwrapped_positions(
         CG_monomer_dictionary
     )
     CG_monomer_dictionary["natoms"] = len(CG_monomer_dictionary["position"])
     return CG_monomer_dictionary
Beispiel #2
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-m",
        "--molecule_source",
        required=False,
        help="""Specify the source of the add_hydrogens dictionary and sigma value.
        This can be in the form of a python script which returns a function of the
        dictionary and sigma or the name of the molecule.""",
    )
    args, input_files = parser.parse_known_args()
    hydrogens_to_add, sigma_val = find_information(args)
    for input_file in input_files:
        # This dictionary has keys of the atom type, and values where the first
        # element is the number of bonds required for us to add a hydrogen to
        # the atom and the second element of the value defines how many
        # hydrogens to add to said atom.
        print(
            "THIS FUNCTION IS SET UP TO USE A DICTIONARY TO DEFINE HOW MANY HYDROGENS "
            " TO ADD TO BONDS OF A SPECIFIC TYPE WITH A CERTAIN NUMBER OF BONDS"
        )
        print(hydrogens_to_add)
        print(
            "IF THE ABOVE DICTIONARY DOESN'T LOOK RIGHT, PLEASE TERMINATE NOW AND "
            " IGNORE ANY OUTPUTS UNTIL THE DICTIONARY HAS BEEN RECTIFIED"
        )
        print("Additionally, we're using a sigma value of", sigma_val)
        morphology_dict = hf.load_morphology_xml(input_file, sigma=sigma_val)
        # We MUST fix the images first, otherwise the hydrogens will be put in
        # incorrectly.
        morphology_dict = fi.zero_out_images(morphology_dict)
        bond_dict = fi.get_bond_dict(morphology_dict)
        morphology_dict = fi.check_bonds(morphology_dict, bond_dict)
        # Now we can safely obtain the unwrapped positions
        morphology_dict = hf.add_unwrapped_positions(morphology_dict)
        hydrogen_positions = calculate_hydrogen_positions(
            morphology_dict, hydrogens_to_add
        )
        morphology_dict = add_hydrogens_to_morph(
            morphology_dict, hydrogen_positions
        )
        morphology_dict = hf.add_wrapped_positions(morphology_dict)
        hf.write_morphology_xml(
            morphology_dict,
            input_file.replace(".xml", "_AA.xml"),
            check_wrapped_posns=False,
        )
Beispiel #3
0
 def __init__(self, morphology_xml, morphology_name, parameter_dict,
              chromophore_list):
     # Need to save the parameter_dict in full as well as its component
     # values because we're going to update the parameterDict with the new
     # type mappings by the end of this code module.
     self.parameter_dict = parameter_dict
     # Import parameters from the parXX.py
     for key, value in parameter_dict.items():
         self.__dict__[key] = value
     self.xml_path = morphology_xml
     self.morphology_name = morphology_name
     # self.inputSigma is the `compression value' in Angstroms that has been
     # used to scale the morphology
     # E.G. the P3HT template uses sigma = 1, but the Marsh morphologies use
     # sigma = 3.
     self.CG_dictionary = hf.load_morphology_xml(self.xml_path,
                                                 sigma=self.input_sigma)
     self.CG_dictionary = hf.add_unwrapped_positions(self.CG_dictionary)
     self.chromophore_list = chromophore_list
Beispiel #4
0
 def __init__(
     self,
     molecule_index,
     site_IDs,
     CG_dictionary,
     molecule_lengths,
     rolling_AA_index,
     ghost_dictionary,
     parameter_dict,
 ):
     # This class sees individual molecules.
     self.no_atoms_in_morphology = rolling_AA_index
     self.molecule_index = molecule_index
     self.molecule_lengths = molecule_lengths
     self.site_IDs = site_IDs
     self.CG_dictionary = CG_dictionary
     # Get the dictionary of all the CG sites in this molecule
     # self.CGMonomerDictionary = self.getCGMonomerDict()
     # Import the parXX.py parameters
     for key, value in parameter_dict.items():
         self.__dict__[key] = value
     self.AA_templates_dictionary = {}
     # Load the template file for each CG atom
     for CG_atom_type in list(self.CG_to_template_files.keys()):
         template_dictionary = hf.load_morphology_xml(
             os.path.join(
                 self.CG_to_template_dirs[CG_atom_type],
                 self.CG_to_template_files[CG_atom_type],
             )
         )
         template_dictionary = self.remap_atom_types(
             template_dictionary,
             parameter_dict["new_type_mappings"][CG_atom_type],
         )
         template_dictionary = hf.add_unwrapped_positions(
             template_dictionary
         )
         self.AA_templates_dictionary[CG_atom_type] = template_dictionary
     fine_grained = self.run_fine_grainer(ghost_dictionary)
     self.AA_dictionary = fine_grained[0]
     self.atom_ID_lookup_table = fine_grained[1]
     self.ghost_dictionary = fine_grained[2]
Beispiel #5
0
def main(
    AA_morphology_dict,
    CG_morphology_dict,
    CG_to_AAID_master,
    parameter_dict,
    chromophore_list,
):
    # Get the random seed now for all the child processes
    if parameter_dict["random_seed_override"] is not None:
        np.random.seed(parameter_dict["random_seed_override"])
    # Main execution function for run_HOOMD that performs the required MD phases
    # First, scale the input morphology based on the pair potentials such that
    # the distances and energies are normalised to the strongest pair
    # interaction and the diameter of the largest atom (makes it easier on
    # HOOMDs calculations and ensures that T = 1.0 is an interesting temperature
    # threshold)
    current_files = os.listdir(
        os.path.join(
            parameter_dict["output_morph_dir"],
            os.path.splitext(parameter_dict["morphology"])[0],
            "morphology",
        )
    )
    # sScale, eScale = obtainScaleFactors(parameterDict)
    print("Under the hood eScaling and sScaling has been disabled.")
    s_scale = 1.0
    e_scale = 1.0
    # Only scale the morphology if it hasn't been already
    if (parameter_dict["overwrite_current_data"] is False) and (
        "".join(["phase0_", parameter_dict["morphology"]]) in current_files
    ):
        pass
    else:
        scale_morphology(AA_morphology_dict, parameter_dict, s_scale, e_scale)
    # Reset logfile
    try:
        os.remove(
            os.path.join(
                parameter_dict["output_morph_dir"],
                os.path.splitext(parameter_dict["morphology"])[0],
                "morphology",
                "".join(
                    [
                        "energies_",
                        os.path.splitext(parameter_dict["morphology"])[0],
                        ".log",
                    ]
                ),
            )
        )
    except OSError:
        pass
    # Perform each molecular dynamics phase as specified in the parXX.py
    for phase_no in range(parameter_dict["number_of_phases"]):
        input_file = "phase{0:d}_{1:s}".format(phase_no, parameter_dict["morphology"])
        output_file = "phase{0:d}_{1:s}".format(
            phase_no + 1, parameter_dict["morphology"]
        )
        if output_file in current_files:
            if parameter_dict["overwrite_current_data"] is False:
                print(output_file, "already exists. Skipping...")
                continue
        md_phase(
            AA_morphology_dict,
            CG_morphology_dict,
            CG_to_AAID_master,
            parameter_dict,
            phase_no,
            os.path.join(
                parameter_dict["output_morph_dir"],
                os.path.splitext(parameter_dict["morphology"])[0],
                "morphology",
                input_file,
            ),
            os.path.join(
                parameter_dict["output_morph_dir"],
                os.path.splitext(parameter_dict["morphology"])[0],
                "morphology",
                output_file,
            ),
            s_scale,
            e_scale,
        ).optimise_structure()
    final_xml_name = os.path.join(
        parameter_dict["output_morph_dir"],
        os.path.splitext(parameter_dict["morphology"])[0],
        "morphology",
        "".join(["final_", parameter_dict["morphology"]]),
    )
    if "".join(["final_", parameter_dict["morphology"]]) not in current_files:
        # Now all phases are complete, remove the ghost particles from the
        # system
        print("Removing ghost particles to create final output...")
        remove_ghost_particles(
            os.path.join(
                parameter_dict["output_morph_dir"],
                os.path.splitext(parameter_dict["morphology"])[0],
                "morphology",
                output_file,
            ),
            final_xml_name,
            sigma=s_scale,
        )
    # Finally, update the pickle file with the most recent and realistic
    # AAMorphologyDict so that we can load it again further along the pipeline
    AA_morphology_dict = hf.load_morphology_xml(final_xml_name)
    # Now that we've obtained the final fine-grained morphology, we need to fix
    # the images to prevent issues with obtaining the chromophores and running
    # them through the ZINDO/S calculations later...
    AA_morphology_dict = hf.fix_images(AA_morphology_dict)
    # ...add in the unwrapped positions...
    AA_morphology_dict = hf.add_unwrapped_positions(AA_morphology_dict)
    # ...rewrite the final morphology xml...
    hf.write_morphology_xml(AA_morphology_dict, final_xml_name)
    # ...and write the pickle file.
    hf.write_pickle(
        (
            AA_morphology_dict,
            CG_morphology_dict,
            CG_to_AAID_master,
            parameter_dict,
            chromophore_list,
        ),
        os.path.join(
            parameter_dict["output_morph_dir"],
            os.path.splitext(parameter_dict["morphology"])[0],
            "code",
            "".join([os.path.splitext(parameter_dict["morphology"])[0], ".pickle"]),
        ),
    )
    return (
        AA_morphology_dict,
        CG_morphology_dict,
        CG_to_AAID_master,
        parameter_dict,
        chromophore_list,
    )
Beispiel #6
0
    def analyse_morphology(self):
        # Split the morphology into individual molecules
        print("Finding molecules...")
        molecule_IDs, molecule_lengths = self.split_molecules()
        rolling_AA_index = 0
        CG_morphology_dict = {}
        AA_morphology_dict = {}
        # Set the AAMorphology and CGMorphology system sizes to the same as the
        # input file system size
        for box_dimension in ["lx", "ly", "lz", "xy", "xz", "yz"]:
            CG_morphology_dict[box_dimension] = self.CG_dictionary[
                box_dimension
            ]
            AA_morphology_dict[box_dimension] = self.CG_dictionary[
                box_dimension
            ]
        CG_to_AAID_master = []  # This is a list of dictionaries. Elements in
        # the list correspond to molecules (useful for splitting out individual
        # molecules for the xyz conversion) within the element, the dictionary
        # key is the CG site, the value is a list containing the CG type (e.g.
        # 'thio') as the first element and then another list of all the AAIDs
        # corresponding to that CG site as the second element.

        # If no CG_to_template info is present in the parameter dict, then we
        # can assume that the morphology is already fine-grained and so we can
        # just return the important information and skip this module
        if len(self.CG_to_template_dirs) == 0:
            print(
                "No CG to AA data found in parameter file - the morphology is already"
                " fine-grained! Skipping this module..."
            )
            # Write the xml file and create the pickle
            print("Writing xml file...")
            AA_file_name = os.path.join(
                self.output_morph_dir,
                self.morphology_name,
                "morphology",
                "".join([self.morphology_name, ".xml"]),
            )
            atomistic_morphology = hf.add_unwrapped_positions(
                self.CG_dictionary
            )
            # Now write the morphology xml
            hf.write_morphology_xml(atomistic_morphology, AA_file_name)
            # And finally write the pickle with the CGDictionary as None (to
            # indicate to MorphCT that no fine-graining has taken place), but
            # the other parameters assigned as required.
            pickle_location = os.path.join(
                self.output_morph_dir,
                self.morphology_name,
                "code",
                "".join([self.morphology_name, ".pickle"]),
            )
            hf.write_pickle(
                (
                    atomistic_morphology,
                    None,
                    None,
                    self.parameter_dict,
                    self.chromophore_list,
                ),
                pickle_location,
            )
            return (
                atomistic_morphology,
                None,
                None,
                self.parameter_dict,
                self.chromophore_list,
            )

        # Create a ghost particle dictionary to be added at the end of the
        # morphology. This way, we don't mess up the order of atoms later on
        # when trying to split back up into individual molecules and monomers.
        # The ghost dictionary contains all of the type T and type X particles
        # that will anchor the thiophene rings to the CG COM positions.
        ghost_dictionary = {
            "position": [],
            "image": [],
            "unwrapped_position": [],
            "mass": [],
            "diameter": [],
            "type": [],
            "body": [],
            "bond": [],
            "angle": [],
            "dihedral": [],
            "improper": [],
            "charge": [],
        }

        # Need to check for atom-type conflicts and suitably increment the
        # type indices if more than one molecule type is being fine-grained
        new_type_mappings = self.get_new_type_mappings(
            self.CG_to_template_dirs, self.CG_to_template_force_fields
        )
        # Need to update the self.parameterDict, which will be rewritten at the
        # end of this module
        self.parameter_dict["new_type_mappings"] = new_type_mappings
        molecule = []
        unique_mappings = []
        CG_sites, mappings = hf.parallel_sort(
            list(new_type_mappings.keys()), list(new_type_mappings.values())
        )
        for index, mapping in enumerate(mappings):
            if mapping not in unique_mappings:
                molecule.append([])
                unique_mappings.append(mapping)
            molecule[-1].append(CG_sites[index])
        printExplanation = True
        for index, CG_sites in enumerate(molecule):
            printMol = True
            initial_atoms, final_atoms = hf.parallel_sort(
                list(unique_mappings[index].keys()),
                list(unique_mappings[index].values()),
            )
            for index, initial_atom in enumerate(initial_atoms):
                if initial_atom == final_atoms[index]:
                    continue
                if printExplanation is True:
                    print(
                        "The following atom types have been remapped due to conflicting"
                        " typenames in the atomistic templates:"
                    )
                    printExplanation = False
                if printMol is True:
                    print(
                        "Atom types belonging the molecule described by",
                        "".join([repr(CG_sites), ":"]),
                    )
                    printMol = False
                print(initialAtom, "--->", finalAtoms[index])
        print("Adding", len(molecule_IDs), "molecules to the system...")
        for molecule_number in range(len(molecule_IDs)):
            print("Adding molecule number", molecule_number, "\r", end=" ")
            if sys.stdout is not None:
                sys.stdout.flush()
            # Obtain the AA dictionary for each molecule using the
            # fine-graining procedure
            AA_molecule_dict, C_gto_AAIDs, ghost_dictionary = atomistic(
                molecule_number,
                molecule_IDs[molecule_number],
                self.CG_dictionary,
                molecule_lengths,
                rolling_AA_index,
                ghost_dictionary,
                self.parameter_dict,
            ).return_data()
            CG_to_AAID_master.append(C_gto_AAIDs)
            # Update the morphology dictionaries with this new molecule
            for key in list(self.CG_dictionary.keys()):
                if key not in [
                    "lx",
                    "ly",
                    "lz",
                    "xy",
                    "xz",
                    "yz",
                    "time_step",
                    "dimensions",
                ]:
                    if key not in list(AA_morphology_dict.keys()):
                        AA_morphology_dict[key] = AA_molecule_dict[key]
                    else:
                        AA_morphology_dict[key] += AA_molecule_dict[key]
            rolling_AA_index += len(AA_molecule_dict["type"])
        # Now add the ghost dictionary to the end of the morphology file
        # total_number_of_atoms should be == rolling_AA_index, but don't want
        # to take any chances.
        total_number_of_atoms = len(AA_morphology_dict["type"])
        # Add in the wrapped positions of the ghosts. Need to know sim dims for
        # this
        for key in ["lx", "ly", "lz", "xy", "xz", "yz"]:
            ghost_dictionary[key] = AA_morphology_dict[key]
        ghost_dictionary = hf.add_wrapped_positions(ghost_dictionary)
        for key in ["lx", "ly", "lz", "xy", "xz", "yz"]:
            ghost_dictionary.pop(key)
        # The real atoms that the ghost particles are bonded to are already
        # correct and no longer need to be changed.
        # However, the ghost particles themselves will have the wrong indices
        # if we were to add them to the system directly.
        # Therefore, increment all of the ghost bond indices that begin with a
        # * (ghost particle) by the total number of atoms already in the
        # system.
        for bond_no, bond in enumerate(ghost_dictionary["bond"]):
            if str(bond[1])[0] == "*":
                ghost_dictionary["bond"][bond_no][1] = (
                    int(bond[1][1:]) + total_number_of_atoms
                )
            if str(bond[2])[0] == "*":
                ghost_dictionary["bond"][bond_no][2] = (
                    int(bond[2][1:]) + total_number_of_atoms
                )
        # Now append all ghosts to morphology
        for key in list(ghost_dictionary.keys()):
            AA_morphology_dict[key] += ghost_dictionary[key]
        # Finally, update the number of atoms
        AA_morphology_dict["natoms"] += len(ghost_dictionary["type"])
        print("\n")
        # Now write the xml file and create the pickle
        print("Writing xml file...")
        AA_file_name = os.path.join(
            self.output_morph_dir,
            self.morphology_name,
            "morphology",
            "".join([self.morphology_name, ".xml"]),
        )
        # Replace the `positions' with the `unwrapped_positions' ready for
        # writing
        AA_morphology_dict = hf.replace_wrapped_positions(AA_morphology_dict)
        # Update the additional_constraints that we put in by checking all of
        # the constraints have the correct names before writing
        AA_morphology_dict = hf.check_constraint_names(AA_morphology_dict)
        # Now write the morphology xml
        hf.write_morphology_xml(AA_morphology_dict, AA_file_name)
        # And finally write the pickle
        pickle_location = os.path.join(
            self.output_morph_dir,
            self.morphology_name,
            "code",
            "".join([self.morphology_name, ".pickle"]),
        )
        hf.write_pickle(
            (
                AA_morphology_dict,
                self.CG_dictionary,
                CG_to_AAID_master,
                self.parameter_dict,
                self.chromophore_list,
            ),
            pickle_location,
        )
        return (
            AA_morphology_dict,
            self.CG_dictionary,
            CG_to_AAID_master,
            self.parameter_dict,
            self.chromophore_list,
        )