def load_pickle_data(old_pickle_file, directory):
    try:
        pickle_data = hf.load_pickle(old_pickle_file)
    except SyntaxError:
        # This pickle is from a python 2 version of MorphCT. We can inject
        # a line into the obtainChromophores.py to try and fix the import
        # error
        print(
            "Pickle is from Python 2, updating the code so it can be imported..."
        )
        code_file_names = ["obtainChromophores.py", "helperFunctions.py"]
        for code_file_name in code_file_names:
            print("Updating", "".join([code_file_name, "..."]))
            with open(os.path.join(directory, code_file_name),
                      "r") as code_file:
                code_lines = code_file.readlines()
            for line_number, line in enumerate(code_lines):
                if "import cPickle as pickle" in line:
                    code_lines[line_number] = "import pickle\n"
                elif ("#" not in line) and ("print" in line):
                    n_spaces = len(line) - len(line.lstrip())
                    code_lines[line_number] = "".join(
                        [" " * n_spaces, "print()\n"])
            with open(os.path.join(directory, code_file_name),
                      "w+") as code_file:
                code_file.writelines(code_lines)
        pickle_data = hf.load_pickle(old_pickle_file)
    return pickle_data
 def test_pickles(self):
     # First load the test file
     input_file = os.path.join(TEST_ROOT, "assets", "hf_test.pickle")
     data = hf.load_pickle(input_file)
     assert len(data) == 5, (
         "Expected pickle file to contain 5 elements, instead it" +
         " contained " + repr(len(data)) + ".")
     assert type(data[0]) == dict, (
         "Expected first element of the pickle file (AA_morphology_dict)" +
         " to be a dictionary, instead its type is " + repr(type(data[0])) +
         ".")
     assert type(data[1]) == dict, (
         "Expected second element of the pickle file (CG_morphology_dict)" +
         " to be a dictionary, instead its type is " + repr(type(data[1])) +
         ".")
     assert type(data[2]) == list, (
         "Expected third element of the pickle file (CG_to_AAID_master)" +
         " to be a list, instead its type is " + repr(type(data[2])) + ".")
     assert type(data[3]) == dict, (
         "Expected fourth element of the pickle file (parameter_dict)" +
         " to be a dictionary, instead its type is " + repr(type(data[3])) +
         ".")
     assert type(data[4]) == list, (
         "Expected fifth element of the pickle file (chromophore_list)" +
         " to be a list, instead its type is " + repr(type(data[4])) + ".")
     # Then write it out somewhere else
     output_file = os.path.join(TEST_ROOT, "output_hf",
                                "test_output.pickle")
     self.confirm_file_exists(output_file,
                              function="write_pickle",
                              posn_args=[data, output_file])
 def __init__(self, mol_morph_name, parameter_dict):
     chromophore_list_location = os.path.join(
         parameter_dict["output_morph_dir"],
         mol_morph_name,
         "code",
         "".join([mol_morph_name, ".pickle"]),
     )
     pickle_data = hf.load_pickle(chromophore_list_location)
     self.AA_morphology_dict = pickle_data[0]
     self.parameter_dict = pickle_data[3]
     self.chromophore_list = pickle_data[4]
     self.carrier_type = self.get_carrier_type()
     # Now add the occupation data to the chromophoreLists so that we can
     # prevent double occupation in the simulations.
     # The occupied property is a list that contains the device moiety
     # coordinates where the chromophore is occupied.
     for index, chromophore in enumerate(self.chromophore_list):
         chromophore.occupied = []
Example #4
0
    return [
        AA_morphology_dict,
        CG_morphology_dict,
        CG_to_AAID_master,
        parameter_dict,
        chromophore_list,
    ]


if __name__ == "__main__":
    try:
        pickle_file = sys.argv[1]
    except:
        print(
            "Please specify the pickle file to load to continue the pipeline from this"
            " point."
        )
    pickle_data = hf.load_pickle(pickle_file)
    AA_morphology_dict = pickle_data[0]
    CG_morphology_dict = pickle_data[1]
    CG_to_AAID_master = pickle_data[2]
    parameter_dict = pickle_data[3]
    chromophore_list = pickle_data[4]
    main(
        AA_morphology_dict,
        CG_morphology_dict,
        CG_to_AAID_master,
        parameter_dict,
        chromophore_list,
    )
def manual_load(table, infile, C1_index, C2_index):
    """
    A manual way to load in the data when we only want
    to compare a pair of chromophores.
    Requires:
        table - string, the name of the table in the database
        infile - string, the name of the pickle file
        C1_index - integer for chromophore 1
        C2_index - integer for chromophore 2
    """
    AA_morphology_dict, CG_morphology_dict, CG_to_AAID_master, parameter_dict, chromophore_list = hf.load_pickle(infile)
    box = np.array([[AA_morphology_dict['lx'], AA_morphology_dict['ly'], AA_morphology_dict['lz']]])
    write_positions_to_xyz(C1_index, C2_index, chromophore_list, AA_morphology_dict, box)
