def Closest_Rotamers(experiment, gn = None):
    """Assign the Closest Rotamers to amino acids in Design Molecules"""
    # Make sure the experiment is an experiment
    if not isinstance(experiment, EXPERIMENT.Experiment):
        text = "The Closest Rotamers function requires an Experiment class "
        text += "object as its input."
        raise IPRO_Error(text)
    # Start timing this
    startTime = time.time()
    # Loop through the Design Groups
    for group in experiment:
        if gn not in [None, group.number]:
            continue
        # Time the group
        groupTime = time.time()
        # Go through the amino acids of the Design Molecules
        for molecule in group:
            for residue in molecule:
                if molecule.design and residue.kind in \
                aminoAcids[residue.fileFormat]:
                    residue.permission = "ISOMER"
                else:
                    residue.permission = "FIXED"
        # use the ROTAMERS function
        ROTAMERS.Closest_Rotamer(group, experiment)
        # Update the summary
        experiment["Summary"] += SHARING.summary_update(groupTime, \
        "Assigning the Closest Rotamers to Design Group " + str(group.number))
    if gn == None:
        experiment["Summary"] += SHARING.summary_update(groupTime, \
                                 "The Closest Rotamers function")
def Optimal_Rotamers(experiment, gn = None):
    """Select an optimal combination of Rotamers for a system"""
    # Do the standard starting checks
    if not isinstance(experiment, EXPERIMENT.Experiment):
        text = "The Optimal Rotamers function requires an Experiment class "
        text += "object as its input."
        raise IPRO_Error(text)
    refinement = refinement_check(experiment, gn)
    if refinement:
        return refinement, "success"
    # Start timing this
    startTime = time.time()
    # Determine the group that will have mutations done for it
    if gn == None:
        N = 1
    else:
        N = gn
    # Do this for each Design Group
    for group in experiment:
        if gn not in [None, group.number]:
            continue
        # Time the group
        groupTime = time.time()
        # Make sure the amino acid sequences match across Design Groups
        if group.number != N:
            for molecule in group:
                for residue in molecule:
                    if residue.design and residue.permission == "ROTAMER":
                        residue.permittedKinds = \
                        [experiment[N][molecule.name][residue.name].kind]
        # Pick the Rotamers
        probability = True
        objective, solution = ROTAMERS.Optimal_Rotamers(group, experiment, probability)
        # Summarize the results
        message = ''
        if group.number == N:
            for molecule in group:
                for residue in molecule:
                    if residue.permission == "ROTAMER":
                        # Summarize the Residue
                        message += "Residue " + residue.name + " in Molecule "
                        message += molecule.name + ": " + residue.kind + "\n"
        if solution:
            message += "The objective value of the MILP was " + format(objective, \
                   '.3f') + "\n"
            experiment["Summary"] += SHARING.summary_update(groupTime, \
            "Selecting Rotamers for Design Group " + str(group.number), message)
            return refinement, "success"
        else:
            message += "No rotamers are selected "
            experiment["Summary"] += SHARING.summary_update(groupTime, \
            "No selecting Rotamers for Design Group " + str(group.number), message)
            return refinement, "failure"
