Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ContactMap.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 ContactMap.cc
11 ///
12 /// @brief Method code and full headers for ContactMapCreator, ContactMap, ContactPartner
13 /// and contact
14 ///
15 /// @author Joerg Schaarschmidt
16 
17 // unit headers
20 
21 // type headers
22 #include <core/types.hh>
23 
24 // project headers
25 #include <core/pose/Pose.hh>
26 #include <core/pose/util.hh>
29 
30 // utility headers
31 #include <utility/tag/Tag.hh>
32 #include <utility/vector1.hh>
33 #include <utility/io/ozstream.hh>
34 
35 #include <basic/Tracer.hh>
36 
37 #include <numeric/xyzVector.hh>
38 
39 // ObjexxFCL headers
40 
41 // C++ headers
42 
43 #include <protocols/jd2/Job.hh>
44 #include <utility/vector0.hh>
45 
46 //Auto Headers
47 #include <utility/excn/Exceptions.hh>
49 
50 namespace protocols {
51 namespace contact_map {
52 
53 using namespace utility::tag;
54 using namespace core;
55 
56 using basic::T;
57 using basic::Error;
58 using basic::Warning;
59 static basic::Tracer TR("protocols.moves.ContactMap");
60 
61 
62 
63 /////////////////////////////// ContactMapCreator ///////////////////////////////
64 
67 }
68 
70  return new ContactMap;
71 }
72 
74  return "ContactMap";
75 }
76 
77 
78 /////////////////////////////// ContactMap ///////////////////////////////
79 
80 /// @brief Default constructor
82  Mover(ContactMapCreator::mover_name()),
83  output_prefix_("contact_map_"),
84  n_poses_(0),
85  distance_cutoff_(10.0),
86  models_per_file_(1),
87  reset_count_(true),
88  row_format_(false)
89 {
90 }
91 
92 /// @brief Copy constructor
93 ContactMap::ContactMap(ContactMap const & contact_map) :
94  Mover(contact_map),
95  contacts_(contact_map.contacts_),
96  output_matrix_(contact_map.output_matrix_),
97  column_names_(contact_map.column_names_),
98  row_names_(contact_map.row_names_),
99  output_prefix_(contact_map.output_prefix_),
100  n_poses_(contact_map.n_poses_),
101  distance_cutoff_(contact_map.distance_cutoff_),
102  models_per_file_(contact_map.models_per_file_),
103  reset_count_(contact_map.reset_count_),
104  row_format_(contact_map.row_format_)
105 {
106 }
107 
108 /// @brief Destructor
110 }
111 
112 
114  return new ContactMap(*this);
115 }
116 
118  return new ContactMap;
119 }
120 
123 }
124 
125 /// @brief Processes options specified in xml-file and sets up the ContactMap
128  Pose const & pose) {
129 
130  // 'distance_cutoff' option
131  set_distance_cutoff(tag->getOption<core::Real>("distance_cutoff", distance_cutoff_));
132 
133  // 'output_prefix_' option
134  set_output_prefix(tag->getOption<std::string>("prefix", output_prefix_));
135 
136  // 'reset_count' flag
137  std::string reset_count_tag = tag->getOption<std::string>("reset_count", "true");
138  if(reset_count_tag == "false") {
139  reset_count_ = false;
140  }
141  else {
142  if (reset_count_tag != "true") throw utility::excn::EXCN_RosettaScriptsOption("'reset_count' option must be true or false");
143  reset_count_ =true;
144  }
145 
146  // 'models_per_file' option
147  models_per_file_ = tag->getOption<core::Size>("models_per_file", models_per_file_);
148 
149  // 'row_format_' flag
150  std::string row_format_tag = tag->getOption<std::string>("row_format", "false");
151  if(row_format_tag == "true") row_format_ = true ;
152  else {
153  if (row_format_tag != "false") throw utility::excn::EXCN_RosettaScriptsOption("'row_format' option must be true or false");
154  row_format_ =false;
155  }
156 
157  // 'region1', 'region2' and 'ligand' options
158  // Initialize 'region1' with complete pose in case no option is specified
159  core::Size region1_begin = 1;
160  core::Size region1_end = pose.n_residue();
161  // Parse 'region1' option if supplied
162  if (tag->hasOption("region1")){
163  parse_region_string(tag->getOption<std::string> ("region1"),
164  region1_begin, region1_end, pose);
165  }
166  // Parse 'region2' option if supplied and initialize ContactMap between 'region1' and 'region2'
167  if (tag->hasOption("region2")){
168  core::Size region2_begin, region2_end;
169  parse_region_string(tag->getOption<std::string> ("region2"),
170  region2_begin, region2_end, pose);
171  fill_contacts(region1_begin, region1_end, region2_begin, region2_end, pose);
172  }
173  // Parse 'ligand' option if supplied and initialize ContactMap between 'region1' and 'ligand'
174  else if (tag->hasOption("ligand")){
175  core::Size ligand_begin, ligand_end;
176  parse_region_string(tag->getOption<std::string> ("ligand"),
177  ligand_begin, ligand_end, pose);
178  fill_contacts(region1_begin, region1_end, ligand_begin, pose);
179  }else{
180  // Initialize ContactMap with 'region1' if neither 'region2' nor 'ligand' were specified
181  fill_contacts(region1_begin, region1_end, pose);
182  }
183 }
184 
185 /// @brief Parses region definition string end sets the boundaries accordingly
187  core::Size & region_begin,
188  core::Size & region_end,
189  Pose const & pose) {
190 
191  // Check if region is defined by chain
192  if (region_def.size() == 1 && isalpha(region_def.at(0)) ){
193  // Retrieve chain ID
194  core::Size const chain_id =
195  core::pose::get_chain_id_from_chain(region_def, pose);
196  // Set region according to chain boundaries
197  region_begin = pose.conformation().chain_begin(chain_id);
198  region_end = pose.conformation().chain_end(chain_id);
199  //TR << "Region defined from " << *region_begin << " to " << *region_end <<"." << std::endl;
200  return;
201  }
202 
203  // Initialize stream and try to read in region_begin
204  std::istringstream region_defstr(region_def);
205  region_defstr >> region_begin;
206  // Set region_end to region_begin if only one position is supplied
207  if (region_defstr.eof()){
208  region_end = region_begin;
209  }else{
210  // Skip separator and read region end
211  region_defstr.seekg(1, std::ios_base::cur);
212  region_defstr >> region_end;
213  }
214  // Exit if something went wrong
215  if(region_defstr.fail() || ! region_defstr.eof() )
216  utility_exit_with_message("Unable to parse region '" + region_def +"'!");
217 
218  // Make sure region_begin is not greater than region end
219  if(region_begin > region_end){
220  core::Size temp = region_begin;
221  region_begin = region_end;
222  region_end = temp;
223  }
224 
225  // Check if region definition is within bounds of the pose
226  if (region_begin < 1 || region_end > pose.n_residue()) {
227  utility_exit_with_message("Specified region '" + region_def +"' is out of bounds!");
228  }
229  //TR << "Region defined from " << *region_begin << " to " << *region_end <<"." << std::endl;
230 
231 }
232 
233 /// @brief Initializes ContactMap within a single region
235  core::Size begin,
236  core::Size end,
237  Pose const & pose)
238 {
239  ContactPartner p1, p2;
240  // Outer loop to assign ContactPartner1
241  for (core::Size i = begin; i<=end; i++){
242  std::string atom_name1 = pose.residue_type(i).name1() == 'G' ? "CA" : "CB";
243  std::string resname1 = pose.residue(i).name3();
244  p1 = ContactPartner(i, resname1, atom_name1);
245  // Fill column and row names
246  row_names_.push_back(p1.string_rep());
247  column_names_.push_back(p1.string_rep());
248  // Outer loop to assign ContactPartner1 and create contact
249  for (core::Size j = i+1; j<=end; j++){
250  std::string atom_name2 = pose.residue_type(j).name1() == 'G' ? "CA" : "CB";
251  std::string resname2 = pose.residue(j).name3();
252  p2 = ContactPartner(j, resname2, atom_name2);
253  // Create contact and add to contacts_
254  Contact contact = Contact(p1,p2);
255  contacts_.push_back(contact);
256  }
257  }
258  // Add additional contact with same ContactPartner to fill identity contacts in Matrix
259  contacts_.push_back(Contact(p1, p1));
260 
261  // Set offset and length of region for calculation of array position
262  core::Size offset = begin- 1;
263  core::Size length = end - offset;
264 
265  // Fill output_matrix with positions of corresponding contact in contacts_ vector
266  for (core::Size i = 1; i<=length; i++){
267  for (core::Size j = 1; j<=length; j++){
268  if (i==j){
269  // Set matrix value to position of identity contact
270  output_matrix_.push_back(contacts_.size());
271  }else{
272  // Set matrix value to corresponding position in contacts_ vector
273  output_matrix_.push_back(i<j ?
274  (2 * length - i) * (i - 1) / 2 - i + j :
275  (2 * length - j) * (j - 1) / 2 - j + i);
276  }
277  }
278  }
279 }
280 
281 /// @brief Initializes ContactMap between a single region and a ligand
283  core::Size begin,
284  core::Size end,
285  core::Size ligand_seqpos,
286  Pose const & pose)
287 {
288  core::Size matrix_position = 1;
289  std::string ligand_resname = pose.residue(ligand_seqpos).name3();
290  // Make sure ligand_seqpos doesn't equal begin
291  if(ligand_seqpos == begin) ++begin;
292  // Loop over residues in specified region
293  for (core::Size i = begin; i <= end; i++) {
294  // Exclude ligand from residues
295  if(i==ligand_seqpos) continue;
296  std::string atom_name1 = pose.residue_type(i).name1() == 'G' ? "CA" : "CB";
297  std::string resname1 = pose.residue(i).name3();
298  ContactPartner p1(i, resname1, atom_name1);
299  // Add residue string to 'row_names_'
300  row_names_.push_back(p1.string_rep());
301  // Loop over atoms in ligand
302  for (core::Size j = 1; j <= pose.residue(ligand_seqpos).atoms().size();j++) {
303  // Skip hydrogen atoms
304  if(pose.residue(ligand_seqpos).atom_is_hydrogen(j))
305  continue;
306  // Initialize second partner, create contact and add to 'contacts_'
307  std::string atom_name2 = pose.residue(ligand_seqpos).atom_name(j);
308  ContactPartner p2(ligand_seqpos, ligand_resname, atom_name2);
309  Contact contact = Contact(p1, p2);
310  contacts_.push_back(contact);
311  // Add ligand atom string to 'column_names_'
312  if (i == begin)
313  column_names_.push_back(p2.string_rep());
314  // Set matrix value to corresponding position in contacts_ vector
315  output_matrix_.push_back(matrix_position++);
316  }
317  }
318 }
319 
320 /// @brief Initializes ContactMap between two separate regions
322  core::Size start1,
323  core::Size end1,
324  core::Size start2,
325  core::Size end2,
326  Pose const & pose)
327 {
328  core::Size matrix_position = 1;
329  // Loop over residues in region1
330  for (core::Size i = start1; i <= end1; i++) {
331  // Assign ContactPartner1
332  std::string atom_name1 = pose.residue_type(i).name1() == 'G' ? "CA"
333  : "CB";
334  std::string resname1 = pose.residue(i).name3();
335  ContactPartner p1(i, resname1, atom_name1);
336  // Add ContactPartner1 string to 'row_names_'
337  row_names_.push_back(p1.string_rep());
338  // Loop over residues in region2
339  for (core::Size j = start2; j <= end2; j++) {
340  // Assign ContactPartner2
341  std::string atom_name2 = pose.residue_type(j).name1() == 'G' ? "CA"
342  : "CB";
343  std::string resname2 = pose.residue(j).name3();
344  ContactPartner p2(j, resname2, atom_name2);
345  // Create contact and add to 'contacts_'
346  Contact contact = Contact(p1, p2);
347  contacts_.push_back(contact);
348  // Add ContactPartner2 string to 'column_names_'
349  if (i == start1)
350  column_names_.push_back(p2.string_rep());
351  // Set matrix value to corresponding position in contacts_ vector
352  output_matrix_.push_back(matrix_position++);
353  }
354  }
355 }
356 
357 /// @brief Process supplied pose
358 void ContactMap::apply(Pose & pose) {
359  using namespace pose;
360  n_poses_++;
361 
362  // Iterate over contacts
363  for (utility::vector1<Contact>::iterator it = contacts_.begin(); it != contacts_.end(); it++){
364  ContactPartnerAP p1(it->partner1());
365  ContactPartnerAP p2(it->partner2());
366  // Get coordinates of both contact partners and calculate distance
367  numeric::xyzVector<core::Real> v1 = pose.residue(p1->seqpos()).atom(p1->atomname()).xyz();
368  numeric::xyzVector<core::Real> v2 = pose.residue(p2->seqpos()).atom(p2->atomname()).xyz();
369  core::Real distance = v1.distance(v2);
370  // Add distance to contact if it's below the cutoff value
371  if (distance <= distance_cutoff_)
372  it->add_distance(distance);
373  }
374 
375  // Output ContactMap to file if the number of processed poses since last output equals models_per_file_ variable
376  if(models_per_file_ > 0 && n_poses_ % models_per_file_ == 0){
377  // If the ContactMap is to be reset, create a unique output name and write the ContactMap to this file
378  if(reset_count_){
379  // Get the file name of the output structure. This will be
380  // something_XXXX.pdb if you're outputting to pdbs, something_XXXX if you're outputting to silent files
382  // Append a prefix and a suffix to get a final filename for the contact map output
383  std::string contact_map_file_name(output_prefix_ + structure_output_name + ".csv");
384  // Call output function with the generated filename
385  write_to_file(contact_map_file_name);
386  // Reset ContactMap
387  reset();
388  } else{
389  // If the ContactMap should just be updated, reconstruct the output name based on the current job name and
390  // the specified prefix
391  std::string current_job_tag(protocols::jd2::JobDistributor::get_instance()->current_job()->input_tag());
392  // Append a prefix and a suffix to get a final filename for the contact map output
393  std::string contact_map_file_name(output_prefix_ + current_job_tag + ".csv");
394  // Call output function with the generated filename
395  write_to_file(contact_map_file_name);
396  }
397  }
398 }
399 
400 /// @brief Resets the movers n_poses_ variable and the counts of all contacts to 0
402  n_poses_ = 0;
403  for (utility::vector1<Contact>::iterator it = contacts_.begin(); it != contacts_.end(); it++){
404  it->reset_count();
405  }
406 }
407 
408 /// @brief Output function that writes the ContactMap to the specified file
410  if (filename == "")
411  filename = output_prefix_ + ".csv";
412  TR.Info << "Writing ContactMap to '" << filename
413  << "', ContactMap includes " << n_poses_ << " structure(s)."
414  << std::endl;
415 
416  // Initialize output stream and write Header
417  utility::io::ozstream output_stream;
418  output_stream.open(filename, std::ios_base::out);
419  output_stream << "# Number of Models: " << n_poses_ << std::endl
420  << std::endl;
421 
422  if (row_format_) {
423  for (utility::vector1<Contact>::iterator it = contacts_.begin(); it != contacts_.end(); it++){
424  output_stream << it->long_string_rep() << std::endl;
425  }
426  } else {
427 
428  // Print column header line
429  for (core::Size col = 1; col <= column_names_.size(); col++) {
430  output_stream << "\t" << column_names_[col];
431  }
432  output_stream << std::endl;
433 
434  for (core::Size row = 1; row <= row_names_.size(); row++) {
435  // Print row header
436  output_stream << row_names_[row];
437  // Loop over columns and print corresponding fields
438  for (core::Size col = 1; col <= column_names_.size(); col++) {
439  core::Size pos_in_contacts = output_matrix_[(row - 1)
440  * column_names_.size() + col];
441  output_stream << "\t"
442  << contacts_.at(pos_in_contacts).string_rep();
443  }
444  output_stream << std::endl;
445  }
446  }
447  // Finish up
448  output_stream.close();
449 }
450 
451 
452 /////////////////////////////// ContactPartner ///////////////////////////////
453 
455  std::ostringstream oss;
456  oss << resname_ << seqpos_;
457  std::string test;
458  // Append atomname if it's not the default
459  if (atomname_ != "CA" && atomname_ != "CB")
460  oss<< "-"<<atomname_;
461  return oss.str();
462 }
463 
464 
465 /////////////////////////////// Contact ///////////////////////////////
466 
467 /// @brief Adds distance to the contact
469  ++count_;
470 }
471 
472 /// @brief Resets count to 0
474  count_ = 0;
475 }
476 
477 /// @brief Returns string representation of the Contact
479  std::ostringstream oss;
480 // oss << partner1_.string_rep() <<"|"<<partner2_.string_rep();
481  oss << count_;
482  return oss.str();
483 }
484 
485 /// @brief Returns string representation of the Contact as percentage value
487  std::ostringstream oss;
488  core::Real percentage = core::Real(count_) / core::Real(n_poses);
489  oss << percentage;
490  return oss.str();
491 }
492 
493 
494 /// @brief Returns string representation of the Contact including partner names
496  std::string stringrep;
497  stringrep = partner1_.string_rep() + "\t"+ partner2_.string_rep() + "\t";
498  stringrep = stringrep + ( (n_poses==0) ? string_rep() :string_rep(n_poses));
499  return stringrep;
500 }
501 
502 } // moves
503 } // protocols