def run_system(table, infile, molecule_dict, species, mers=15):
    """
    Calculate the relative orientational
    data for pairs of chromophores.
    Requires:
        table - string, the name of the table in the database
        infile - string, the name of the pickle file
        molecule_dict - dictionary containing molecule information
        species - string, 'donor' or 'acceptor'
    """
    #Load in the data
    AA_morphology_dict, CG_morphology_dict, CG_to_AAID_master, parameter_dict, chromophore_list = hf.load_pickle(infile)

    #Get the number of the desired species for creating the dictionary
    species_list = [chromophore.species for chromophore in chromophore_list]
    chromo_IDs = [index for index, chromo_species in enumerate(species_list) if chromo_species == species]
    vector_dict = generate_empty_dict(chromo_IDs)
    #Set up the periodic simulation box into a single variable.
    box = np.array([[AA_morphology_dict['lx'], AA_morphology_dict['ly'], AA_morphology_dict['lz']]])

    vector_dict = fill_dict(vector_dict, 
            chromophore_list, 
            AA_morphology_dict, 
            box, 
            species, 
            molecule_dict['atom_indices'])

    data = []  # List for storing the calculated data

    molecule_list = identify_chains(AA_morphology_dict, chromophore_list)
    sulfur_distances = []

    #Because DBP has fullerenes, iterate only up to
    #where the system is DBP

    #Iterate through all the chromophores.
    print("Extracting descriptors from all chromophores...")
    for i, chromophore in enumerate(chromophore_list):
        #Only get the desired acceptor or donor index, needed for blends.
        if chromophore.species == species:
            #Iterate through the neighbors of each chromophore.
            for neighbor in zip(chromophore.neighbours, chromophore.neighbours_delta_E, chromophore.neighbours_TI):
                index1 = i
                index2 = neighbor[0][0]  # Gets the neighbor's index
                relative_image = neighbor[0][1] # Gets the neighbour's image
                dE = neighbor[1]  # Get the difference in energy
                TI = neighbor[2]  # Get the transfer integral

                same_chain = check_same_chain(molecule_list, index1, index2, mers)
                if os.path.splitext(molecule_dict['database'])[0].lower() == 'p3ht':
                    sulfur_distance = get_sulfur_separation(chromophore, chromophore_list[index2], relative_image, box[0], AA_morphology_dict)
                else:
                    sulfur_distance = 0

                if (TI is None) or (TI > 0):  # Consider only pairs that will have hops.

                    #Get the location of the other chromophore and make sure they're in the
                    #same periodic image.
                    index2_loc = check_vector(chromophore_list[index2].posn, chromophore.posn, box)
                    #Calculate the distance (normally this is in Angstroms)
                    centers_vec = chromophore.posn - index2_loc

                    #Get the vectors describing the two chromophores
                    vdict1 = vector_dict[index1]
                    vdict2 = vector_dict[index2]
                    #Calculate the differences in alignment between the chromophores
                    # Vec1 for DBP is (midpoint(1, 2) -> 3) (along Y axis)
                    # Vec2 for DBP is (1 -> 2) (along X axis)
                    # Vec3 for DBP is Normal to both (along Z axis)
                    # MJ note: FOR DBP ONLY if we assume the chromophore is identical above
                    # and below the plane of the molecule, then because
                    # dot(a, b) == - dot(a, -b), we can reduce the dimensionality
                    # of our data further by just taking the absolute value of the
                    # dot product.
                    rotY = np.dot(vdict1['vec1'], vdict2['vec1'])
                    rotX = np.dot(vdict1['vec2'], vdict2['vec2'])
                    rotZ = np.dot(vdict1['vec3'], vdict2['vec3'])

                    # We need to calculate a rotation matrix that can map the normal vector
                    # describing the plane of the first chromophore to the z-axis.
                    # We can define this rotation matrix as the required transformation to
                    # map the normal of chromophore 1 (a) to the unit z axis (b).
                    rotation_matrix = calculate_rotation_matrix(vdict1['vec3'], vdict1['vec2'])
                    old_length = np.linalg.norm(centers_vec)
                    transformed_separation_vec = np.matmul(rotation_matrix, centers_vec)
                    new_length = np.linalg.norm(transformed_separation_vec)
                    assert np.isclose(old_length, new_length)

                    # import matplotlib.pyplot as plt
                    # import mpl_toolkits.mplot3d as p3
                    # fig = plt.figure()
                    # ax = p3.Axes3D(fig)
                    # plt.plot([0, centers_vec[0]], [0, centers_vec[1]], zs=[0, centers_vec[2]], c='b', label="Original")
                    # plt.plot([0, vdict1['vec3'][0]], [0, vdict1['vec3'][1]], zs=[0, vdict1['vec3'][2]], c='c', label="Orig Vec3")
                    # plt.plot([0, transformed_separation_vec[0]], [0, transformed_separation_vec[1]], zs=[0, transformed_separation_vec[2]], c='r', label="Rotated")
                    # rotated_vec3 = np.matmul(rotation_matrix, vdict1['vec3'])
                    # plt.plot([0, rotated_vec3[0]], [0, rotated_vec3[1]], zs=[0, rotated_vec3[2]], c='m', label="Rotated Vec3")
                    # plt.legend()
                    # plt.show()


                    posX = centers_vec[0]
                    posY = centers_vec[1]
                    posZ = centers_vec[2]
                    #Combine the data into an array
                    datum = np.array([index1,
                        index2,
                        posX,
                        posY,
                        posZ,
                        rotX,
                        rotY,
                        rotZ,
                        dE,
                        same_chain,
                        sulfur_distance,
                        TI])

                    data.append(datum) #Write the data to the list

    data = np.array(data) #Turn the list into an array, may be unnecessary

    add_to_database(table, data, molecule_dict['database']) #Write the data to the database