def Calculate_Energy(experiment, gn = None):
    """Calculate the energies of an IPRO iteration"""
    # Do the standard introductory checks
    if not isinstance(experiment, EXPERIMENT.Experiment):
        text = "The Calculate Energy function requires an Experiment class "
        text += "object as its input."
        raise IPRO_Error(text)
    refinement = refinement_check(experiment, gn)
    if refinement:
        return {}, refinement
    # Start timing
    startTime = time.time()
    # Store the energies here
    energies = {}
    # Loop through the Design Groups
    for group in experiment:
        if gn not in [None, group.number]:
            continue
        # Time the group
        groupTime = time.time()
        # initialize the dictionary
        energies[group.number] = {}
        # If there are no Target Molecules, it is impossible to calculate an
        # interaction energy
        do = False
        for molecule in group:
            if not molecule.design:
                do = True
                break
        # Calculate the energies
        if experiment["Force Field"] == "CHARMM":
            complex = CHARMM.Energy(group, experiment, "all")
            energies[group.number]["Complex"] = complex
            if do:
                design = CHARMM.Energy(group, experiment, True)
                target = CHARMM.Energy(group, experiment, False)
                energies[group.number]["Interaction"] = complex-design-target
        else:
            text = "The Calculate Energy function does not support the "
            text += str(experiment["Force Field"]) + " force field."
            raise IPRO_Error(text)
        # update the summary
        if gn == None:
            experiment["Summary"] += SHARING.summary_update(groupTime, \
            "Energy Calculation for Design Group " + str(group.number))
        experiment["Summary"] +=SHARING.format_energies(energies[group.number],\
                                group.number, False)
    experiment["Summary"] += SHARING.summary_update(startTime, \
                             "The Calculate Energy function")
    return energies, refinement
def Relaxation(experiment, gn = None, all = True):
    """Do an energy minimization"""
    # Make sure we have an Experiment
    if not isinstance(experiment, EXPERIMENT.Experiment):
        text = "The Relaxation function requires an Experiment class object as "
        text += "its input."
        raise IPRO_Error(text)
    # Check to see if a refinement is happening
    refinement = refinement_check(experiment, gn)
    if refinement:
        return refinement
    # Start timing
    startTime = time.time()
    # Loop through the relevant Design Groups
    for group in experiment:
        if gn not in [None, group.number]:
            continue
        # Time the group
        groupTime = time.time()
        # If appropriate, free all Residues
        if all:
            for molecule in group:
                for residue in molecule:
                    residue.freedom = "FREE"
        # If appropriate, superimpose the reference structures of Molecules
        for molecule in group:
            # Design Molecules never need to have structures superimposed
            if not molecule.design:
                if experiment["Superimpose"][group.number][molecule.name]:
                    superimpose(molecule, experiment[0][molecule.name])
        # Do the relaxation
        if experiment["Force Field"] == "CHARMM":
            CHARMM.Relaxation(group, experiment)
        else:
            text = "The Relaxation function does not support the "
            text += str(experiment["Force Field"]) + " force field."
            raise IPRO_Error(text)
        # update the summary
        if gn == None:
            experiment["Summary"] += SHARING.summary_update(groupTime, \
            "The Relaxation of Design Group " + str(group.number))
    experiment["Summary"] += SHARING.summary_update(startTime, \
                             "The Relaxation function")
    return refinement
def Docking(experiment, iteration, gn = None):
    """Carry out a local, rigid body docking of Target Molecules"""
    # Do the standard initial checks
    if not isinstance(experiment, EXPERIMENT.Experiment):
        text = "The Docking function requires an Experiment class object as its"
        text += " input."
        raise IPRO_Error(text)
    refinement = refinement_check(experiment, gn)
    if refinement:
        return False, refinement
    # Make sure Docking should be run in this iteration
    if iteration % experiment["Docking Frequency"] != 0:
        return False, refinement
    # Time this
    startTime = time.time()
    # Collect the groups of Molecules that will move during docking
    dockingGroups = DOCKING_FUNCTIONS.collect_docking_groups(experiment, gn)
    # If there aren't any, say that
    if len(dockingGroups) == 0:
        experiment["Summary"] += "There were no Molecules that could move "
        experiment["Summary"] += "during docking.\n"
        return False, refinement
    # Store the names of all files generated by this function
    fileNames = []
    # Create all of the information and structures needed to run Docking
    information, movingMolecules = DOCKING_FUNCTIONS.create_moving_structures(\
                                   experiment, dockingGroups, fileNames)
    DOCKING_FUNCTIONS.create_static_structures(experiment, movingMolecules, \
                                               fileNames)
    DOCKING_FUNCTIONS.make_docking_information(experiment, dockingGroups, \
                                               information, fileNames)
    # Run docking
    i = os.system("./docking.out")
    if i != 0:
        text = "There was an error running the executable docking.out file."
        raise IPRO_Error(text)
    # Load the results from docking
    message = DOCKING_FUNCTIONS.load_docking_results(experiment, dockingGroups,\
                                                     fileNames)
    DOCKING_FUNCTIONS.load_docking_structures(experiment, dockingGroups)
    # Delete all of the files made by docking
    for fileName in fileNames:
        try:
            os.remove(fileName)
        except OSError:
            pass
    # Update the summary
    experiment["Summary"] += SHARING.summary_update(startTime, \
                             "The Docking function", message)
    # Return that docking ran and that a refinement is not currently ongoing
    return True, refinement
