def simulate(file="simulation.pdb.bz2", dir=None, step_size=2.0, snapshot=10, total=1000, model=1, force=True): """Pseudo-Brownian dynamics simulation of the frame order motions. @keyword file: The PDB file for storing the frame order pseudo-Brownian dynamics simulation. The compression is determined automatically by the file extensions '*.pdb', '*.pdb.gz', and '*.pdb.bz2'. @type file: str @keyword dir: The directory name to place the file into. @type dir: str or None @keyword step_size: The rotation will be of a random direction but with this fixed angle. The value is in degrees. @type step_size: float @keyword snapshot: The number of steps in the simulation when snapshots will be taken. @type snapshot: int @keyword total: The total number of snapshots to take before stopping the simulation. @type total: int @keyword model: Only one model from an analysed ensemble of structures can be used for the pseudo-Brownian simulation, as the simulation and corresponding PDB file consists of one model per simulation. @type model: int @keyword force: A flag which, if set to True, will overwrite the any pre-existing file. @type force: bool """ # Printout. print("Pseudo-Brownian dynamics simulation of the frame order motions.") # Checks. check_pipe() check_model() check_domain() check_parameters() check_pivot() # Skip the rigid model. if cdp.model == MODEL_RIGID: print("Skipping the rigid model.") return # Open the output file. file = open_write_file(file_name=file, dir=dir, force=force) # The parameter values. values = assemble_param_vector() params = {} i = 0 for name in cdp.params: params[name] = values[i] i += 1 # The structure. structure = deepcopy(cdp.structure) if structure.num_models() > 1: structure.collapse_ensemble(model_num=model) # The pivot points. num_states = 1 if cdp.model == MODEL_DOUBLE_ROTOR: num_states = 2 pivot = zeros((num_states, 3), float64) for i in range(num_states): pivot[i] = generate_pivot(order=i+1, pdb_limit=True) # Shift to the average position. average_position(structure=structure, models=[None]) # The motional eigenframe. frame = generate_axis_system() # Create the distribution. brownian(file=file, model=cdp.model, structure=structure, parameters=params, eigenframe=frame, pivot=pivot, atom_id=domain_moving(), step_size=step_size, snapshot=snapshot, total=total) # Close the file. file.close()
def distribute(file="distribution.pdb.bz2", dir=None, atom_id=None, total=1000, max_rotations=100000, model=1, force=True): """Create a uniform distribution of structures for the frame order motions. @keyword file: The PDB file for storing the frame order motional distribution. The compression is determined automatically by the file extensions '*.pdb', '*.pdb.gz', and '*.pdb.bz2'. @type file: str @keyword dir: The directory name to place the file into. @type dir: str or None @keyword atom_id: The atom identification string to allow the distribution to be a subset of all atoms. @type atom_id: None or str @keyword total: The total number of states/model/structures in the distribution. @type total: int @keyword max_rotations: The maximum number of rotations to generate the distribution from. This prevents an execution for an infinite amount of time when a frame order amplitude parameter is close to zero so that the subset of all rotations within the distribution is close to zero. @type max_rotations: int @keyword model: Only one model from an analysed ensemble of structures can be used for the distribution, as the corresponding PDB file consists of one model per state. @type model: int @keyword force: A flag which, if set to True, will overwrite the any pre-existing file. @type force: bool """ # Printout. print("Uniform distribution of structures representing the frame order motions.") # Check the total. if total > 9999: raise RelaxError("A maximum of 9999 models is allowed in the PDB format.") # Checks. check_pipe() check_model() check_domain() check_parameters() check_pivot() # Skip the rigid model. if cdp.model == MODEL_RIGID: print("Skipping the rigid model.") return # Open the output file. file = open_write_file(file_name=file, dir=dir, force=force) # The parameter values. values = assemble_param_vector() params = {} i = 0 for name in cdp.params: params[name] = values[i] i += 1 # The structure. structure = deepcopy(cdp.structure) if structure.num_models() > 1: structure.collapse_ensemble(model_num=model) # The pivot points. num_states = 1 if cdp.model == MODEL_DOUBLE_ROTOR: num_states = 2 pivot = zeros((num_states, 3), float64) for i in range(num_states): pivot[i] = generate_pivot(order=i+1, pdb_limit=True) # Shift to the average position. average_position(structure=structure, models=[None]) # The motional eigenframe. frame = generate_axis_system() # Only work with a subset. if atom_id: # The inverted selection. selection = structure.selection(atom_id=atom_id, inv=True) # Delete the data. structure.delete(selection=selection, verbosity=0) # Create the distribution. uniform_distribution(file=file, model=cdp.model, structure=structure, parameters=params, eigenframe=frame, pivot=pivot, atom_id=domain_moving(), total=total, max_rotations=max_rotations) # Close the file. file.close()
def permute_axes(permutation='A'): """Permute the axes of the motional eigenframe to switch between local minima. @keyword permutation: The permutation to use. This can be either 'A' or 'B' to select between the 3 permutations, excluding the current combination. @type permutation: str """ # Check that the model is valid. allowed = MODEL_LIST_ISO_CONE + MODEL_LIST_PSEUDO_ELLIPSE if cdp.model not in allowed: raise RelaxError("The permutation of the motional eigenframe is only valid for the frame order models %s." % allowed) # Check that the model parameters are setup. if cdp.model in MODEL_LIST_ISO_CONE: if not hasattr(cdp, 'cone_theta') or not is_float(cdp.cone_theta): raise RelaxError("The parameter values are not set up.") else: if not hasattr(cdp, 'cone_theta_y') or not is_float(cdp.cone_theta_y): raise RelaxError("The parameter values are not set up.") # The iso cones only have one permutation. if cdp.model in MODEL_LIST_ISO_CONE and permutation == 'B': raise RelaxError("The isotropic cones only have one permutation.") # The angles. cone_sigma_max = 0.0 if cdp.model in MODEL_LIST_RESTRICTED_TORSION: cone_sigma_max = cdp.cone_sigma_max elif cdp.model in MODEL_LIST_FREE_ROTORS: cone_sigma_max = pi if cdp.model in MODEL_LIST_ISO_CONE: angles = array([cdp.cone_theta, cdp.cone_theta, cone_sigma_max], float64) else: angles = array([cdp.cone_theta_x, cdp.cone_theta_y, cone_sigma_max], float64) x, y, z = angles # The axis system. axes = generate_axis_system() # Start printout for the isotropic cones. if cdp.model in MODEL_LIST_ISO_CONE: print("\nOriginal parameters:") print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta)) print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max)) print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta)) print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi)) print("%-20s\n%s" % ("cone axis", axes[:, 2])) print("%-20s\n%s" % ("full axis system", axes)) print("\nPermutation '%s':" % permutation) # Start printout for the pseudo-ellipses. else: print("\nOriginal parameters:") print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x)) print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y)) print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max)) print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha)) print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta)) print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma)) print("%-20s\n%s" % ("eigenframe", axes)) print("\nPermutation '%s':" % permutation) # The axis inversion structure. inv = ones(3, float64) # The starting condition x <= y <= z. if x <= y and y <= z: # Printout. print("%-20s %-20s" % ("Starting condition", "x <= y <= z")) # The cone angle and axes permutations. if permutation == 'A': perm_angles = [0, 2, 1] perm_axes = [2, 1, 0] inv[perm_axes[2]] = -1.0 else: perm_angles = [1, 2, 0] perm_axes = [2, 0, 1] # The starting condition x <= z <= y. elif x <= z and z <= y: # Printout. print("%-20s %-20s" % ("Starting condition", "x <= z <= y")) # The cone angle and axes permutations. if permutation == 'A': perm_angles = [0, 2, 1] perm_axes = [2, 1, 0] inv[perm_axes[2]] = -1.0 else: perm_angles = [2, 1, 0] perm_axes = [0, 2, 1] inv[perm_axes[2]] = -1.0 # The starting condition z <= x <= y. elif z <= x and x <= y: # Printout. print("%-20s %-20s" % ("Starting condition", "z <= x <= y")) # The cone angle and axes permutations. if permutation == 'A': perm_angles = [2, 0, 1] perm_axes = [1, 2, 0] else: perm_angles = [2, 1, 0] perm_axes = [0, 2, 1] inv[perm_axes[2]] = -1.0 # Cannot be here. else: raise RelaxFault # Printout. print("%-20s %-20s" % ("Cone angle permutation", perm_angles)) print("%-20s %-20s" % ("Axes permutation", perm_axes)) # Permute the angles. if cdp.model in MODEL_LIST_ISO_CONE: cdp.cone_theta = (angles[perm_angles[0]] + angles[perm_angles[1]]) / 2.0 else: cdp.cone_theta_x = angles[perm_angles[0]] cdp.cone_theta_y = angles[perm_angles[1]] if cdp.model in MODEL_LIST_RESTRICTED_TORSION: cdp.cone_sigma_max = angles[perm_angles[2]] elif cdp.model in MODEL_LIST_FREE_ROTORS: cdp.cone_sigma_max = pi # Permute the axes (iso cone). if cdp.model in MODEL_LIST_ISO_CONE: # Convert the y-axis to spherical coordinates (the x-axis would be ok too, or any vector in the x-y plane due to symmetry of the original permutation). axis_new = axes[:, 1] r, cdp.axis_theta, cdp.axis_phi = cartesian_to_spherical(axis_new) # Permute the axes (pseudo-ellipses). else: axes_new = transpose(array([inv[0]*axes[:, perm_axes[0]], inv[1]*axes[:, perm_axes[1]], inv[2]*axes[:, perm_axes[2]]], float64)) # Convert the permuted frame to Euler angles and store them. cdp.eigen_alpha, cdp.eigen_beta, cdp.eigen_gamma = R_to_euler_zyz(axes_new) # End printout. if cdp.model in MODEL_LIST_ISO_CONE: print("\nPermuted parameters:") print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta)) if cdp.model == MODEL_ISO_CONE: print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max)) print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta)) print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi)) print("%-20s\n%s" % ("cone axis", axis_new)) else: print("\nPermuted parameters:") print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x)) print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y)) if cdp.model == MODEL_PSEUDO_ELLIPSE: print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max)) print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha)) print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta)) print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma)) print("%-20s\n%s" % ("eigenframe", axes_new))
def simulate(file="simulation.pdb.bz2", dir=None, step_size=2.0, snapshot=10, total=1000, model=1, force=True): """Pseudo-Brownian dynamics simulation of the frame order motions. @keyword file: The PDB file for storing the frame order pseudo-Brownian dynamics simulation. The compression is determined automatically by the file extensions '*.pdb', '*.pdb.gz', and '*.pdb.bz2'. @type file: str @keyword dir: The directory name to place the file into. @type dir: str or None @keyword step_size: The rotation will be of a random direction but with this fixed angle. The value is in degrees. @type step_size: float @keyword snapshot: The number of steps in the simulation when snapshots will be taken. @type snapshot: int @keyword total: The total number of snapshots to take before stopping the simulation. @type total: int @keyword model: Only one model from an analysed ensemble of structures can be used for the pseudo-Brownian simulation, as the simulation and corresponding PDB file consists of one model per simulation. @type model: int @keyword force: A flag which, if set to True, will overwrite the any pre-existing file. @type force: bool """ # Printout. print("Pseudo-Brownian dynamics simulation of the frame order motions.") # Checks. check_pipe() check_model() check_domain() check_parameters() check_pivot() # Skip the rigid model. if cdp.model == MODEL_RIGID: print("Skipping the rigid model.") return # Open the output file. file = open_write_file(file_name=file, dir=dir, force=force) # The parameter values. values = assemble_param_vector() params = {} i = 0 for name in cdp.params: params[name] = values[i] i += 1 # The structure. structure = deepcopy(cdp.structure) if structure.num_models() > 1: structure.collapse_ensemble(model_num=model) # The pivot points. num_states = 1 if cdp.model == MODEL_DOUBLE_ROTOR: num_states = 2 pivot = zeros((num_states, 3), float64) for i in range(num_states): pivot[i] = generate_pivot(order=i + 1, pdb_limit=True) # Shift to the average position. average_position(structure=structure, models=[None]) # The motional eigenframe. frame = generate_axis_system() # Create the distribution. brownian(file=file, model=cdp.model, structure=structure, parameters=params, eigenframe=frame, pivot=pivot, atom_id=domain_moving(), step_size=step_size, snapshot=snapshot, total=total) # Close the file. file.close()
def distribute(file="distribution.pdb.bz2", dir=None, atom_id=None, total=1000, max_rotations=100000, model=1, force=True): """Create a uniform distribution of structures for the frame order motions. @keyword file: The PDB file for storing the frame order motional distribution. The compression is determined automatically by the file extensions '*.pdb', '*.pdb.gz', and '*.pdb.bz2'. @type file: str @keyword dir: The directory name to place the file into. @type dir: str or None @keyword atom_id: The atom identification string to allow the distribution to be a subset of all atoms. @type atom_id: None or str @keyword total: The total number of states/model/structures in the distribution. @type total: int @keyword max_rotations: The maximum number of rotations to generate the distribution from. This prevents an execution for an infinite amount of time when a frame order amplitude parameter is close to zero so that the subset of all rotations within the distribution is close to zero. @type max_rotations: int @keyword model: Only one model from an analysed ensemble of structures can be used for the distribution, as the corresponding PDB file consists of one model per state. @type model: int @keyword force: A flag which, if set to True, will overwrite the any pre-existing file. @type force: bool """ # Printout. print( "Uniform distribution of structures representing the frame order motions." ) # Check the total. if total > 9999: raise RelaxError( "A maximum of 9999 models is allowed in the PDB format.") # Checks. check_pipe() check_model() check_domain() check_parameters() check_pivot() # Skip the rigid model. if cdp.model == MODEL_RIGID: print("Skipping the rigid model.") return # Open the output file. file = open_write_file(file_name=file, dir=dir, force=force) # The parameter values. values = assemble_param_vector() params = {} i = 0 for name in cdp.params: params[name] = values[i] i += 1 # The structure. structure = deepcopy(cdp.structure) if structure.num_models() > 1: structure.collapse_ensemble(model_num=model) # The pivot points. num_states = 1 if cdp.model == MODEL_DOUBLE_ROTOR: num_states = 2 pivot = zeros((num_states, 3), float64) for i in range(num_states): pivot[i] = generate_pivot(order=i + 1, pdb_limit=True) # Shift to the average position. average_position(structure=structure, models=[None]) # The motional eigenframe. frame = generate_axis_system() # Only work with a subset. if atom_id: # The inverted selection. selection = structure.selection(atom_id=atom_id, inv=True) # Delete the data. structure.delete(selection=selection, verbosity=0) # Create the distribution. uniform_distribution(file=file, model=cdp.model, structure=structure, parameters=params, eigenframe=frame, pivot=pivot, atom_id=domain_moving(), total=total, max_rotations=max_rotations) # Close the file. file.close()
def permute_axes(permutation='A'): """Permute the axes of the motional eigenframe to switch between local minima. @keyword permutation: The permutation to use. This can be either 'A' or 'B' to select between the 3 permutations, excluding the current combination. @type permutation: str """ # Check that the model is valid. allowed = MODEL_LIST_ISO_CONE + MODEL_LIST_PSEUDO_ELLIPSE if cdp.model not in allowed: raise RelaxError( "The permutation of the motional eigenframe is only valid for the frame order models %s." % allowed) # Check that the model parameters are setup. if cdp.model in MODEL_LIST_ISO_CONE: if not hasattr(cdp, 'cone_theta') or not is_float(cdp.cone_theta): raise RelaxError("The parameter values are not set up.") else: if not hasattr(cdp, 'cone_theta_y') or not is_float(cdp.cone_theta_y): raise RelaxError("The parameter values are not set up.") # The iso cones only have one permutation. if cdp.model in MODEL_LIST_ISO_CONE and permutation == 'B': raise RelaxError("The isotropic cones only have one permutation.") # The angles. cone_sigma_max = 0.0 if cdp.model in MODEL_LIST_RESTRICTED_TORSION: cone_sigma_max = cdp.cone_sigma_max elif cdp.model in MODEL_LIST_FREE_ROTORS: cone_sigma_max = pi if cdp.model in MODEL_LIST_ISO_CONE: angles = array([cdp.cone_theta, cdp.cone_theta, cone_sigma_max], float64) else: angles = array([cdp.cone_theta_x, cdp.cone_theta_y, cone_sigma_max], float64) x, y, z = angles # The axis system. axes = generate_axis_system() # Start printout for the isotropic cones. if cdp.model in MODEL_LIST_ISO_CONE: print("\nOriginal parameters:") print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta)) print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max)) print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta)) print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi)) print("%-20s\n%s" % ("cone axis", axes[:, 2])) print("%-20s\n%s" % ("full axis system", axes)) print("\nPermutation '%s':" % permutation) # Start printout for the pseudo-ellipses. else: print("\nOriginal parameters:") print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x)) print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y)) print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max)) print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha)) print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta)) print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma)) print("%-20s\n%s" % ("eigenframe", axes)) print("\nPermutation '%s':" % permutation) # The axis inversion structure. inv = ones(3, float64) # The starting condition x <= y <= z. if x <= y and y <= z: # Printout. print("%-20s %-20s" % ("Starting condition", "x <= y <= z")) # The cone angle and axes permutations. if permutation == 'A': perm_angles = [0, 2, 1] perm_axes = [2, 1, 0] inv[perm_axes[2]] = -1.0 else: perm_angles = [1, 2, 0] perm_axes = [2, 0, 1] # The starting condition x <= z <= y. elif x <= z and z <= y: # Printout. print("%-20s %-20s" % ("Starting condition", "x <= z <= y")) # The cone angle and axes permutations. if permutation == 'A': perm_angles = [0, 2, 1] perm_axes = [2, 1, 0] inv[perm_axes[2]] = -1.0 else: perm_angles = [2, 1, 0] perm_axes = [0, 2, 1] inv[perm_axes[2]] = -1.0 # The starting condition z <= x <= y. elif z <= x and x <= y: # Printout. print("%-20s %-20s" % ("Starting condition", "z <= x <= y")) # The cone angle and axes permutations. if permutation == 'A': perm_angles = [2, 0, 1] perm_axes = [1, 2, 0] else: perm_angles = [2, 1, 0] perm_axes = [0, 2, 1] inv[perm_axes[2]] = -1.0 # Cannot be here. else: raise RelaxFault # Printout. print("%-20s %-20s" % ("Cone angle permutation", perm_angles)) print("%-20s %-20s" % ("Axes permutation", perm_axes)) # Permute the angles. if cdp.model in MODEL_LIST_ISO_CONE: cdp.cone_theta = (angles[perm_angles[0]] + angles[perm_angles[1]]) / 2.0 else: cdp.cone_theta_x = angles[perm_angles[0]] cdp.cone_theta_y = angles[perm_angles[1]] if cdp.model in MODEL_LIST_RESTRICTED_TORSION: cdp.cone_sigma_max = angles[perm_angles[2]] elif cdp.model in MODEL_LIST_FREE_ROTORS: cdp.cone_sigma_max = pi # Permute the axes (iso cone). if cdp.model in MODEL_LIST_ISO_CONE: # Convert the y-axis to spherical coordinates (the x-axis would be ok too, or any vector in the x-y plane due to symmetry of the original permutation). axis_new = axes[:, 1] r, cdp.axis_theta, cdp.axis_phi = cartesian_to_spherical(axis_new) # Permute the axes (pseudo-ellipses). else: axes_new = transpose( array([ inv[0] * axes[:, perm_axes[0]], inv[1] * axes[:, perm_axes[1]], inv[2] * axes[:, perm_axes[2]] ], float64)) # Convert the permuted frame to Euler angles and store them. cdp.eigen_alpha, cdp.eigen_beta, cdp.eigen_gamma = R_to_euler_zyz( axes_new) # End printout. if cdp.model in MODEL_LIST_ISO_CONE: print("\nPermuted parameters:") print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta)) if cdp.model == MODEL_ISO_CONE: print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max)) print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta)) print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi)) print("%-20s\n%s" % ("cone axis", axis_new)) else: print("\nPermuted parameters:") print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x)) print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y)) if cdp.model == MODEL_PSEUDO_ELLIPSE: print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max)) print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha)) print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta)) print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma)) print("%-20s\n%s" % ("eigenframe", axes_new))
def decompose(root="decomposed", dir=None, atom_id=None, model=1, force=True): """Structural representation of the individual frame order motional components. @keyword root: The file root for the PDB files created. Each motional component will be represented by a different PDB file appended with '_mode1.pdb', '_mode2.pdb', '_mode3.pdb', etc. @type root: str @keyword dir: The directory name to place the file into. @type dir: str or None @keyword atom_id: The atom identification string to allow the decomposition to be applied to subset of all atoms. @type atom_id: None or str @keyword model: Only one model from an analysed ensemble of structures can be used for the decomposition, as the corresponding PDB file consists of one model per state. @type model: int @keyword force: A flag which, if set to True, will overwrite the any pre-existing file. @type force: bool """ # Printout. print( "PDB representation of the individual components of the frame order motions." ) # Checks. check_pipe() check_model() check_domain() check_parameters() check_pivot() # Skip any unsupported models. unsupported = [MODEL_RIGID, MODEL_DOUBLE_ROTOR] if cdp.model in unsupported: print("Skipping the unsupported '%s' model." % cdp.model) return # Initialise the angle vector (cone opening angle 1, cone opening angle 2, torsion angle). angles = zeros(3, float64) # Cone opening. if cdp.model in MODEL_LIST_ISO_CONE: angles[0] = angles[1] = cdp.cone_theta elif cdp.model in MODEL_LIST_PSEUDO_ELLIPSE: angles[0] = cdp.cone_theta_y angles[1] = cdp.cone_theta_x # Non-zero torsion angle. if cdp.model in MODEL_LIST_FREE_ROTORS: angles[2] = pi elif cdp.model in MODEL_LIST_RESTRICTED_TORSION: angles[2] = cdp.cone_sigma_max # The motional eigenframe. frame = generate_axis_system() # Mode ordering from largest to smallest. indices = argsort(angles) angles = angles[indices[::-1]] frame = transpose(transpose(frame)[indices[::-1]]) # The pivot point. pivot = generate_pivot(order=1, pdb_limit=True) # Loop over each mode. for i in range(3): # Skip modes with no motion. if angles[i] < 1e-7: continue # Open the output file. file_name = "%s_mode%i.pdb" % (root, i + 1) file = open_write_file(file_name=file_name, dir=dir, force=force) # The structure. structure = deepcopy(cdp.structure) if structure.num_models() > 1: structure.collapse_ensemble(model_num=model) # Shift to the average position. average_position(structure=structure, models=[None]) # Create the representation. mode_distribution(file=file, structure=structure, axis=frame[:, i], angle=angles[i], pivot=pivot, atom_id=domain_moving()) # Close the file. file.close()