def main():
    global log_file

    KMC_directory = sys.argv[1]
    CPU_rank = int(sys.argv[2])
    np.random.seed(int(sys.argv[3]))
    overwrite = False
    try:
        overwrite = bool(sys.argv[4])
    except:
        pass
    # Load `jobs_to_run' which is a list, where each element contains the
    # [carrier.ID, carrier.lifetime, carrier.carrierType]
    pickle_file_name = os.path.join(KMC_directory,
                                    "KMC_data_{:02d}.pickle".format(CPU_rank))
    with open(pickle_file_name, "rb") as pickle_file:
        jobs_to_run = pickle.load(pickle_file)
    log_file = os.path.join(KMC_directory,
                            "KMC_log_{:02d}.log".format(CPU_rank))
    # Reset the log file
    with open(log_file, "wb+") as log_file_handle:
        pass
    hf.write_to_file(log_file,
                     ["Found {:d} jobs to run".format(len(jobs_to_run))])
    # Set the affinities for this current process to make sure it's maximising
    # available CPU usage
    current_PID = os.getpid()
    # try:
    #     affinity_job = sp.Popen(['taskset', '-pc', str(CPU_rank), str(current_PID)],
    #                             stdin=sp.PIPE, stdout=sp.PIPE,
    #                             stderr=sp.PIPE).communicate()
    #     # hf.write_to_file(log_file, affinity_job[0].split('\n'))
    #     # hf.write_to_file(log_file, affinity_job[1].split('\n'))
    # except OSError:
    #     hf.write_to_file(log_file, ["Taskset command not found, skipping setting of"
    #                                 " processor affinity..."])
    # Now load the main morphology pickle (used as a workaround to obtain the
    # chromophore_list without having to save it in each carrier [very memory
    # inefficient!])
    pickle_dir = KMC_directory.replace("/KMC", "/code")
    for file_name in os.listdir(pickle_dir):
        if "pickle" in file_name:
            main_morphology_pickle_name = os.path.join(pickle_dir, file_name)
    hf.write_to_file(
        log_file,
        [
            "".join([
                "Found main morphology pickle file at ",
                main_morphology_pickle_name,
                "! loading data...",
            ])
        ],
    )
    pickle_data = hf.load_pickle(main_morphology_pickle_name)
    AA_morphology_dict = pickle_data[0]
    CG_morphology_dict = pickle_data[1]
    CG_to_AAID_master = pickle_data[2]
    parameter_dict = pickle_data[3]
    chromophore_list = pickle_data[4]
    hf.write_to_file(log_file, ["Main morphology pickle loaded!"])
    try:
        if parameter_dict["use_average_hop_rates"] is True:
            # Chosen to split hopping by inter-intra molecular hops, so get
            # molecule data
            mol_ID_dict = split_molecules(AA_morphology_dict)
            # molIDDict is a dictionary where the keys are the chromoIDs, and
            # the vals are the molIDs
        else:
            raise KeyError
    except KeyError:
        mol_ID_dict = None
    # Attempt to catch a kill signal to ensure that we save the pickle before
    # termination
    killer = termination_signal()
    # Save the pickle as a list of `saveCarrier' instances that contain the
    # bare minimum
    save_data = initialise_save_data(len(chromophore_list), int(sys.argv[3]))
    if parameter_dict["record_carrier_history"] is False:
        save_data["hole_history_matrix"] = None
        save_data["electron_history_matrix"] = None
    t0 = T.time()
    save_time = T.time()
    save_slot = "slot1"
    try:
        for job_number, [carrier_no, lifetime,
                         carrier_type] in enumerate(jobs_to_run):
            t1 = T.time()
            # Find a random position to start the carrier in
            while True:
                start_chromo_ID = np.random.randint(0,
                                                    len(chromophore_list) - 1)
                if (carrier_type.lower() == "electron") and (
                        chromophore_list[start_chromo_ID].species.lower() !=
                        "acceptor"):
                    continue
                elif (carrier_type.lower() == "hole") and (
                        chromophore_list[start_chromo_ID].species.lower() !=
                        "donor"):
                    continue
                break
            # Create the carrier instance
            this_carrier = carrier(
                chromophore_list,
                parameter_dict,
                start_chromo_ID,
                lifetime,
                carrier_no,
                AA_morphology_dict,
                mol_ID_dict,
            )
            terminate_simulation = False
            while terminate_simulation is False:
                terminate_simulation = bool(
                    this_carrier.calculate_hop(chromophore_list))
                if killer.kill_sent is True:
                    raise terminate(
                        "Kill command sent, terminating KMC simulation...")
            # Now the carrier has finished hopping, let's calculate its vitals
            initial_position = this_carrier.initial_chromophore.posn
            final_position = this_carrier.current_chromophore.posn
            final_image = this_carrier.image
            sim_dims = this_carrier.sim_dims
            this_carrier.displacement = calculate_displacement(
                initial_position, final_position, final_image, sim_dims)
            # Now the calculations are completed, create a barebones class
            # containing the save data
            importantData = [
                "ID",
                "image",
                "lifetime",
                "current_time",
                "no_hops",
                "displacement",
                "carrier_type",
            ]
            for name in importantData:
                save_data[name].append(this_carrier.__dict__[name])
            # Update the carrierHistoryMatrix
            if parameter_dict["record_carrier_history"] is True:
                if this_carrier.carrier_type.lower() == "hole":
                    save_data[
                        "hole_history_matrix"] += this_carrier.hole_history_matrix
                elif this_carrier.carrier_type.lower() == "electron":
                    save_data[
                        "electron_history_matrix"] += this_carrier.electron_history_matrix
            # Then add in the initial and final positions
            save_data["initial_position"].append(initial_position)
            save_data["final_position"].append(final_position)
            t2 = T.time()
            elapsed_time = float(t2) - float(t1)
            if elapsed_time < 60:
                time_units = "seconds."
            elif elapsed_time < 3600:
                elapsed_time /= 60.0
                time_units = "minutes."
            elif elapsed_time < 86400:
                elapsed_time /= 3600.0
                time_units = "hours."
            else:
                elapsed_time /= 86400.0
                time_units = "days."
            hf.write_to_file(
                log_file,
                [
                    "".join([
                        "{0:s} hopped {1:d} times, over {2:.2e} seconds, into image "
                        .format(
                            this_carrier.carrier_type.capitalize(),
                            this_carrier.no_hops,
                            this_carrier.current_time,
                        ),
                        repr(this_carrier.image),
                        ", for a displacement of {0:.2f}, in {1:.2f} wall-clock {2:s}"
                        .format(this_carrier.displacement, elapsed_time,
                                time_units),
                    ])
                ],
            )
            # Save the pickle file every hour
            if (t2 - save_time) > 3600:
                print(
                    "Completed {0:d} of {1:d} jobs. Making checkpoint at {2:3d}%%"
                    .format(
                        job_number,
                        len(jobs_to_run),
                        np.round(
                            (job_number + 1) / float(len(jobs_to_run)) * 100),
                    ))
                hf.write_to_file(
                    log_file,
                    [
                        "Completed {0:d} of {1:d} jobs. Making checkpoint at {2:3d}%%"
                        .format(
                            job_number,
                            len(jobs_to_run),
                            np.round((job_number + 1) /
                                     float(len(jobs_to_run)) * 100),
                        )
                    ],
                )
                save_pickle(
                    save_data,
                    pickle_file_name.replace("data",
                                             "".join([save_slot, "_results"])),
                )
                if save_slot.lower() == "slot1":
                    save_slot = "slot2"
                elif save_slot.lower() == "slot2":
                    save_slot = "slot1"
                save_time = T.time()
    except Exception as error_message:
        print(traceback.format_exc())
        print("Saving the pickle file cleanly before termination...")
        hf.write_to_file(log_file, [str(error_message)])
        hf.write_to_file(
            log_file, ["Saving the pickle file cleanly before termination..."])
        save_pickle(save_data,
                    pickle_file_name.replace("data", "terminated_results"))
        print("Pickle saved! Exitting Python...")
        exit()
    t3 = T.time()
    elapsed_time = float(t3) - float(t0)
    if elapsed_time < 60:
        time_units = "seconds."
    elif elapsed_time < 3600:
        elapsed_time /= 60.0
        time_units = "minutes."
    elif elapsed_time < 86400:
        elapsed_time /= 3600.0
        time_units = "hours."
    else:
        elapsed_time /= 86400.0
        time_units = "days."
    hf.write_to_file(
        log_file,
        [
            "All jobs completed in {0:.2f} {1:s}".format(
                elapsed_time, time_units)
        ],
    )
    hf.write_to_file(log_file,
                     ["Saving the pickle file cleanly before termination..."])
    save_pickle(save_data, pickle_file_name.replace("data", "results"))
    hf.write_to_file(log_file, ["Exiting normally..."])
