Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
BackboneStubConstraint.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/scoring/constraints/BackboneStubConstraint.cc
11 ///
12 /// @brief
13 /// @author John Karanicolas, Sarel Fleishman
14 
15 
17 
18 // AUTO-REMOVED #include <basic/options/option.hh>
19 // AUTO-REMOVED #include <basic/options/keys/OptionKeys.hh>
20 // AUTO-REMOVED #include <core/conformation/Conformation.hh>
22 // AUTO-REMOVED #include <core/scoring/constraints/ConstraintSet.hh>
24 #include <basic/Tracer.hh>
25 
26 // used to make temporary alanines for gly cst's
32 
33 //Auto Headers
35 #include <core/pose/Pose.hh>
38 #include <utility/vector1.hh>
39 
40 //Auto Headers
41 #include <core/kinematics/Jump.hh>
42 
43 namespace core {
44 namespace scoring {
45 namespace constraints {
46 
47 
48 static basic::Tracer TR("core.scoring.constraints.BackboneStubConstraint");
49 
51 
53  pose::Pose const & pose,
54  Size const seqpos,
55  AtomID const & fixed_atom_id,
56  conformation::Residue const & target_rsd,
57  core::Real const & superposition_bonus,
58  core::Real const & CB_force_constant
59 ):
60  Constraint( core::scoring::backbone_stub_constraint ),
61  superposition_bonus_( superposition_bonus ),
62  CB_force_constant_( CB_force_constant ),
63  seqpos_( seqpos ),
64  fixed_atom_id_( fixed_atom_id )
65 {
66 
67  // store info about the target residue
68  assert( target_rsd.is_protein() );
69  if ( (target_rsd.aa() == chemical::aa_gly ) ) {
70  TR << "ERROR - Gly residues cannot be used in BackboneStubConstraints." << std::endl;
71  return;
72  }
73  CB_target_ = target_rsd.xyz("CB");
74  CA_target_ = target_rsd.xyz("CA");
75  C_target_ = target_rsd.xyz("C");
76  N_target_ = target_rsd.xyz("N");
79 
80  // constraint depends on CB, CA, C coordinates
81  conformation::Residue const & rsd( pose.residue(seqpos_) );
82  assert( rsd.is_protein() );
83  if ( (rsd.aa() == chemical::aa_gly) ) {
84  TR << "ERROR - Gly residues cannot be used in BackboneStubConstraints." << std::endl;
85  return;
86  }
87  CB_atom_id_ = AtomID( rsd.atom_index("CB"), seqpos_ );
88  atom_ids_.push_back(CB_atom_id_);
89  CA_atom_id_ = AtomID( rsd.atom_index("CA"), seqpos_ );
90  atom_ids_.push_back(CA_atom_id_);
91  C_atom_id_ = AtomID( rsd.atom_index("C"), seqpos_ );
92  atom_ids_.push_back(C_atom_id_);
93  N_atom_id_ = AtomID( rsd.atom_index("N"), seqpos_ );
94  atom_ids_.push_back( N_atom_id_ );
95 
96  // need a fixed reference point on the pose
97  atom_ids_.push_back(fixed_atom_id_);
98  // we don't actually need to save the coors of the reference point,
99  // but will do so to ensure that it doesn't move
101 
102  // to get access to AngleConstraint derivatives
103  if ( ang_cst_ == 0 ) {
104  // note: PeriodicFunc has functional form y = ( k * cos(n * (x - x0) ) ) + C
105  FuncOP cos_func = new PeriodicFunc(0., 1., 1., 0.);
106  ang_cst_ = new AngleConstraint( cos_func );
107  }
108 }
109 
112 { return seqpos_; }
113 
114 void BackboneStubConstraint::show( std::ostream& out ) const
115 {
116  out << "BackboneStubCst Seqpos: " << seqpos_ << " bonus: " << superposition_bonus_ << " CB force constant: " << CB_force_constant_ << std::endl;
117 }
118 
119 
120 bool
122 {
123 
124  if( !dynamic_cast< BackboneStubConstraint const * > ( &other_cst ) ) return false;
125 
126  BackboneStubConstraint const & other( static_cast< BackboneStubConstraint const & > (other_cst) );
127 
128  if( superposition_bonus_ != other.superposition_bonus_ ) return false;
129  if( CB_force_constant_ != other.CB_force_constant_ ) return false;
130  if( seqpos_ != other.seqpos_ ) return false;
131 
132  if( CB_atom_id_ != other.CB_atom_id_ ) return false;
133  if( CA_atom_id_ != other.CA_atom_id_ ) return false;
134  if( C_atom_id_ != other.C_atom_id_ ) return false;
135  if( N_atom_id_ != other.N_atom_id_ ) return false;
136 
137  if( CB_target_ != other.CB_target_ ) return false;
138  if( CA_target_ != other.CA_target_ ) return false;
139  if( C_target_ != other.C_target_ ) return false;
140  if( N_target_ != other.N_target_ ) return false;
141  if( CB_CA_target_ != other.CB_CA_target_ ) return false;
142  if( C_N_target_ != other.C_N_target_ ) return false;
143 
144  if( fixed_atom_id_ != other.fixed_atom_id_ ) return false;
145  if( fixed_reference_point_ != other.fixed_reference_point_ ) return false;
146 
147  return true;
148 }
149 
150 
151 
152 // Calculates a score for this constraint using XYZ_Func, and puts the UNWEIGHTED score into
153 // emap. Although the current set of weights currently is provided, Constraint objects
154 // should put unweighted scores into emap.
155 // the constraint score, C, is given by C = (b + kx^2) * z, where b is the score bonus for the stub, k is the user-defined CB force constant
156 // z is the dot product between the Ca-Cb vectors of the stub and the current
157 // position on the scaffold times the C-N vectors of the stub and scaffold position.
158 // The intuition in this is that a stub that lands
159 // perfectly on the scaffold's bacbkone position AND for which the two vectors
160 // match the scaffold's perfectly would give maximal bonus. This choice of vectors is
161 // orthogonal and so provides unbiased resolution for conformation space.
162 // Note that we don't know in advance which phi/psi angles a scaffold position would have, and
163 // that may change the C_N vector by up to 25o from the stub's. Since the cosine of small angular
164 // differences is close to 1, this uncertainty would not cause large problems.
165 // Since the constraint does not produce positive values, the effect of a stub
166 // on the energy is only if the distance between the Cb's of stub and scaffold is
167 // sqrt( -b / k ). As a rule of thumb, b=-4, so k can be decided in a way that will
168 // determine the radius of the effect of a stub on pulling a scaffold towards it: k = 4/dist^2, where dist is the preferred radius
169 void
170 BackboneStubConstraint::score( XYZ_Func const & xyz_func, EnergyMap const & weights, EnergyMap & emap ) const {
171 
172  if ( weights[ this->score_type() ] == 0 ) return;
173 
174  core::conformation::Residue const & curr_rsd = xyz_func.residue(seqpos_);
175  assert( curr_rsd.is_protein() );
176 
177  // verify that the fixed reference point is in the same place
178  core::Vector curr_ref_location = xyz_func(fixed_atom_id_);
179  core::Real ref_dist = curr_ref_location.distance_squared( fixed_reference_point_ );
180  if ( ref_dist > 1E-8 ) {
181  TR << "ERROR - BackboneStubConstraint requires a fixed reference atom, but this atom has moved!!" << std::endl;
182  TR << "Reference location was " << fixed_reference_point_.x() << ", " << fixed_reference_point_.y() << ", " << fixed_reference_point_.z() << ", now it's " << curr_ref_location.x() << ", " << curr_ref_location.y() << ", " << curr_ref_location.z() << std::endl;
183  std::exit(1);
184  }
185 
186  // return a value between superposition_bonus_ (-ve) and zero
188  assert( cst_val < 0. );
189 
190  // apply a harmonic constraint on the CB's
191  core::Vector CB_curr;
192  if ( (curr_rsd.aa() == chemical::aa_gly) ) {
193 /// SJF I'm disabling the option for glycine backbone stub constraints b/c it hardly seems useful and is something of a pain
194 /// to deal with since changing curr_rsd to a Residue const &
195 /* if( basic::options::option[basic::options::OptionKeys::hotspot::allow_gly]() ) {
196  // make an alanine
197  core::chemical::ResidueTypeSetCAP residue_set = core::chemical::ChemicalManager::get_instance()->residue_type_set( "fa_standard" );
198  core::chemical::ResidueType const & alatype( residue_set->name_map( "ALA" ) );
199  core::conformation::ResidueOP ala_copy = core::conformation::ResidueFactory::create_residue( alatype );
200  // move ala on top of gly
201  ala_copy->orient_onto_residue( curr_rsd );
202  curr_rsd = *(ala_copy); // gly => ala
203  }
204  else { */
205  TR << "ERROR - Gly residues cannot be used in BackboneStubConstraints." << std::endl;
206  return;
207 // }
208  }
209  CB_curr = curr_rsd.xyz("CB");
210 
211  core::Real CB_d2 = CB_curr.distance_squared( CB_target_ );
212  cst_val += CB_force_constant_ * CB_d2;
213  if ( cst_val > 0. ) return;
214 
215 ///// SJF the following are the dot product results (or cosines) of the various
216 ///// vectors in an amino-acid:
217 ///// ca-cb x ca_c = 0.34
218 ///// ca-cb x cb_c = 0.82
219 ///// ca-cb x n-c = 0.02
220 ///// So, by far the most orthogonal choice is to use ca-b and n-c
221 
222  // multiply by the cos of the angle between the CB-CA and CB'-CA' vectors
223  core::Vector const CA_curr = curr_rsd.xyz("CA");
224 // core::Vector const CB_CA_curr = CB_curr - CA_curr;
225  cst_val *= ang_cst_->score( CB_curr, CA_curr, CA_curr + CB_CA_target_);
226  if ( cst_val > -1E-10 ) return;
227 
228  // multiply by the cos of the angle between the C-N and C'-N' vectors
229  core::Vector const C_curr = curr_rsd.xyz("C");
230  core::Vector const N_curr = curr_rsd.xyz("N");
231 // core::Vector const C_N_curr = C_curr - N_curr;
232 
233  cst_val *= ang_cst_->score( C_curr, N_curr, N_curr + C_N_target_ );
234  if ( cst_val > -1E-10 ) return;
235 
236  emap[ this->score_type() ] += cst_val;
237 }
238 
239 void
241  AtomID const & atom,
242  XYZ_Func const & xyz,
243  Vector & F1,
244  Vector & F2,
245  EnergyMap const & weights
246 ) const
247 {
248  if ( weights[ this->score_type() ] == 0 ) return;
249 
250  core::conformation::Residue const & curr_rsd = xyz.residue( seqpos_ );
251 
252  assert( curr_rsd.is_protein() );
253 
254  if ( ( atom != CB_atom_id_ ) && ( atom != CA_atom_id_ ) && ( atom != C_atom_id_ ) && ( atom != N_atom_id_ ) ) {
255  return;
256  }
257 
258  // return a value between superposition_bonus_ (-ve) and zero
260  assert( cst_val < 0. );
261 
262  // start by computing the cst value normally, collecting score components along the way. if cst_val is non-negative no derivative is computed
263 
264  if ( (curr_rsd.aa() == chemical::aa_gly) ) {
265 /* if( basic::options::option[basic::options::OptionKeys::hotspot::allow_gly] ) {
266  // make an alanine
267  core::chemical::ResidueTypeSetCAP residue_set = core::chemical::ChemicalManager::get_instance()->residue_type_set( "fa_standard" );
268  core::chemical::ResidueType const & alatype( residue_set->name_map( "ALA" ) );
269  core::conformation::ResidueOP ala_copy = core::conformation::ResidueFactory::create_residue( alatype );
270  // move ala on top of gly
271  ala_copy->orient_onto_residue( *curr_rsd );
272  curr_rsd = *ala_copy; // gly => ala
273  }
274  else { */
275  TR << "ERROR - Gly residues cannot be used in BackboneStubConstraints." << std::endl;
276  return;
277 // }
278  }
279 
280  // apply a harmonic constraint on the CB's
281  core::Vector const CB_curr( curr_rsd.xyz("CB") );
282 
283  core::Real const CB_d2 = CB_curr.distance_squared( CB_target_ );
284  core::Real const CB_pos_term = CB_force_constant_ * CB_d2;
285  cst_val += CB_pos_term;
286  if ( cst_val > -1E-10 ) return;
287 
288  // multiply by the cos of the angle between the CB-CA and CB'-CA' vectors
289  core::Vector const CA_curr = curr_rsd.xyz("CA");
290  core::Vector const CB_CA_curr = CB_curr - CA_curr;
291  core::Real const CB_CA_angle_term( ang_cst_->score( CB_curr, CA_curr, CA_curr + CB_CA_target_ ) );
292  if( CB_CA_angle_term <= 1E-10 ) return;
293 
294  // multiply by the cos of the angle between the C-N and C'-N' vectors
295  core::Vector const C_curr = curr_rsd.xyz("C");
296  core::Vector const N_curr = curr_rsd.xyz("N");
297  core::Vector const C_N_curr = C_curr - N_curr;
298  core::Real const C_N_angle_term( ang_cst_->score( C_curr, N_curr, N_curr + C_N_target_ ) );
299  if ( C_N_angle_term <= 1E-10 ) return;
300 
301  core::Real const constant_dist_term( weights[ this->score_type() ] );
302  core::Real const constant_ang_term( constant_dist_term * ( superposition_bonus_ + CB_pos_term ) );
303 
304  // contribution from differentiating CB_dist ( * CA_angle_term * C_angle_term from product rule)
305  // and then adding the effect of the angular constraint on cb using the chain rule
306  if ( atom == CB_atom_id_ ) {
307 // the effects of the coordinate constraint
308  Vector const CB_f2( CB_curr - CB_target_ );
309  core::Real const CB_dist( CB_f2.length() );
310  core::Real const CB_deriv = 2. * CB_force_constant_ * CB_dist;
311  if ( CB_deriv != 0.0 && CB_dist != 0.0 ) {
312  Vector const CB_f1( CB_curr.cross( CB_target_ ) );
313  F1 += ( ( CB_deriv / CB_dist ) * CB_f1 ) * CB_CA_angle_term * C_N_angle_term * constant_dist_term;
314  F2 += ( ( CB_deriv / CB_dist ) * CB_f2 ) * CB_CA_angle_term * C_N_angle_term * constant_dist_term;
315  }
316 
317 // the angular constraint on cb
318  Vector partial_F1(0.), partial_F2(0.);
319  ang_cst_->p1_deriv( CB_curr/*p1*/, CA_curr/*p2*/, CA_curr + CB_CA_target_/*p3*/, partial_F1, partial_F2 );
320  F1 += partial_F1 * C_N_angle_term * constant_ang_term;
321  F2 += partial_F2 * C_N_angle_term * constant_ang_term;
322  return;
323  }
324 
325 // the angular constraint on ca
326 // See N atom for explanation on the derivs
327  if ( atom == CA_atom_id_ ) {
328  Vector partial_F1(0.), partial_F2(0.);
329  ang_cst_->p1_deriv( CA_curr, CA_curr - CB_CA_curr, CA_curr + CB_CA_target_ - CB_CA_curr, partial_F1, partial_F2 );
330  F1 += -partial_F1 * C_N_angle_term * constant_ang_term;
331  F2 += -partial_F2 * C_N_angle_term * constant_ang_term;
332  return;
333  }
334 
335 // the angular constraint on c
336  if ( atom == C_atom_id_ ) {
337  Vector partial_F1(0.), partial_F2(0.);
338  ang_cst_->p1_deriv( C_curr/*p1*/, N_curr/*p2*/, N_curr + C_N_target_/*p3*/, partial_F1, partial_F2 );
339  F1 += partial_F1 * CB_CA_angle_term * constant_ang_term;
340  F2 += partial_F2 * CB_CA_angle_term * constant_ang_term;
341  return;
342  }
343 
344 // the angular constraint on n
345 // This is tricky, and thanks to Frank for coming up with this!
346 // Ang_cst uses the actual coordinates of p1 in computing the derivatives, requiring it to be constant.
347 // But in our case, p1 changes with respect to p2->p3. Solution: translate the vectors by -C_N_curr.
348 // Now, p1 is at the site of the nonchanging vector, and so the coordinates are safe for ang_cst.
349 // However, the derivative for the angular constraint is reversed, so we multiply by -1
350  if( atom == N_atom_id_ ) {
351  Vector partial_F1(0.), partial_F2(0.);
352  ang_cst_->p1_deriv( N_curr, N_curr - C_N_curr, N_curr + C_N_target_ - C_N_curr, partial_F1, partial_F2 );
353  F1 += -partial_F1 * CB_CA_angle_term * constant_ang_term;
354  F2 += -partial_F2 * CB_CA_angle_term * constant_ang_term;
355  }
356  return;
357 }
358 
360 {
361  return ConstraintOP( new BackboneStubConstraint( *this ) );
362 }
363 
364 /// @brief Copies the data from this Constraint into a new object and returns an OP
365 /// atoms are mapped to atoms with the same name in dest pose ( e.g. for switch from centroid to fullatom )
366 /// if a sequence_mapping is present it is used to map residue numbers .. NULL = identity mapping
367 /// to the new object. Intended to be implemented by derived classes.
369 
370  core::Size new_seqpos = seqpos_;
371  AtomID new_fixed_atom_id = fixed_atom_id_;
372 
373  if ( smap ) {
374  new_seqpos = (*smap)[ seqpos_ ];
375  new_fixed_atom_id.rsd() = (*smap)[ fixed_atom_id_.rsd() ];
376  if( new_seqpos == 0 ) return NULL;
377  }
378 
379  // make an alanine
381  core::chemical::ResidueType const & alatype( residue_set->name_map( "ALA" ) );
383  ala->set_xyz("CB",CB_target_);
384  ala->set_xyz("CA",CA_target_);
385  ala->set_xyz("C",C_target_);
386  ala->set_xyz("N",N_target_);
387 
388  return new BackboneStubConstraint(dest, new_seqpos, new_fixed_atom_id, *ala, superposition_bonus_, CB_force_constant_ );
389 }
390 
391 
392 /*ConstraintOP
393 BackboneStubConstraint::remap_resid(
394  core::id::SequenceMapping const & seqmap
395 ) const {
396  for(
397  if ( seqmap[atom1_.rsd()] != 0 && seqmap[atom2_.rsd()] != 0 && seqmap[atom3_.rsd()] != 0 && seqmap[atom4_.rsd()] != 0 ) {
398  AtomID remap_a1( atom1_.atomno(), seqmap[atom1_.rsd()] ),
399  remap_a2( atom2_.atomno(), seqmap[atom2_.rsd()] ),
400  remap_a3( atom3_.atomno(), seqmap[atom3_.rsd()] ),
401  remap_a4( atom4_.atomno(), seqmap[atom4_.rsd()] );
402  return ConstraintOP( new DihedralConstraint( remap_a1, remap_a2, remap_a3, remap_a4, this->func_ ) );
403  } else {
404  return NULL;
405  }
406 }
407 */
408 
409 
410 } // namespace constraints
411 } // namespace scoring
412 } // namespace core