1 """@namespace IMP.pmi.restraints.stereochemistry
2 Restraints for keeping correct stereochemistry.
5 from __future__
import print_function
15 from operator
import itemgetter
16 from math
import pi,log,sqrt
21 """ This class creates a restraint between consecutive TempResidue objects OR an entire
22 PMI MOlecule object. """
27 disorderedlength=
False,
31 @param objects - a list of hierarchies, PMI TempResidues OR a single Molecule
32 @param scale - Riccardo knows what this is
33 @param disorderedlength - This flag uses either disordered length
34 calculated for random coil peptides (True) or zero
35 surface-to-surface distance between beads (False)
36 as optimal distance for the sequence connectivity
38 @param upperharmonic - This flag uses either harmonic (False)
39 or upperharmonic (True) in the intra-pair
40 connectivity restraint.
41 @parm resolution The resolution to connect things at - only used if you pass PMI objects
48 raise Exception(
"ConnectivityRestraint: only pass stuff from one Molecule, please")
52 self.m = list(hiers)[0].get_model()
68 SortedSegments.append((start, end, startres))
69 SortedSegments = sorted(SortedSegments, key=itemgetter(2))
72 for x
in range(len(SortedSegments) - 1):
74 last = SortedSegments[x][1]
75 first = SortedSegments[x + 1][0]
77 apply_restraint =
True
91 apply_restraint =
False
100 residuegap = firstresn - lastresn - 1
101 if disorderedlength
and (nreslast / 2 + nresfirst / 2 + residuegap) > 20.0:
104 optdist = sqrt(5 / 3) * 1.93 * \
105 (nreslast / 2 + nresfirst / 2 + residuegap) ** 0.6
113 optdist = (0.0 + (float(residuegap) + 1.0) * 3.6) * scale
120 pt0 = last.get_particle()
121 pt1 = first.get_particle()
124 print(
"Adding sequence connectivity restraint between", pt0.get_name(),
" and ", pt1.get_name(),
'of distance', optdist)
125 self.rs.add_restraint(r)
128 def set_label(self, label):
131 def get_weight(self):
134 def add_to_model(self):
137 def get_restraint(self):
140 def set_weight(self, weight):
142 self.rs.set_weight(weight)
144 def get_output(self):
147 score = self.weight * self.rs.unprotected_evaluate(
None)
148 output[
"_TotalScore"] = str(score)
149 output[
"ConnectivityRestraint_" + self.label] = str(score)
153 """ Returns number of connectivity restraints """
154 return len(self.rs.get_restraints())
157 return self.weight * self.rs.unprotected_evaluate(
None)
160 """A class to create an excluded volume restraint for a set of particles at a given resolution.
161 Can be initialized as a bipartite restraint between two sets of particles.
162 # Potential additional function: Variable resolution for each PMI object. Perhaps passing selection_tuples
163 with (PMI_object, resolution)
168 included_objects=
None,
173 @param representation DEPRECATED - just pass objects
174 @param included_objects Can be one of the following inputs:
175 IMP Hierarchy, PMI System/State/Molecule/TempResidue, or a list/set of them
176 @param other_objects Initializes a bipartite restraint between included_objects and other_objects
177 Same format as included_objects
178 @param resolution The resolution particles at which to impose the restraint.
179 By default, the coarsest particles will be chosen.
180 If a number is chosen, for each particle, the closest
181 resolution will be used (see IMP.atom.Selection).
182 @param kappa Restraint strength
196 if other_objects
is not None:
204 if representation
is None:
205 if hierarchies
is None:
206 raise Exception(
"Must at least pass included objects")
207 self.mdl = hierarchies[0].get_model()
208 included_ps = [h.get_particle()
for h
in hierarchies]
210 other_ps = [h.get_particle()
for h
in other_hierarchies]
212 type(representation)
is IMP.pmi.representation.SimplifiedModel:
213 self.mdl = representation.m
216 resolution=resolution,
217 hierarchies=hierarchies)
221 resolution=resolution,
222 hierarchies=other_hierarchies)
224 raise Exception(
"Must pass Representation or included_objects")
239 other_lsa.add_particles(other_ps)
247 self.rs.add_restraint(evr)
249 def add_excluded_particle_pairs(self, excluded_particle_pairs):
254 self.cpc.add_pair_filter(icpf)
256 def set_label(self, label):
259 def add_to_model(self):
262 def get_restraint(self):
265 def set_weight(self, weight):
267 self.rs.set_weight(weight)
269 def get_output(self):
272 score = self.weight * self.rs.unprotected_evaluate(
None)
273 output[
"_TotalScore"] = str(score)
274 output[
"ExcludedVolumeSphere_" + self.label] = str(score)
278 return self.weight * self.rs.unprotected_evaluate(
None)
282 """ Add bond restraint between pair of consecutive
283 residues/beads to enforce the stereochemistry.
292 @param representation
293 @param selection_tuple Requested selection
294 @param distance Resting distance for restraint
295 @param strength Bond constant
296 @param jitter Defines the +- added to the optimal distance in the harmonic well restraint
297 used to increase the tolerance
299 self.m = representation.prot.get_model()
305 particles = IMP.pmi.tools.select_by_tuple(
314 (distance - jitter, distance + jitter), strength)
319 raise ValueError(
"wrong length of pair")
322 raise TypeError(
"not a residue")
325 print(
"ResidueBondRestraint: adding a restraint between %s %s" % (pair[0].get_name(), pair[1].get_name()))
326 self.rs.add_restraint(
331 def set_label(self, label):
333 self.rs.set_name(label)
334 for r
in self.rs.get_restraints():
337 def add_to_model(self):
340 def get_restraint(self):
343 def set_weight(self, weight):
345 self.rs.set_weight(weight)
347 def get_excluded_pairs(self):
348 return self.pairslist
350 def get_output(self):
353 score = self.weight * self.rs.unprotected_evaluate(
None)
354 output[
"_TotalScore"] = str(score)
355 output[
"ResidueBondRestraint_" + self.label] = str(score)
360 """Add angular restraint between triplets of consecutive
361 residues/beads to enforce the stereochemistry.
369 self.m = representation.prot.get_model()
375 particles = IMP.pmi.tools.select_by_tuple(
381 (pi * anglemin / 180.0,
382 pi * anglemax / 180.0),
388 raise ValueError(
"wrong length of triplet")
391 raise TypeError(
"not a residue")
394 print(
"ResidueAngleRestraint: adding a restraint between %s %s %s" % (triplet[0].get_name(), triplet[1].get_name(), triplet[2].get_name()))
395 self.rs.add_restraint(
403 def set_label(self, label):
405 self.rs.set_name(label)
406 for r
in self.rs.get_restraints():
409 def add_to_model(self):
412 def get_restraint(self):
415 def set_weight(self, weight):
417 self.rs.set_weight(weight)
419 def get_excluded_pairs(self):
420 return self.pairslist
422 def get_output(self):
425 score = self.weight * self.rs.unprotected_evaluate(
None)
426 output[
"_TotalScore"] = str(score)
427 output[
"ResidueAngleRestraint_" + self.label] = str(score)
432 """Add dihedral restraints between quadruplet of consecutive
433 residues/beads to enforce the stereochemistry.
434 Give as input a string of "C" and "T", meaning cys (0+-40) or trans (180+-40)
435 dihedral. The length of the string must be \#residue-3.
436 Without the string, the dihedral will be assumed trans.
444 self.m = representation.prot.get_model()
450 particles = IMP.pmi.tools.select_by_tuple(
455 if stringsequence
is None:
456 stringsequence =
"T" * (len(particles) - 3)
461 raise ValueError(
"wrong length of quadruplet")
464 raise TypeError(
"not a residue")
467 dihedraltype = stringsequence[n]
468 if dihedraltype ==
"C":
472 (pi * anglemin / 180.0,
473 pi * anglemax / 180.0),
475 print(
"ResidueDihedralRestraint: adding a CYS restraint between %s %s %s %s" % (quadruplet[0].get_name(), quadruplet[1].get_name(),
476 quadruplet[2].get_name(), quadruplet[3].get_name()))
477 if dihedraltype ==
"T":
478 anglemin = 180 - 70.0
479 anglemax = 180 + 70.0
481 (pi * anglemin / 180.0,
482 pi * anglemax / 180.0),
484 print(
"ResidueDihedralRestraint: adding a TRANS restraint between %s %s %s %s" % (quadruplet[0].get_name(), quadruplet[1].get_name(),
485 quadruplet[2].get_name(), quadruplet[3].get_name()))
486 self.rs.add_restraint(
492 self.pairslist.append(
494 self.pairslist.append(
497 def set_label(self, label):
499 self.rs.set_name(label)
500 for r
in self.rs.get_restraints():
503 def add_to_model(self):
506 def get_restraint(self):
509 def set_weight(self, weight):
511 self.rs.set_weight(weight)
513 def get_excluded_pairs(self):
514 return self.pairslist
516 def get_output(self):
519 score = self.weight * self.rs.unprotected_evaluate(
None)
520 output[
"_TotalScore"] = str(score)
521 output[
"ResidueDihedralRestraint_" + self.label] = str(score)
525 """Experimental, requires isd_emxl for now"""
535 raise ValueError(
"IMP.isd_emxl is needed")
540 self.particles = IMP.pmi.tools.select_by_tuple(
544 self.m = representation.prot.get_model()
548 self.anglfilename = IMP.isd_emxl.get_data_path(
"CAAngleRestraint.dat")
549 self.dihefilename = IMP.isd_emxl.get_data_path(
550 "CADihedralRestraint.dat")
551 self.nativeness = nativeness
552 self.kt_caff = kt_caff
558 if len(self.particles) != len(ssstring):
559 print(len(self.particles), len(ssstring))
560 print(
"SecondaryStructure: residue range and SS string incompatible")
561 self.ssstring = ssstring
563 (bondrslist, anglrslist, diherslist,
564 pairslist) = self.get_CA_force_field()
565 self.pairslist = pairslist
568 self.anglrs.add_restraints(anglrslist)
569 self.dihers.add_restraints(diherslist)
570 self.bondrs.add_restraints(bondrslist)
572 def set_label(self, label):
575 def add_to_model(self):
580 def get_CA_force_field(self):
586 for res
in range(0, len(self.particles) - 1):
588 ps = self.particles[res:res + 2]
591 br = self.get_distance_restraint(ps[0], ps[1], 3.78, 416.0)
592 br.set_name(
'Bond_restraint')
593 bondrslist.append(br)
595 for res
in range(0, len(self.particles) - 4):
600 ps = self.particles[res:res + 5]
603 score_dih] = self.read_potential_dihedral(
604 self.ssstring[res:res + 4],
610 dr = IMP.isd_emxl.CADihedralRestraint(
619 dr.set_name(
'Dihedral restraint')
620 diherslist.append(dr)
622 for res
in range(0, len(self.particles) - 2):
623 ps = self.particles[res:res + 3]
624 [psi, score_ang] = self.read_potential_angle(
625 self.ssstring[res:res + 2],
True)
628 dr = IMP.isd_emxl.CAAngleRestraint(
634 dr.set_name(
'Angle restraint')
635 anglrslist.append(dr)
636 return (bondrslist, anglrslist, diherslist, pairslist)
638 def read_potential_dihedral(self, string, mix=False):
643 for i
in range(0, 36):
644 phi0.append(i * 10.0 / 180.0 * pi)
645 phi1.append(i * 10.0 / 180.0 * pi)
646 for j
in range(0, 36):
647 score_dih.append(0.0)
650 f = open(self.dihefilename,
'r')
651 for line
in f.readlines():
652 riga = (line.strip()).split()
653 if (len(riga) == 4
and riga[0] == string):
654 ii = int(float(riga[1]) / 10.0)
655 jj = int(float(riga[2]) / 10.0)
656 score_dih[ii * len(phi0) + jj] = - \
657 self.kt_caff * self.log(float(riga[3]))
662 for i
in range(0, 36):
663 for j
in range(0, 36):
665 f = open(self.dihefilename,
'r')
666 for line
in f.readlines():
667 riga = (line.strip()).split()
668 if (len(riga) == 4
and riga[0] == string):
669 ii = int(float(riga[1]) / 10.0)
670 jj = int(float(riga[2]) / 10.0)
671 counts[ii * len(phi0) + jj] += self.nativeness * \
673 if (len(riga) == 4
and riga[0] ==
"-----"):
674 ii = int(float(riga[1]) / 10.0)
675 jj = int(float(riga[2]) / 10.0)
676 counts[ii * len(phi0) + jj] += (1.0 - self.nativeness) * \
679 for i
in range(len(counts)):
680 score_dih[i] = -self.kt_caff * self.log(counts[i])
681 return [phi0, phi1, score_dih]
683 def read_potential_angle(self, string, mix=False):
687 for i
in range(0, 180):
688 psi.append(i / 180.0 * pi)
689 score_ang.append(0.0)
692 f = open(self.anglfilename,
'r')
693 for line
in f.readlines():
694 riga = (line.strip()).split()
695 if (len(riga) == 3
and riga[0] == string):
697 score_ang[ii] = -self.kt_caff * self.log(float(riga[2]))
702 for i
in range(0, 180):
705 f = open(self.anglfilename,
'r')
706 for line
in f.readlines():
707 riga = (line.strip()).split()
708 if (len(riga) == 3
and riga[0] == string):
710 counts[ii] += self.nativeness * float(riga[2])
711 if (len(riga) == 3
and riga[0] ==
"---"):
713 counts[ii] += (1.0 - self.nativeness) * float(riga[2])
715 for i
in range(0, 180):
716 score_ang[i] = -self.kt_caff * self.log(counts[i])
717 return [psi, score_ang]
719 def get_excluded_pairs(self):
720 return self.pairslist
722 def get_restraint(self):
724 tmprs.add_restraint(self.anglrs)
725 tmprs.add_restraint(self.dihers)
726 tmprs.add_restraint(self.bondrs)
729 def get_distance_restraint(self, p0, p1, d0, kappa):
735 def get_output(self):
738 score_angle = self.anglrs.unprotected_evaluate(
None)
739 score_dihers = self.dihers.unprotected_evaluate(
None)
740 score_bondrs = self.bondrs.unprotected_evaluate(
None)
741 output[
"_TotalScore"] = str(score_angle + score_dihers + score_bondrs)
743 output[
"SecondaryStructure_Angles_" + self.label] = str(score_angle)
744 output[
"SecondaryStructure_Dihedrals_" +
745 self.label] = str(score_dihers)
746 output[
"SecondaryStructure_Bonds_" + self.label] = str(score_bondrs)
751 """Add harmonic restraints between all pairs
753 def __init__(self,representation=None,
754 selection_tuples=
None,
761 @param representation Representation object
762 @param selection_tuples Selecting regions for the restraint
763 @param resolution Resolution for applying restraint
764 @param strength Bond strength
765 @param dist_cutoff Cutoff for making restraints
766 @param ca_only Selects only CAlphas. Only matters if resolution=0.
767 @param hierarchy Root hierarchy to select from, use this instead of representation
771 if representation
is None and hierarchy
is not None:
772 self.m = hierarchy.get_model()
773 for st
in selection_tuples:
779 particles+=sel.get_selected_particles()
781 self.m = representation.mdl
782 for st
in selection_tuples:
783 print(
'selecting with',st)
784 for p
in IMP.pmi.tools.select_by_tuple(representation,st,resolution=resolution):
788 particles.append(p.get_particle())
790 raise Exception(
"must pass representation or hierarchy")
798 for r
in self.rs.get_restraints():
799 a1,a2 = r.get_inputs()
802 print(
'created',self.rs.get_number_of_restraints(),
'restraints')
804 def set_label(self, label):
806 self.rs.set_name(label)
807 for r
in self.rs.get_restraints():
810 def add_to_model(self):
813 def get_restraint(self):
816 def set_weight(self, weight):
818 self.rs.set_weight(weight)
820 def get_excluded_pairs(self):
821 return self.pairslist
823 def get_output(self):
826 score = self.weight * self.rs.unprotected_evaluate(
None)
827 output[
"_TotalScore"] = str(score)
828 output[
"ElasticNetworkRestraint_" + self.label] = str(score)
833 """ Enable CHARMM force field """
839 enable_nonbonded=
True,
841 zone_nonbonded=
False,
842 representation=
None):
843 """Setup the CHARMM restraint on a selection. Expecting atoms.
844 @param root The node at which to apply the restraint
845 @param ff_temp The temperature of the force field
846 @param zone_ps Create a zone around this set of particles
847 Automatically includes the entire residue (incl. backbone)
848 @param zone_size The size for looking for neighbor residues
849 @param enable_nonbonded Allow the repulsive restraint
850 @param enable_bonded Allow the bonded restraint
851 @param zone_nonbonded EXPERIMENTAL: exclude from nonbonded all sidechains that aren't in zone!
852 @param representation Legacy representation object
855 kB = (1.381 * 6.02214) / 4184.0
856 if representation
is not None:
857 root = representation.prot
859 self.mdl = root.get_model()
861 self.nonbonded_rs =
IMP.RestraintSet(self.mdl, 1.0 / (kB * ff_temp),
'NONBONDED')
868 topology = ff.create_topology(root)
869 topology.apply_default_patches()
870 topology.setup_hierarchy(root)
871 if zone_ps
is not None:
872 limit_to_ps=IMP.pmi.topology.get_particles_within_zone(
876 entire_residues=
True,
877 exclude_backbone=
False)
881 self.ps = limit_to_ps
885 self.bonds_rs.add_restraint(r)
887 ff.add_well_depths(root)
889 atoms = IMP.atom.get_by_type(root,IMP.atom.ATOM_TYPE)
892 if (zone_ps
is not None)
and zone_nonbonded:
893 print(
'stereochemistry: zone_nonbonded is True')
895 backbone_types=[
'C',
'N',
'CB',
'O']
897 for n
in backbone_types])
898 backbone_atoms = sel.get_selected_particles()
900 sel_ps=IMP.pmi.topology.get_particles_within_zone(
904 entire_residues=
True,
905 exclude_backbone=
True)
915 self.nbl.add_pair_filter(r.get_full_pair_filter())
918 self.nonbonded_rs.add_restraint(pr)
919 print(
'CHARMM is set up')
921 def set_label(self, label):
923 self.rs.set_name(label)
924 for r
in self.rs.get_restraints():
927 def add_to_model(self):
931 def get_restraint(self):
934 def get_close_pair_container(self):
937 def set_weight(self, weight):
939 self.rs.set_weight(weight)
941 def get_output(self):
944 bonds_score = self.weight * self.bonds_rs.unprotected_evaluate(
None)
945 nonbonded_score = self.weight * self.nonbonded_rs.unprotected_evaluate(
None)
946 score=bonds_score+nonbonded_score
947 output[
"_TotalScore"] = str(score)
948 output[
"CHARMM_BONDS"] = str(bonds_score)
949 output[
"CHARMM_NONBONDED"] = str(nonbonded_score)
954 """Add bonds and improper dihedral restraints for the CBs
957 self, rnums, representation, selection_tuple, strength=10.0, kappa=1.0,
958 jitter_angle=0.0, jitter_improper=0.0):
962 ca-cb is a constraint, no restraint needed
967 self.m = representation.prot.get_model()
977 ca, cb = self.get_ca_cb(
978 IMP.pmi.tools.select_by_tuple(representation,
979 (rnum, rnum,
'chainA'), resolution=0))
983 ca_prev, cb_prev = self.get_ca_cb(
984 IMP.pmi.tools.select_by_tuple(representation,
985 (rnum - 1, rnum - 1,
'chainA'), resolution=0))
986 ca_next, cb_next = self.get_ca_cb(
987 IMP.pmi.tools.select_by_tuple(representation,
988 (rnum + 1, rnum + 1,
'chainA'), resolution=0))
1022 self.rset_angles.add_restraint(ar13u)
1023 self.rset_angles.add_restraint(ar13l)
1029 self.rset_angles.add_restraint(ar23u)
1030 self.rset_angles.add_restraint(ar23l)
1031 if not nter
and not cter:
1055 self.rset_angles.add_restraint(idru)
1056 self.rset_angles.add_restraint(idrl)
1057 self.rs.add_restraint(self.rset_bonds)
1058 self.rs.add_restraint(self.rset_angles)
1060 def get_ca_cb(self, atoms):
1065 ca = a.get_particle()
1067 cb = a.get_particle()
1070 def set_label(self, label):
1072 self.rs.set_name(label)
1073 for r
in self.rs.get_restraints():
1076 def add_to_model(self):
1079 def get_restraint(self):
1082 def set_weight(self, weight):
1083 self.weight = weight
1084 self.rs.set_weight(weight)
1086 def get_excluded_pairs(self):
1087 return self.pairslist
1089 def get_output(self):
1092 score = self.weight * self.rs.unprotected_evaluate(
None)
1093 output[
"_TotalScore"] = str(score)
1094 output[
"PseudoAtomicRestraint_" + self.label] = str(score)
1098 """Create harmonic restraints between the reference and (transformed) clones.
1099 \note Wraps IMP::core::TransformedDistancePairScore with an IMP::core::Harmonic
1108 @param references List of particles for symmetry reference
1109 @param clones_list List of lists of clone particles
1110 @param transforms Transforms moving each selection to the first selection
1111 @param label Label for output
1112 @param strength The elastic bond strength
1113 \note You will have to perform an IMP::atom::Selection to get the particles you need.
1114 Will check to make sure the numbers match.
1116 self.mdl = root.get_model()
1120 if len(clones_list)!=len(transforms):
1121 raise Exception(
'Error: There should be as many clones as transforms')
1124 for clones,trans
in zip(clones_list,transforms):
1125 if len(clones)!=len(references):
1126 raise Exception(
"Error: len(references)!=len(clones)")
1128 for p0,p1
in zip(references,clones):
1130 self.rs.add_restraint(r)
1132 print(
'created symmetry network with',self.rs.get_number_of_restraints(),
'restraints')
1134 def set_label(self, label):
1136 self.rs.set_name(label)
1137 for r
in self.rs.get_restraints():
1140 def add_to_model(self):
1143 def get_restraint(self):
1146 def set_weight(self, weight):
1147 self.weight = weight
1148 self.rs.set_weight(weight)
1150 def get_excluded_pairs(self):
1151 return self.pairslist
1153 def get_output(self):
1156 score = self.weight * self.rs.unprotected_evaluate(
None)
1157 output[
"SymmetryRestraint_" + self.label] = str(score)
1158 output[
"_TotalScore"] = str(score)
A filter which returns true if a container containers the Pair.
Add dihedral restraints between quadruplet of consecutive residues/beads to enforce the stereochemist...
CHARMMParameters * get_heavy_atom_CHARMM_parameters()
Lower bound harmonic function (non-zero when feature < mean)
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Enforce CHARMM stereochemistry on the given Hierarchy.
A member of a rigid body, it has internal (local) coordinates.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Various classes to hold sets of particles.
Upper bound harmonic function (non-zero when feature > mean)
Enable CHARMM force field.
A class to store an fixed array of same-typed values.
Add harmonic restraints between all pairs.
Dihedral restraint between four particles.
A score on the distance between the surfaces of two spheres.
Return all close unordered pairs of particles taken from the SingletonContainer.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Return all close ordered pairs of particles taken from the two SingletonContainers.
GenericHierarchies get_leaves(Hierarchy mhd)
Get all the leaves of the bit of hierarchy.
Distance restraint between two particles.
Representation of the system.
Object used to hold a set of restraints.
Store a list of ParticleIndexPairs.
A well with harmonic barriers.
Angle restraint between three particles.
ParticleIndexPairs get_indexes(const ParticlePairsTemp &ps)
Add bond restraint between pair of consecutive residues/beads to enforce the stereochemistry.
The standard decorator for manipulating molecular structures.
RestraintSet * create_elastic_network(const Particles &ps, Float dist_cutoff, Float strength)
Create an elastic network restraint set.
Add bonds and improper dihedral restraints for the CBs.
Store a list of ParticleIndexes.
A decorator for a particle representing an atom.
def __init__
Setup the CHARMM restraint on a selection.
Create harmonic restraints between the reference and (transformed) clones.
Add angular restraint between triplets of consecutive residues/beads to enforce the stereochemistry...
def get_num_restraints
Returns number of connectivity restraints.
Basic functionality that is expected to be used by a wide variety of IMP users.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
This class creates a restraint between consecutive TempResidue objects OR an entire PMI MOlecule obje...
A class to create an excluded volume restraint for a set of particles at a given resolution.
The general base class for IMP exceptions.
def __init__
need to add: ca-ca bond ca-cb is a constraint, no restraint needed ca-ca-ca cb-ca-ca-cb ...
Applies a PairScore to a Pair.
Experimental, requires isd_emxl for now.
Set up the representation of all proteins and nucleic acid macromolecules.
Functionality for loading, creating, manipulating and scoring atomic structures.
Select hierarchy particles identified by the biological name.
Applies a PairScore to each Pair in a list.
A repulsive potential on the distance between two atoms.
Perform more efficient close pair finding when rigid bodies are involved.
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...
Harmonic function (symmetric about the mean)