def run_simulation(request):
    _voronoi = request.param["voronoi"]
    _hop_range_value = request.param["hop_range"]
    _transiting = request.param["transiting"]
    _koopmans = request.param["koopmans"]
    if _hop_range_value != 10.0:
        _hop_range = True
    else:
        _hop_range = False
    _modifiers = {"True": [], "False": []}
    for _key in request.param.keys():
        _boolean = eval("".join(["_", _key]))
        _modifiers[repr(_boolean)].append(_key)

    # ---==============================================---
    # ---======== Directory and File Structure ========---
    # ---==============================================---

    input_morph_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_morph_dir = os.path.join(TEST_ROOT, "output_OC")
    output_orca_dir = None
    input_device_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_device_dir = os.path.join(TEST_ROOT, "output_OC")

    # ---==============================================---
    # ---========== Input Morphology Details ==========---
    # ---==============================================---

    morphology = "donor_polymer.xml"
    input_sigma = 3.0
    device_morphology = None
    device_components = {}
    overwrite_current_data = True
    random_seed_override = 929292929

    # ---==============================================---
    # ---============= Execution Modules ==============---
    # ---==============================================---

    execute_fine_graining = False  # Requires: None
    execute_molecular_dynamics = False  # Requires: fine_graining
    execute_obtain_chromophores = (
        True)  # Requires: Atomistic morphology, or molecular_dynamics
    execute_ZINDO = False  # Requires: obtain_chromophores
    execute_calculate_transfer_integrals = False  # Requires: execute_ZINDO
    execute_calculate_mobility = False  # Requires: calculate_transfer_integrals
    execute_device_simulation = (
        False
    )  # Requires: calculate_transfer_integrals for all device_components

    # ---==============================================---
    # ---============ Chromophore Parameters ==========---
    # ---==============================================---

    molecule_terminating_connections = {"C1": [[2, 1]], "C10": [[2, 1]]}
    AA_rigid_body_species = {}
    CG_site_species = {"A": "donor", "B": "none", "C": "none"}
    use_voronoi_neighbours = _voronoi
    maximum_hole_hop_distance = _hop_range
    maximum_electron_hop_distance = _hop_range
    permit_hops_through_opposing_chromophores = _transiting
    remove_orca_inputs = False
    remove_orca_outputs = True
    chromophore_length = 3

    # ---==============================================---
    # ---=== Chromophore Energy Scaling Parameters ====---
    # ---==============================================---

    chromophore_species = {
        "donor": {
            "literature_MO": -5.0,
            "target_DOS_std": 0.1,
            "reorganisation_energy": 0.3064,
            "species": "donor",
            "VRH_delocalisation": 2e-10,
        }
    }
    use_koopmans_approximation = _koopmans
    koopmans_hopping_prefactor = 1E-3

    # ---==============================================---
    # ---================= Begin run ==================---
    # ---==============================================---

    parameter_file = os.path.realpath(__file__)
    proc_IDs = hf.get_CPU_cores()
    parameter_names = [
        i for i in dir() if (not i.startswith("_")) and (
            not i.startswith("@")) and (not i.startswith("Test")) and (
                not i.startswith("test")) and (i not in [
                    "run_MorphCT",
                    "helper_functions",
                    "hf",
                    "os",
                    "shutil",
                    "TestCommand",
                    "TEST_ROOT",
                    "setup_module",
                    "teardown_module",
                    "testing_tools",
                    "sys",
                    "pytest",
                    "request",
                ])
    ]
    parameters = {}
    for name in parameter_names:
        parameters[name] = locals()[name]

    # ---==============================================---
    # ---=============== Setup Prereqs ================---
    # ---==============================================---

    try:
        shutil.rmtree(output_morph_dir)
    except OSError:
        pass
    os.makedirs(
        os.path.join(output_morph_dir,
                     os.path.splitext(morphology)[0], "code"))
    shutil.copy(
        os.path.join(
            TEST_ROOT,
            "assets",
            os.path.splitext(morphology)[0],
            "OC",
            morphology.replace(".xml", "_post_run_HOOMD.pickle"),
        ),
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ),
    )

    run_MorphCT.simulation(
        **parameters)  # Execute MorphCT using these simulation parameters
    # The output dictionary from this fixing
    fix_dict = {}
    # Load the output pickle
    output_pickle_data = hf.load_pickle(
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ))
    fix_dict["output_AA_morphology_dict"] = output_pickle_data[0]
    fix_dict["output_CG_morphology_dict"] = output_pickle_data[1]
    fix_dict["output_CG_to_AAID_master"] = output_pickle_data[2]
    fix_dict["output_parameter_dict"] = output_pickle_data[3]
    fix_dict["output_chromophore_list"] = output_pickle_data[4]
    # Load the correct expected pickle
    pickle_name = os.path.join(
        input_morph_dir, "OC",
        morphology.replace(".xml", "_post_obtain_chromophores"))
    pickle_name_modified = "_".join([pickle_name] + sorted(_modifiers["True"]))
    expected_pickle_data = hf.load_pickle("".join(
        [pickle_name_modified, ".pickle"]))
    fix_dict["expected_AA_morphology_dict"] = expected_pickle_data[0]
    fix_dict["expected_CG_morphology_dict"] = expected_pickle_data[1]
    fix_dict["expected_CG_to_AAID_master"] = expected_pickle_data[2]
    fix_dict["expected_parameter_dict"] = expected_pickle_data[3]
    fix_dict["expected_chromophore_list"] = expected_pickle_data[4]
    return fix_dict
