Symmetry restraints

You can restrain two groups of atoms to be the same during optimization of the objective function. This is achieved by adding the sum of squares of the differences between the equivalent distances (similar to distance RMS deviation) to the objective function being optimized. See Equation A.99.

After creating a `Symmetry` object, you can call its `append` function
to add additional pairs of groups. This allows some equivalent atoms to be
weighted more strongly than others. Finally, add the `Symmetry` object to
the *Restraints.symmetry* list.

`Symmetry(set1, set2, weight)`

Creates a new symmetry restraint which will constrain the interatomic distances
in `set1` to be the same as in `set2`. (The `append` function takes the
same parameters.) Both sets are just lists of atoms or objects which contain
atoms, such as `Residue` or `Selection` objects. Note that each
set must contain the same number of atoms. Note also that the order is
important. (If using `Selection` objects, the atoms are always sorted
in the same order as seen in the PDB file.)

See Section 2.2.13 for an example of using symmetry
restraints with the `AutoModel` class.

**Example: examples/commands/define_symmetry.py**-

# Example for: Model.symmetry.define() # This will force two copies of 1fas to have similar mainchain # conformation. from modeller import * from modeller.scripts import complete_pdb from modeller.optimizers import ConjugateGradients, MolecularDynamics log.level(1, 1, 1, 1, 0) env = Environ() env.io.atom_files_directory = ['../atom_files'] env.libs.topology.read(file='$(LIB)/top_heav.lib') env.libs.parameters.read(file='$(LIB)/par.lib') def defsym(mdl, seg1, seg2): sel1 = Selection(mdl.residue_range(*seg1)).only_mainchain() sel2 = Selection(mdl.residue_range(*seg2)).only_mainchain() mdl.restraints.symmetry.append(Symmetry(sel1, sel2, 1.0)) # Generate two copies of a segment: mdl = complete_pdb(env, '2abx', model_segment=('1:A', '74:B')) mdl.rename_segments(segment_ids=('A', 'B'), renumber_residues=(1, 1)) myedat = EnergyData(dynamic_sphere = False) atmsel = Selection(mdl) atmsel.energy(edat=myedat) atmsel.randomize_xyz(deviation=6.0) # Define the two segments (chains in this case) to be identical: defsym(mdl, seg1=('1:A', '74:A'), seg2=('1:B', '74:B')) # Create optimizer objects cg = ConjugateGradients() md = MolecularDynamics(md_return='FINAL') # Make them identical by optimizing the initial randomized structure # without any other restraints: atmsel.energy(edat=myedat) mdl.write(file='define_symmetry-1.atm') cg.optimize(atmsel, max_iterations=300, edat=myedat) mdl.write(file='define_symmetry-2.atm') atmsel.energy(edat=myedat) # Now optimize with stereochemical restraints so that the # result is not so distorted a structure (still distorted # because optimization is not thorough): myedat.dynamic_sphere = True mdl.restraints.make(atmsel, restraint_type='stereo', spline_on_site=False, edat=myedat) atmsel.randomize_xyz(deviation=3.0) for method in (cg, md, cg): method.optimize(atmsel, max_iterations=300, edat=myedat, output='REPORT') mdl.write(file='define_symmetry-3.atm') atmsel.energy(edat=myedat) # Report on symmetry violations mdl.restraints.symmetry.report(0.3) # Create a blank alignment so that superpose uses its 1:1 default aln = Alignment(env) mdl = Model(env, file='define_symmetry-3.atm', model_segment=('1:A', '74:A')) mdl2 = Model(env, file='define_symmetry-3.atm', model_segment=('1:B', '74:B')) atmsel = Selection(mdl).only_mainchain() atmsel.superpose(mdl2, aln)