def Backbone_Perturbation(experiment, gn = None):
    """Perturb the Backbone of a Molecule"""
    # Make sure the experiment is an Experiment
    if not isinstance(experiment, EXPERIMENT.Experiment):
        text = "The Backbone Perturbation function requires an Experiment class"
        text += " object as its input"
        raise IPRO_Error(text)
    # Find out if a refinement is happening
    refinement = refinement_check(experiment, gn)
    if refinement:
        return refinement
    # Assign the closest rotamers to all Residues
    #Closest_Rotamers(experiment, gn)
    # Start timing this
    startTime = time.time()
    # Determine which Group to make the perturbation selections for
    if gn == None:
        N = 1
    else:
        N = gn
    # Choose the perturbation location
    spot = select_perturbation_position(experiment)
    # Choose the perturbation region
    experiment["Summary"] += "Residue " + spot[1] + " in Molecule " + spot[0]
    experiment["Summary"] += " selected as the Perturbation Position\n"
    perturbed = select_perturbation_region(experiment, experiment[N], spot)
    if len(perturbed) > 1:
        items = []
        for spot in perturbed:
            items.append("Residue " + spot[1] + " in Molecule " + spot[0])
        text = screen_formatting("Perturbing" + list_items(items) + "\n")
        experiment["Summary"] += text
    initialMolecule = experiment[N][spot[0]]
    #sequence = DEIMMUNIZATION.extract_sequence_molecule(initialMolecule)
    #fs = open("sequence.txt", "w")
    #fs.write(sequence)
    #fs.close()
    # Generate the random perturbation angles
    angles = generate_angles(experiment[N], perturbed)
    # Loop through the Design Groups
    for group in experiment:
        if gn not in [None, group.number]:
            continue
        # Time the group
        groupTime = time.time()
        # Assign freedoms and permissions
        if group.number == N:
            # Set based on sequence
            sequence_setting(experiment, group, perturbed)
            # Set based on distance (will only work if appropriate)
            distance_setting(experiment, group)
            # Match Dimer information
            Dimers(experiment, group, angles)
        # Otherwise, match things to the Number group
        else:
            for m in group:
                for r in m:
                    # If this is a Target Molecule, freeze it
                    if not m.design:
                        r.freedom = "FIXED"
                        r.permission = "FIXED"
                    else:
                        r.currentKind = r.kind
                        r.freedom = experiment[N][m.name][r.name].freedom
                        r.permission = experiment[N][m.name][r.name].permission
        # Mutate to Glycines
        ROTAMERS.Glycine(group, experiment)
        # Perturb the backbone
        if experiment["Force Field"] == "CHARMM":
            CHARMM.Perturbation(group, angles, experiment)
        else:
            text = "The Backbone Perturbation function does not support the "
            text += str(experiment["Force Field"]) + " force field."
            raise IPRO_Error(text)
        # Update the summary
        if gn == None:
            experiment["Summary"] += SHARING.summary_update(groupTime, \
                        "Perturbing Design Group " + str(group.number))
    experiment["Summary"] += SHARING.summary_update(startTime, \
                             "The Backbone Perturbation function")
    return refinement