def run_simulation():
    # ---==============================================---
    # ---======== Directory and File Structure ========---
    # ---==============================================---

    input_morph_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_morph_dir = os.path.join(TEST_ROOT, "output_FG")
    output_orca_dir = None
    input_device_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_device_dir = os.path.join(TEST_ROOT, "output_FG")

    # ---==============================================---
    # ---========== Input Morphology Details ==========---
    # ---==============================================---

    morphology = "donor_polymer.xml"
    input_sigma = 3.0
    device_morphology = None
    device_components = {}
    overwrite_current_data = True
    random_seed_override = 929292929

    # ---==============================================---
    # ---============= Execution Modules ==============---
    # ---==============================================---

    execute_fine_graining = True  # Requires: None
    execute_molecular_dynamics = False  # Requires: fine_graining
    execute_obtain_chromophores = (
        False)  # Requires: Atomistic morphology, or molecular_dynamics
    execute_ZINDO = False  # Requires: obtain_chromophores
    execute_calculate_transfer_integrals = False  # Requires: execute_ZINDO
    execute_calculate_mobility = False  # Requires: calculate_transfer_integrals
    execute_device_simulation = (
        False
    )  # Requires: calculate_transfer_integrals for all device_components

    # ---==============================================---
    # ---========== Fine Graining Parameters ==========---
    # ---==============================================---

    CG_to_template_dirs = {
        "A": os.path.join(TEST_ROOT, "assets", "donor_polymer"),
        "B": os.path.join(TEST_ROOT, "assets", "donor_polymer"),
        "C": os.path.join(TEST_ROOT, "assets", "donor_polymer"),
    }
    CG_to_template_files = {
        "A": "P3HT_template.xml",
        "B": "P3HT_template.xml",
        "C": "P3HT_template.xml",
    }
    CG_to_template_force_fields = {
        "A": "test_FF.xml",
        "B": "test_FF.xml",
        "C": "test_FF.xml",
    }
    CG_to_template_AAIDs = {
        "A": [0, 1, 2, 3, 4, 24],
        "B": [5, 6, 7, 18, 19, 20, 21, 22, 23],
        "C": [8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
    }
    CG_to_template_bonds = {"bondB": ["C2-C3", 2, 5], "bondC": ["C5-C6", 7, 8]}
    rigid_body_sites = {"A": [0, 1, 2, 3, 4]}
    additional_constraints = [
        ["C1-C10", 3, 25],
        ["C1-C10-C9", 3, 25, 26],
        ["C1-C10-S1", 3, 25, 29],
        ["S1-C1-C10", 4, 3, 25],
        ["C2-C1-C10", 2, 3, 25],
        ["C1-C10-C9-C2", 3, 25, 26, 27],
        ["C1-C10-S1-C1", 3, 25, 29, 28],
        ["S1-C1-C10-S1", 4, 3, 25, 29],
        ["C2-C1-C10-S1", 2, 3, 25, 29],
    ]
    molecule_terminating_connections = {"C1": [[2, 1]], "C10": [[2, 1]]}

    # ---==============================================---
    # ---================= Begin run ==================---
    # ---==============================================---

    parameter_file = os.path.realpath(__file__)
    proc_IDs = hf.get_CPU_cores()
    parameter_names = [
        i for i in dir() if (not i.startswith("__")) and (
            not i.startswith("@")) and (not i.startswith("Test")) and (
                not i.startswith("test")) and (i not in [
                    "run_MorphCT",
                    "helper_functions",
                    "hf",
                    "os",
                    "shutil",
                    "TestCommand",
                    "TEST_ROOT",
                    "setup_module",
                    "teardown_module",
                    "testing_tools",
                    "sys",
                    "pytest",
                ])
    ]
    parameters = {}
    for name in parameter_names:
        parameters[name] = locals()[name]
    run_MorphCT.simulation(
        **parameters)  # Execute MorphCT using these simulation parameters
    # The output dictionary from this fixing
    fix_dict = {}

    # Load the output pickle
    output_pickle_data = hf.load_pickle(
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ))
    fix_dict["output_AA_morphology_dict"] = output_pickle_data[0]
    fix_dict["output_CG_morphology_dict"] = output_pickle_data[1]
    fix_dict["output_CG_to_AAID_master"] = output_pickle_data[2]
    fix_dict["output_parameter_dict"] = output_pickle_data[3]
    fix_dict["output_chromophore_list"] = output_pickle_data[4]

    # Load the expected pickle
    expected_pickle_data = hf.load_pickle(
        os.path.join(
            input_morph_dir,
            "FG",
            morphology.replace(".xml", "_post_fine_graining.pickle"),
        ))
    fix_dict["expected_AA_morphology_dict"] = expected_pickle_data[0]
    fix_dict["expected_CG_morphology_dict"] = expected_pickle_data[1]
    fix_dict["expected_CG_to_AAID_master"] = expected_pickle_data[2]
    fix_dict["expected_parameter_dict"] = expected_pickle_data[3]
    fix_dict["expected_chromophore_list"] = expected_pickle_data[4]
    return fix_dict
Example #10
0
def run_simulation():
    # ---==============================================---
    # ---======== Directory and File Structure ========---
    # ---==============================================---

    input_morph_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_morph_dir = os.path.join(TEST_ROOT, "output_TI")
    output_orca_dir = None
    input_device_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_device_dir = os.path.join(TEST_ROOT, "output_TI")

    # ---==============================================---
    # ---========== Input Morphology Details ==========---
    # ---==============================================---

    morphology = "donor_polymer.xml"
    input_sigma = 3.0
    device_morphology = None
    device_components = {}
    overwrite_current_data = True
    random_seed_override = 929292929

    # ---==============================================---
    # ---============= Execution Modules ==============---
    # ---==============================================---

    execute_fine_graining = False  # Requires: None
    execute_molecular_dynamics = False  # Requires: fine_graining
    execute_obtain_chromophores = (
        False)  # Requires: Atomistic morphology, or molecular_dynamics
    execute_ZINDO = False  # Requires: obtain_chromophores
    execute_calculate_transfer_integrals = True  # Requires: execute_ZINDO
    execute_calculate_mobility = False  # Requires: calculate_transfer_integrals
    execute_device_simulation = (
        False
    )  # Requires: calculate_transfer_integrals for all device_components

    remove_orca_inputs = False
    remove_orca_outputs = False

    # ---==============================================---
    # ---================= Begin run ==================---
    # ---==============================================---

    parameter_file = os.path.realpath(__file__)
    proc_IDs = hf.get_CPU_cores()
    parameter_names = [
        i for i in dir() if (not i.startswith("__")) and (
            not i.startswith("@")) and (not i.startswith("Test")) and (
                not i.startswith("test")) and (i not in [
                    "run_MorphCT",
                    "helper_functions",
                    "hf",
                    "os",
                    "shutil",
                    "TestCommand",
                    "TEST_ROOT",
                    "setup_module",
                    "teardown_module",
                    "testing_tools",
                    "sys",
                    "pytest",
                ])
    ]
    parameters = {}
    for name in parameter_names:
        parameters[name] = locals()[name]

    # ---==============================================---
    # ---=============== Setup Prereqs ================---
    # ---==============================================---

    try:
        shutil.rmtree(output_morph_dir)
    except OSError:
        pass
    os.makedirs(
        os.path.join(output_morph_dir,
                     os.path.splitext(morphology)[0], "code"))
    shutil.copy(
        os.path.join(
            TEST_ROOT,
            "assets",
            os.path.splitext(morphology)[0],
            "TI",
            morphology.replace(".xml", "_post_execute_ZINDO.pickle"),
        ),
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ),
    )
    shutil.copytree(
        os.path.join(TEST_ROOT, "assets",
                     os.path.splitext(morphology)[0], "TI", "input_orca"),
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "chromophores",
            "input_orca",
        ),
    )
    shutil.copytree(
        os.path.join(TEST_ROOT, "assets",
                     os.path.splitext(morphology)[0], "TI", "output_orca"),
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "chromophores",
            "output_orca",
        ),
    )

    run_MorphCT.simulation(
        **parameters)  # Execute MorphCT using these simulation parameters
    # The output dictionary from this fixing
    fix_dict = {}

    # Load the output pickle
    output_pickle_data = hf.load_pickle(
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ))
    fix_dict["output_AA_morphology_dict"] = output_pickle_data[0]
    fix_dict["output_CG_morphology_dict"] = output_pickle_data[1]
    fix_dict["output_CG_to_AAID_master"] = output_pickle_data[2]
    fix_dict["output_parameter_dict"] = output_pickle_data[3]
    fix_dict["output_chromophore_list"] = output_pickle_data[4]

    # Load the expected pickle
    expected_pickle_data = hf.load_pickle(
        os.path.join(
            input_morph_dir,
            "TI",
            morphology.replace(".xml",
                               "_post_calculate_transfer_integrals.pickle"),
        ))
    fix_dict["expected_AA_morphology_dict"] = expected_pickle_data[0]
    fix_dict["expected_CG_morphology_dict"] = expected_pickle_data[1]
    fix_dict["expected_CG_to_AAID_master"] = expected_pickle_data[2]
    fix_dict["expected_parameter_dict"] = expected_pickle_data[3]
    fix_dict["expected_chromophore_list"] = expected_pickle_data[4]
    return fix_dict
