def remove_ghost_particles(last_phase_xml, output_file_name, sigma=1.0): # Remove all the ghost particles from the morphology for the final output final_morphology = hf.load_morphology_xml(last_phase_xml) # Determine the atomIDs for each particle beginning with the letters 'X' # or 'R' - these are the ghost particles atom_IDs_to_remove = [] for atom_ID, atom_type in enumerate(final_morphology["type"]): if (atom_type[0] == "X") or (atom_type[0] == "R"): # This is a ghost particle atom_IDs_to_remove.append(atom_ID) # Reverse sorting trick so that the location indices don't change as we # delete particles from the system atom_IDs_to_remove.sort(reverse=True) # Now delete the atoms from the morphology atom_attribs = ["position", "image", "type", "mass", "diameter", "body", "charge"] for atom_ID in atom_IDs_to_remove: for key in atom_attribs: final_morphology[key].pop(atom_ID) final_morphology["natoms"] -= len(atom_IDs_to_remove) # Delete any constraints associated with those atoms that have been removed atom_constraints = ["bond", "angle", "dihedral", "improper"] for key in atom_constraints: constraints_to_remove = [] for constraint_no, constraint in enumerate(final_morphology[key]): for atom_ID in constraint[1:]: if (atom_ID in atom_IDs_to_remove) and ( constraint_no not in constraints_to_remove ): constraints_to_remove.append(constraint_no) constraints_to_remove.sort(reverse=True) for constraint_no in constraints_to_remove: final_morphology[key].pop(constraint_no) # Output the final morphology hf.write_morphology_xml(final_morphology, output_file_name, sigma)
def test_check_morphology(self, run_simulation): output_morph_dir = run_simulation["output_parameter_dict"][ "output_morph_dir"] input_morph_dir = run_simulation["output_parameter_dict"][ "input_morph_dir"] morphology = run_simulation["output_parameter_dict"]["morphology"] morph_dir = os.path.join(output_morph_dir, os.path.splitext(morphology)[0], "morphology") output_morphology = hf.load_morphology_xml( os.path.join(morph_dir, morphology)) expected_morphology = hf.load_morphology_xml( os.path.join( input_morph_dir, "FG", morphology.replace(".xml", "_post_fine_graining.xml"), )) self.compare_equal(expected_morphology, response=output_morphology)
def test_check_morphology_final_output_pickle(self, run_simulation): output_morph_dir = run_simulation["output_parameter_dict"][ "output_morph_dir"] morphology = run_simulation["output_parameter_dict"]["morphology"] morph_dir = os.path.join(output_morph_dir, os.path.splitext(morphology)[0], "morphology") final_MD_output = hf.load_morphology_xml( os.path.join(morph_dir, "final_" + morphology)) self.compare_equal( final_MD_output, response=run_simulation["output_AA_morphology_dict"])
def main(): list_of_files = sys.argv[1:] if len(list_of_files) < 1: print("No files requested to convert!") exit() for file_name in list_of_files: print("Fixing the images for {:s}...".format(file_name)) morphology = hf.load_morphology_xml(file_name) morphology = zero_out_images(morphology) bond_dict = get_bond_dict(morphology) morphology = check_bonds(morphology, bond_dict) file_directory, split_file_name = os.path.split(file_name) hf.write_morphology_xml( morphology, os.path.join(file_directory, "".join(["image_fix_", split_file_name])), )
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, )
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
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]
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, )