Example #11
0
 def __init__(self, **kwargs):
     parameter_dict = {}
     # Read in all of the keyword arguments from the par file
     for key, value in kwargs.items():
         self.__dict__[key] = value
     # Obtain the slurm job ID (if there is one)
     self.slurm_job_ID = self.get_slurm_ID()
     # Parse the parameter file to get more useful file locations
     if self.morphology is not None:
         self.input_morphology_file = os.path.join(self.input_morph_dir,
                                                   self.morphology)
         self.output_morphology_directory = os.path.join(
             self.output_morph_dir,
             os.path.splitext(self.morphology)[0])
         if (self.output_orca_dir
                 is not None) and len(self.output_orca_dir) > 0:
             self.output_orca_directory = os.path.join(
                 self.output_orca_dir,
                 os.path.splitext(self.morphology)[0])
         else:
             self.output_orca_directory = self.output_morphology_directory
     if self.device_morphology is not None:
         self.input_device_file = os.path.join(self.input_device_dir,
                                               self.device_morphology)
         self.output_device_directory = os.path.join(
             self.output_device_dir, self.device_morphology)
     # Add all the parameters to the parameterDict, which will be used to
     # send everything between classes
     for key, value in self.__dict__.items():
         if key in ["os", "sys"]:
             continue
         parameter_dict[key] = value
     # Make the correct directory tree
     self.make_dir_tree()
     if self.morphology is not None:
         # Copy the current code and the parameter file for safekeeping
         self.copy_code()
         if self.execute_fine_graining is False:
             # Load any previous data to allow us to run individual phases
             try:
                 pickle_data = hf.load_pickle(
                     os.path.join(
                         self.output_morphology_directory,
                         "code",
                         "".join([
                             os.path.splitext(self.morphology)[0],
                             ".pickle",
                         ]),
                     ))
                 AA_morphology_dict = pickle_data[0]
                 CG_morphology_dict = pickle_data[1]
                 CG_to_AAID_master = pickle_data[2]
                 previous_parameter_dict = pickle_data[3]
                 chromophore_list = pickle_data[4]
                 # Load in any parameters from the previous_parameter_dict
                 # that have not been already defined in the new
                 # parameter_dict (e.g. CG_type_mappings):
                 for key, previous_value in previous_parameter_dict.items():
                     if key not in list(parameter_dict.keys()):
                         parameter_dict[key] = previous_value
                 # We need to make sure that the most up-to-date parameters
                 # for this system (parameter_dict) gets correctly passed
                 # on to the child processes. We do this by re-saving the
                 # pickle using these new parameters.
                 pickle_name = 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",
                     ]),
                 )
                 hf.write_pickle(
                     (
                         AA_morphology_dict,
                         CG_morphology_dict,
                         CG_to_AAID_master,
                         parameter_dict,
                         chromophore_list,
                     ),
                     pickle_name,
                 )
             except:
                 print(
                     "PICKLE NOT FOUND, EXECUTING FINE GRAINING TO OBTAIN REQUIRED"
                     " PARAMETERS...")
                 self.execute_fine_graining = True
         # Now begin running the code based on user's flags
         if self.execute_fine_graining is True:
             print("---=== BACKMAPPING COARSE-GRAINED SITES... ===---")
             returned_data = fine_grainer.morphology(
                 self.input_morphology_file,
                 os.path.splitext(self.morphology)[0],
                 parameter_dict,
                 [],
             ).analyse_morphology()
             AA_morphology_dict = returned_data[0]
             CG_morphology_dict = returned_data[1]
             CG_to_AAID_master = returned_data[2]
             parameter_dict = returned_data[3]
             chromophore_list = returned_data[4]
             print("---=== BACKMAPPING COMPLETED ===---")
         if self.execute_molecular_dynamics is True:
             print("---=== EQUILIBRATING FINE-GRAINED MORPHOLOGY... ===---")
             returned_data = run_HOOMD.main(
                 AA_morphology_dict,
                 CG_morphology_dict,
                 CG_to_AAID_master,
                 parameter_dict,
                 chromophore_list,
             )
             AA_morphology_dict = returned_data[0]
             CG_morphology_dict = returned_data[1]
             CG_to_AAID_master = returned_data[2]
             parameter_dict = returned_data[3]
             chromophore_list = returned_data[4]
             print("---=== EQUILIBRATION COMPLETED ===---")
         if self.execute_obtain_chromophores is True:
             print(
                 "---=== IDENTIFYING CHROMOPHORES OF CHARGE CARRIER DELOCALISATION"
                 "... ===---")
             returned_data = obtain_chromophores.main(
                 AA_morphology_dict,
                 CG_morphology_dict,
                 CG_to_AAID_master,
                 parameter_dict,
                 chromophore_list,
             )
             AA_morphology_dict = returned_data[0]
             CG_morphology_dict = returned_data[1]
             CG_to_AAID_master = returned_data[2]
             parameter_dict = returned_data[3]
             chromophore_list = returned_data[4]
             print("---=== IDENTIFICATION COMPLETED ===---")
         if self.execute_ZINDO is True:
             print(
                 "---=== PERFORMING SEMI-EMPIRICAL ZINDO/S CALCULATIONS... ===---"
             )
             returned_data = execute_ZINDO.main(
                 AA_morphology_dict,
                 CG_morphology_dict,
                 CG_to_AAID_master,
                 parameter_dict,
                 chromophore_list,
             )
             AA_morphology_dict = returned_data[0]
             CG_morphology_dict = returned_data[1]
             CG_to_AAID_master = returned_data[2]
             parameter_dict = returned_data[3]
             chromophore_list = returned_data[4]
             print("---=== CALCULATIONS COMPLETED ===---")
         if self.execute_calculate_transfer_integrals is True:
             print(
                 "---=== DETERMINING ELECTRONIC TRANSFER INTEGRALS... ===---"
             )
             returned_data = transfer_integrals.main(
                 AA_morphology_dict,
                 CG_morphology_dict,
                 CG_to_AAID_master,
                 parameter_dict,
                 chromophore_list,
             )
             AA_morphology_dict = returned_data[0]
             CG_morphology_dict = returned_data[1]
             CG_to_AAID_master = returned_data[2]
             parameter_dict = returned_data[3]
             chromophore_list = returned_data[4]
             print("---=== DETERMINATION COMPLETED ===---")
             if self.remove_orca_inputs is True:
                 print(
                     "remove_orca_inputs is True. Cleaning up orca input dir..."
                 )
                 orca_input_dir = os.path.join(self.output_orca_directory,
                                               "chromophores", "input_orca")
                 try:
                     shutil.rmtree(orca_input_dir)
                 except FileNotFoundError:
                     print("Directory already empty. Continuing...")
             if self.remove_orca_outputs is True:
                 print(
                     "remove_orca_outputs is True. Cleaning up orca output dir..."
                 )
                 orca_output_dir = os.path.join(
                     self.output_orca_directory,
                     "chromophores",
                     "output_orca",
                 )
                 try:
                     shutil.rmtree(orca_output_dir)
                 except FileNotFoundError:
                     print("Directory already empty. Continuing...")
         if self.execute_calculate_mobility is True:
             print(
                 "---=== EXECUTING KINETIC MONTE CARLO MOBILITY SIMULATIONS..."
                 " ===---")
             returned_data = mobility_KMC.main(
                 AA_morphology_dict,
                 CG_morphology_dict,
                 CG_to_AAID_master,
                 parameter_dict,
                 chromophore_list,
             )
             AA_morphology_dict = returned_data[0]
             CG_morphology_dict = returned_data[1]
             CG_to_AAID_master = returned_data[2]
             parameter_dict = returned_data[3]
             chromophore_list = returned_data[4]
             print("---=== EXECUTION COMPLETED ===---")
     else:
         # NEED TO PUT A CHECK IN HERE TO ENSURE THAT WE LOAD THE CORRECT MOLECULAR
         # DATA IN
         if self.execute_device_simulation is True:
             print(
                 "---=== EXECUTING KINETIC MONTE CARLO DEVICE SIMULATIONS... ===---"
             )
             device_KMC.main(parameter_dict)
             print("---=== EXECUTION COMPLETED ===---")
Example #12
0
 def test_outputs_import(self, run_simulation):
     (directory, pickle_file) = run_simulation
     if ".pickle" not in pickle_file:
         pickle_file = "".join(
             [pickle_file, "/code/", pickle_file, ".pickle"])
     hf.load_pickle(os.path.join(directory, pickle_file))
        # and then feed the child process a new seed from the random number
        # stream. This way, we ensure that each child process has a different
        # random number stream to the other processes, but it's the same stream
        # every time we run the program.
        child_seed = np.random.randint(0, 2**32)
        # Previous run command:
        run_command = [
            "python",
            SINGLE_RUN_DEVICE_KMC_FILE,
            output_dir,
            str(proc_ID),
            str(child_seed),
        ]
        print(run_command)
        running_jobs.append(sp.Popen(run_command))
    # Wait for all jobs to complete
    [p.wait() for p in running_jobs]
    print("All KMC jobs completed!")
    # Combine results if required.


if __name__ == "__main__":
    try:
        pickle_file = sys.argv[1]
    except:
        print(
            "Please specify the pickle file to load to continue the pipeline from"
            " this point.")
    _, _, _, parameter_dict, _ = hf.load_pickle(pickle_file)
    main(parameter_dict)
Example #14
0
def run_simulation():
    # ---==============================================---
    # ---======== Directory and File Structure ========---
    # ---==============================================---

    input_morph_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_morph_dir = os.path.join(TEST_ROOT, "output_MKMC")
    output_orca_dir = None
    input_device_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_device_dir = os.path.join(TEST_ROOT, "output_MKMC")

    # ---==============================================---
    # ---========== Input Morphology Details ==========---
    # ---==============================================---

    morphology = "donor_polymer.xml"
    input_sigma = 3.0
    device_morphology = None
    device_components = {}
    overwrite_current_data = True
    random_seed_override = 929292929

    # ---==============================================---
    # ---============= Execution Modules ==============---
    # ---==============================================---

    execute_fine_graining = False  # Requires: None
    execute_molecular_dynamics = False  # Requires: fine_graining
    execute_obtain_chromophores = (
        False)  # Requires: Atomistic morphology, or molecular_dynamics
    execute_ZINDO = False  # Requires: obtain_chromophores
    execute_calculate_transfer_integrals = False  # Requires: execute_ZINDO
    execute_calculate_mobility = True  # Requires: calculate_transfer_integrals
    execute_device_simulation = (
        False
    )  # Requires: calculate_transfer_integrals for all device_components

    # ---==============================================---
    # ---=== General Kinetic Monte Carlo Parameters ===---
    # ---==============================================---

    # ---=== Universal KMC Parameters ===---
    system_temperature = 290
    use_simple_energetic_penalty = False
    record_carrier_history = True
    use_VRH = True

    # ---=== Mobility Specific KMC Parameters ===---
    number_of_holes_per_simulation_time = 10
    number_of_electrons_per_simulation_time = 0
    hop_limit = 0
    simulation_times = [1.00e-13, 1.00e-12, 1.00e-11]
    combine_KMC_results = True
    use_average_hop_rates = False
    average_intra_hop_rate = 8.07E14
    average_inter_hop_rate = 3.92E14

    # ---==============================================---
    # ---================= Begin run ==================---
    # ---==============================================---

    parameter_file = os.path.realpath(__file__)
    # Force serial running
    proc_IDs = [0]
    parameter_names = [
        i for i in dir() if (not i.startswith("__")) and (
            not i.startswith("@")) and (not i.startswith("Test")) and (
                not i.startswith("test")) and (i not in [
                    "run_MorphCT",
                    "helper_functions",
                    "hf",
                    "os",
                    "shutil",
                    "TestCommand",
                    "TEST_ROOT",
                    "setup_module",
                    "teardown_module",
                    "testing_tools",
                    "sys",
                    "pytest",
                    "pickle",
                ])
    ]
    parameters = {}
    for name in parameter_names:
        parameters[name] = locals()[name]

    # ---==============================================---
    # ---=============== Setup Prereqs ================---
    # ---==============================================---

    try:
        shutil.rmtree(output_morph_dir)
    except OSError:
        pass
    os.makedirs(
        os.path.join(output_morph_dir,
                     os.path.splitext(morphology)[0], "code"))
    shutil.copy(
        os.path.join(
            TEST_ROOT,
            "assets",
            os.path.splitext(morphology)[0],
            "MKMC",
            morphology.replace(".xml",
                               "_post_calculate_transfer_integrals.pickle"),
        ),
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ),
    )

    run_MorphCT.simulation(
        **parameters)  # Execute MorphCT using these simulation parameters
    # The output dictionary from this fixing
    fix_dict = {}

    # Load the output pickle
    output_pickle_data = hf.load_pickle(
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ))
    fix_dict["output_AA_morphology_dict"] = output_pickle_data[0]
    fix_dict["output_CG_morphology_dict"] = output_pickle_data[1]
    fix_dict["output_CG_to_AAID_master"] = output_pickle_data[2]
    fix_dict["output_parameter_dict"] = output_pickle_data[3]
    fix_dict["output_chromophore_list"] = output_pickle_data[4]

    # Load the expected pickle
    expected_pickle_data = hf.load_pickle(
        os.path.join(
            input_morph_dir,
            "MKMC",
            morphology.replace(".xml", "_post_calculate_mobility.pickle"),
        ))
    fix_dict["expected_AA_morphology_dict"] = expected_pickle_data[0]
    fix_dict["expected_CG_morphology_dict"] = expected_pickle_data[1]
    fix_dict["expected_CG_to_AAID_master"] = expected_pickle_data[2]
    fix_dict["expected_parameter_dict"] = expected_pickle_data[3]
    fix_dict["expected_chromophore_list"] = expected_pickle_data[4]
    return fix_dict
def run_simulation():
    # ---==============================================---
    # ---======== Directory and File Structure ========---
    # ---==============================================---

    input_morph_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_morph_dir = os.path.join(TEST_ROOT, "output_RH")
    output_orca_dir = None
    input_device_dir = os.path.join(TEST_ROOT, "assets", "donor_polymer")
    output_device_dir = os.path.join(TEST_ROOT, "output_RH")

    # ---==============================================---
    # ---========== Input Morphology Details ==========---
    # ---==============================================---

    morphology = "donor_polymer.xml"
    input_sigma = 3.0
    device_morphology = None
    device_components = {}
    overwrite_current_data = True
    random_seed_override = 929292929

    # ---==============================================---
    # ---============= Execution Modules ==============---
    # ---==============================================---

    execute_fine_graining = False  # Requires: None
    execute_molecular_dynamics = True  # Requires: fine_graining
    execute_obtain_chromophores = (
        False)  # Requires: Atomistic morphology, or molecular_dynamics
    execute_ZINDO = False  # Requires: obtain_chromophores
    execute_calculate_transfer_integrals = False  # Requires: execute_ZINDO
    execute_calculate_mobility = False  # Requires: calculate_transfer_integrals
    execute_device_simulation = (
        False
    )  # Requires: calculate_transfer_integrals for all device_components

    # ---==============================================---
    # ---=========== Forcefield Parameters ============---
    # ---==============================================---

    CG_to_template_dirs = {
        "A": os.path.join(TEST_ROOT, "assets", "donor_polymer"),
        "B": os.path.join(TEST_ROOT, "assets", "donor_polymer"),
        "C": os.path.join(TEST_ROOT, "assets", "donor_polymer"),
    }
    CG_to_template_force_fields = {
        "A": "test_FF.xml",
        "B": "test_FF.xml",
        "C": "test_FF.xml",
    }
    pair_r_cut = 10.0
    pair_dpd_gamma_val = 0.0

    # ---==============================================---
    # ---===== Molecular Dynamics Phase Parameters ====---
    # ---==============================================---

    number_of_phases = 4
    temperatures = [1.0]
    taus = [1.0]
    pair_types = ["none", "dpd", "lj", "lj", "lj", "lj", "lj", "lj"]
    bond_types = ["harmonic"]
    angle_types = ["harmonic"]
    dihedral_types = ["opls"]
    integration_targets = ["all"]
    timesteps = [1E-3, 1E-3, 1E-7, 1E-4]
    durations = [1E5, 5E4, 1E4, 5E4]
    termination_conditions = ["ke_min", "max_t", "max_t", "max_t"]
    group_anchorings = ["all", "all", "all", "none"]
    dcd_file_write = True
    dcd_file_dumpsteps = [0]

    # ---==============================================---
    # ---================= Begin run ==================---
    # ---==============================================---

    parameter_file = os.path.realpath(__file__)
    proc_IDs = hf.get_CPU_cores()
    parameter_names = [
        i for i in dir() if (not i.startswith("__")) and (
            not i.startswith("@")) and (not i.startswith("Test")) and (
                not i.startswith("test")) and (i not in [
                    "run_MorphCT",
                    "helper_functions",
                    "hf",
                    "os",
                    "shutil",
                    "TestCommand",
                    "TEST_ROOT",
                    "setup_module",
                    "teardown_module",
                    "testing_tools",
                    "sys",
                    "pytest",
                ])
    ]
    parameters = {}
    for name in parameter_names:
        parameters[name] = locals()[name]

    # ---==============================================---
    # ---=============== Setup Prereqs ================---
    # ---==============================================---

    try:
        shutil.rmtree(output_morph_dir)
    except OSError:
        pass
    os.makedirs(
        os.path.join(output_morph_dir,
                     os.path.splitext(morphology)[0], "code"))
    shutil.copy(
        os.path.join(
            TEST_ROOT,
            "assets",
            os.path.splitext(morphology)[0],
            "RH",
            morphology.replace(".xml", "_post_fine_graining.pickle"),
        ),
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ),
    )

    run_MorphCT.simulation(
        **parameters)  # Execute MorphCT using these simulation parameters
    # The output dictionary from this fixing
    fix_dict = {}
    # Load the output pickle
    output_pickle_data = hf.load_pickle(
        os.path.join(
            output_morph_dir,
            os.path.splitext(morphology)[0],
            "code",
            morphology.replace(".xml", ".pickle"),
        ))
    fix_dict["output_AA_morphology_dict"] = output_pickle_data[0]
    fix_dict["output_CG_morphology_dict"] = output_pickle_data[1]
    fix_dict["output_CG_to_AAID_master"] = output_pickle_data[2]
    fix_dict["output_parameter_dict"] = output_pickle_data[3]
    fix_dict["output_chromophore_list"] = output_pickle_data[4]
    # Load the expected pickle
    expected_pickle_data = hf.load_pickle(
        os.path.join(input_morph_dir, "RH",
                     morphology.replace(".xml", "_post_run_HOOMD.pickle")))
    fix_dict["expected_AA_morphology_dict"] = expected_pickle_data[0]
    fix_dict["expected_CG_morphology_dict"] = expected_pickle_data[1]
    fix_dict["expected_CG_to_AAID_master"] = expected_pickle_data[2]
    fix_dict["expected_parameter_dict"] = expected_pickle_data[3]
    fix_dict["expected_chromophore_list"] = expected_pickle_data[4]
    return fix_dict