Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LoopsFileIO.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 protocols/loops/LoopsFileIO.cc
11 /// @brief
12 /// @author Brian D. Weitzner
13 
14 // Unit header
16 
17 // Package headers
18 #include <protocols/loops/Loop.hh>
19 #include <protocols/loops/Loops.hh>
20 
21 // Project headers
22 #include <core/pose/Pose.hh>
23 #include <core/pose/PDBInfo.hh>
24 
25 // Utility Headers
26 #include <basic/Tracer.hh>
27 #include <utility/exit.hh>
28 #include <utility/string_util.hh> // needed to parse old style loop files
29 #include <utility/vector1.hh>
30 #include <ObjexxFCL/string.functions.hh>
31 
32 
33 
34 
35 namespace protocols {
36 namespace loops {
37 
38 /// @details Auto-generated virtual destructor
40 
41 static basic::Tracer tr("protocols.loops.LoopsFileIO");
44 
45 void
47  bool prohibit_single_residue_loops,
50  std::string const & filename,
51  core::Size linecount
52 )
53 {
54  if ( start > stop || ( start == stop && prohibit_single_residue_loops ) ) {
55  utility_exit_with_message(
56  "[ERROR] Error parsing " + filename + " ( line " + ObjexxFCL::string_of( linecount ) +
57  " ): " + " Invalid loop definition (start residue " +
58  ( prohibit_single_residue_loops ? ">=" : ">" ) + " end residue) - ERROR" );
59  }
60 }
61 
63  unassigned_( true ),
64  pose_numbered_( false ),
65  pose_index_( 0 ),
66  chain_( ' ' ),
67  resindex_( 0 ),
68  insertion_code_( ' ' )
69 {}
70 
72  core::Size pose_index
73 ) :
74  unassigned_( false ),
75  pose_numbered_( true ),
76  pose_index_( pose_index ),
77  chain_( ' ' ),
78  resindex_( 0 ),
79  insertion_code_( ' ' )
80 {}
81 
83  char chain,
84  int resindex,
85  char insertion_code
86 ) :
87  unassigned_( false ),
88  pose_numbered_( false ),
89  pose_index_ ( 0 ),
90  chain_( chain ),
91  resindex_( resindex ),
92  insertion_code_( insertion_code )
93 {}
94 
97  core::pose::Pose const & pose
98 ) const
99 {
100  /// return bogus index, but do not trip an error.
101  if ( unassigned_ ) { return 0; }
102  if ( pose_numbered_ ) {
103  if ( pose_index_ > pose.total_residue() ) {
104  utility_exit_with_message( "Residue index description exceeds the number of residues in the Pose: pose_index_ = " +
105  utility::to_string( pose_index_ ) + " vs pose.total_residue() " + utility::to_string( pose.total_residue() ));
106  }
107  return pose_index_;
108  } else {
109  /// THIS HAS NOT BEEN TESTED OR CAREFULLY CONSIDERED
110  /// ONLY A SKETCH OF CODE THAT COULD BE PUT HERE
111  core::Size resid = pose.pdb_info()->pdb2pose().find( chain_, resindex_, insertion_code_ );
112  if ( resid == 0 ) {
113  // Dealing with the inability to return a null char constant by having two error messages. LAAAAAAME.
114  if ( insertion_code() != ' ' ) utility_exit_with_message( "Unable to find PDB residue " + utility::to_string( resindex_ ) + insertion_code_ + ' ' + "on chain " + chain_ + " in input Pose" );
115  utility_exit_with_message( "Unable to find PDB residue " + utility::to_string( resindex_ ) + insertion_code_ + "on chain " + chain_ + " in input Pose" );
116  }
117  return resid;
118  }
119 }
120 
123  linenum_( 0 )
124 {}
125 
127  std::string fname,
128  core::Size linenum,
129  core::Size pose_index
130 ) :
131  ResidueIndexDescription( pose_index ),
132  fname_( fname ),
133  linenum_( linenum )
134 {}
135 
137  std::string fname,
138  core::Size linenum,
139  char chain,
140  int resindex,
141  char insertion_code
142 ) :
143  ResidueIndexDescription( chain, resindex, insertion_code ),
144  fname_( fname ),
145  linenum_( linenum )
146 {}
147 
150  core::pose::Pose const & pose
151 ) const
152 {
153  /// return bogus index, but do not trip an error.
154  if ( unassigned() ) { return 0; }
155  if ( pose_numbered() ) {
156  if ( pose_index() > pose.total_residue() ) {
157  utility_exit_with_message( "Residue index description given on line " + utility::to_string( linenum_ ) +
158  " of the file named " + fname_ + " exceeds the number of residues in the Pose: pose_index_ = " +
159  utility::to_string( pose_index() ) + " vs pose.total_residue() " + utility::to_string( pose.total_residue() ));
160  }
161  return pose_index();
162  } else {
163  /// THIS HAS NOT BEEN TESTED OR CAREFULLY CONSIDERED
164  /// ONLY A SKETCH OF CODE THAT COULD BE PUT HERE
165  core::Size resid = pose.pdb_info()->pdb2pose().find( chain(), resindex(), insertion_code() );
166  if ( resid == 0 ) {
167  // Dealing with the inability to return a null char constant by having two error messages. LAAAAAAME.
168  if ( insertion_code() != ' ' ) utility_exit_with_message( "Unable to find PDB residue " + utility::to_string( resindex() ) + insertion_code() + ' ' + "on chain " + chain() + " in input Pose" );
169  utility_exit_with_message( "Unable to find PDB residue " + utility::to_string( resindex() ) + insertion_code() + "on chain " + chain() + " in input Pose" );
170  }
171  return resid;
172  }
173 }
174 
176  skip_rate_( 0.0 ),
177  extended_( false ),
178  prohibit_single_residue_loops_( true )
179 {}
180 
182  ResidueIndexDescriptionFromFile const & start_res,
183  ResidueIndexDescriptionFromFile const & cutpoint_res,
184  ResidueIndexDescriptionFromFile const & end_res,
186  bool extended,
187  bool prohibit_single_residue_loops
188 ) :
189  start_res_( start_res ),
190  cutpoint_res_( cutpoint_res ),
191  end_res_( end_res ),
192  skip_rate_( skip_rate ),
193  extended_( extended ),
194  prohibit_single_residue_loops_( prohibit_single_residue_loops )
195 {}
196 
197 /// constructed the other way around (for the the PoseNumberedLoopReader)
199  SerializedLoop const & loop,
200  std::string const & fname,
201  bool prohibit_single_residue_loops
202 ) :
203  start_res_( fname, 0, loop.start ),
204  cutpoint_res_( fname, 0, loop.cut ),
205  end_res_( fname, 0, loop.stop ),
206  skip_rate_( loop.skip_rate ),
207  extended_( loop.extended ),
208  prohibit_single_residue_loops_( prohibit_single_residue_loops )
209 {}
210 
211 /// @brief Convert from the information read from the loop-definition file into
212 /// residue indices that make sense in the context of this pose, and validate
213 /// the input loop definition (i.e. that the index of the start residue is
214 /// less than the index of the end residue ).
217 {
218 
219  core::Size const start_res_index = start_res_.resolve_index( pose );
220  core::Size const cutpoint_res_index = cutpoint_res_.resolve_index( pose );
221  core::Size const end_res_index = end_res_.resolve_index( pose );
223  prohibit_single_residue_loops_, start_res_index, end_res_index,
225 
226  SerializedLoop loop;
227  loop.start = start_res_index;
228  loop.cut = cutpoint_res_index;
229  loop.stop = end_res_index;
230  loop.skip_rate = skip_rate_;
231  loop.extended = extended_;
232 
233  return loop;
234 }
235 
236 LoopsOP
238  core::pose::Pose const & pose
239 ) const
240 {
242  return new Loops( sloops );
243 }
244 
247  core::pose::Pose const & pose
248 ) const
249 {
250  SerializedLoopList sloops; sloops.reserve( size() );
251  for ( Size ii = 1; ii <= size(); ++ii ) {
252  sloops.push_back( (*this)[ ii ].resolve_as_serialized_loop_from_pose( pose ) );
253  }
254  return sloops;
255 }
256 
258 {
259  return loops_file_data_.size();
260 }
261 
263 {
264  loops_file_data_.resize( new_size );
265 }
266 
268 {
269  loops_file_data_.push_back( loop );
270 }
271 
273 {
274  loops_file_data_[ i ] = loop;
275 }
276 
278 {
279  return loops_file_data_[ i ];
280 }
281 
282 
283 /// @details default constructor: set state to not expect a pose, but to return an empty Loops object
285  in_charge_( true ),
286  pose_has_resolved_loop_indices_( true ),
287  rely_on_loopfile_indices_( false ),
288  loops_( new Loops )
289 {}
290 
291 /// @details construct from LoopsFileData: set state to expect a Pose
293  in_charge_( true ),
294  pose_has_resolved_loop_indices_( false ),
295  rely_on_loopfile_indices_( true ),
296  loops_file_data_( lfd ),
297  loops_( new Loops )
298 {}
299 
300 /// @details construct from a LoopsOP
302  in_charge_( false ),
303  pose_has_resolved_loop_indices_( true ),
304  rely_on_loopfile_indices_( false ),
305  loops_( loops ) // copy the pointer -- assume this pointer comes from some other GuardedLoopsFromFile object and that I am not in charge
306 {}
307 
308 
309 /// @details construct from a LoopsOP
311  in_charge_( false ),
312  pose_has_resolved_loop_indices_( true ),
313  rely_on_loopfile_indices_( false ),
314  loops_( new Loops( loops ) ) // copy the contents into a new loops object -- assume this pointer comes from some other GuardedLoopsFromFile object and that I am not in charge
315 {}
316 
317 /// @details Shallow copy of the LoopsOP data so that it can be shared between
318 /// multiple objects; take the "in_charge_" bit from the source in the event that
319 /// this is a called as part of a clone.
321  utility::pointer::ReferenceCount(),
322  in_charge_( src.in_charge_ ),
323  pose_has_resolved_loop_indices_( src.pose_has_resolved_loop_indices_ ),
324  rely_on_loopfile_indices_( src.rely_on_loopfile_indices_ ),
325  loops_file_data_( src.loops_file_data_ ),
326  loops_( src.loops_ )
327 {}
328 
329 /// @details Shallow copy of the LoopsOP data so that it can be shared between
330 /// multiple objects -- also assume that the GuardedLoopsFromFile object is the one that is in charge.
332  utility::pointer::ReferenceCount(),
333  in_charge_( false ),
334  pose_has_resolved_loop_indices_( src.pose_has_resolved_loop_indices_ ),
335  rely_on_loopfile_indices_( src.rely_on_loopfile_indices_ ),
336  loops_file_data_( src.loops_file_data_ ),
337  loops_( src.loops_ )
338 {}
339 
341 
342 GuardedLoopsFromFile const &
344  if ( this != & rhs ) {
345  // should this be set to false under the assumption that "this" is subserviant to "rhs" (rhs may or may not be in charge)?
346  /// no, because this function might be called from an assignment operator
347  in_charge_ = rhs.in_charge_;
348 
352  loops_ = rhs.loops_;
353  }
354  return *this;
355 }
356 
357 void
359 {
360  in_charge_ = setting;
361 }
362 
364 
365 /// @details This will re-resolve the loop indices with the input pose, even if they had been resolved in the past.
366 void
368 {
369  if ( ! in_charge_ ) return;
371  LoopsOP loops_from_lfd = loops_file_data_.resolve_loops( pose );
372  (*loops_) = (*loops_from_lfd );
374 }
375 
376 /// @details This will only resolve the loop indices once, so repeated calls to this will not alter the Loops
377 /// object with (possibly) new loop indices.
378 void
380 {
381  if ( ! in_charge_ ) return;
382  if ( pose_has_resolved_loop_indices_ ) return;
383  resolve_loop_indices( pose );
384 }
385 
386 /// @brief request the LoopsCOP pointer; asserts that the loop indices
387 /// have been resolved or that "I am not in charge".
388 LoopsCOP
390 {
392  return loops_;
393 }
394 
395 /// @brief request the LoopsOP pointer; asserts that the loop indices
396 /// have been resolved or that "I am not in charge".
397 LoopsOP
399 {
401  return loops_;
402 }
403 
404 /// @brief Deep copy into the loops data; this updates the single Loops object that is / can be shared
405 /// among multiple objects.
406 void
408 {
409  pose_has_resolved_loop_indices_ = true; // the assumption is that the user has resolved the indices themselves.
410  rely_on_loopfile_indices_ = false; // the user has indicated the Loops data should be used and not the LoopsFileData
411  *loops_ = setting;
412 
413 }
414 
415 /// @brief Shallow copy of the loops data
416 void
418 {
419  assert( ! in_charge_ );
420  pose_has_resolved_loop_indices_ = true; // the assumption is that the user has resolved the indices themselves.
421  rely_on_loopfile_indices_ = false; // the user has indicated the Loops data should be used and not the LoopsFileData
422  loops_ = setting;
423 
424 }
425 
426 /// @brief set the LoopsFileData object directly
427 void
429 {
430  assert( in_charge_ ); // if not in_charge, then this data will never be used.
433  loops_file_data_ = setting;
434 }
435 
436 /// @brief read access to the LoopsFileData
437 LoopsFileData const &
439 {
440  return loops_file_data_;
441 }
442 
443 
444 LoopsFileIO::LoopsFileIO() : utility::pointer::ReferenceCount()
445 {
446 
447 }
448 
449 LoopsFileIO::LoopsFileIO( const LoopsFileIO & ) : utility::pointer::ReferenceCount()
450 {
451 }
452 
453 // destructor
455 
456 //////////////////////////////////////////////////////////////////////
457 std::ostream & operator<< ( std::ostream & os, const LoopsFileIO & /*loops*/ ) {
458  /*
459  os << "LOOP begin end cut skip_rate extended" << std::endl;
460  for ( Loops::const_iterator it = loops.begin(), it_end = loops.end();
461  it != it_end; ++it ) {
462  os << *it << std::endl;
463  }
464  */
465  return os;
466 }
467 
468 
471  std::string const & filename,
472  bool prohibit_single_residue_loops
473 )
474 {
475  std::ifstream infile( filename.c_str() );
476 
477  if (!infile.good()) {
478  utility_exit_with_message( "[ERROR] Error opening RBSeg file '" + filename + "'" );
479  }
480  return read_loop_file_stream( infile, filename, prohibit_single_residue_loops );
481 }
482 
485  std::istream & loopfstream,
486  std::string const & filename,
487  bool prohibit_single_residue_loops
488 )
489 {
490  // if the first line is a comment, consume this line and determine if the line is
491  // specifying the new file format
492  core::Size lines_pre_read( 0 );
493  if ( loopfstream.peek() == '#' ) {
494  std::string line;
495  getline( loopfstream, line );
496  ++lines_pre_read;
498 
499  if ( tokens.size() >= 3 && tokens[2] == "FORMAT" ) {
500  if ( tokens[3] == "JSON" ) {
502  reader.set_linecount_offset( lines_pre_read );
503  LoopsFileDataOP loops = reader.read_loop_file( loopfstream, filename, prohibit_single_residue_loops );
504  return loops;
505  }
506  }
507 
508  }
509 
511  reader.set_linecount_offset( lines_pre_read );
512  SerializedLoopList sloops = reader.read_pose_numbered_loops_file( loopfstream, filename, prohibit_single_residue_loops );
513  LoopsFileDataOP loops = new LoopsFileData;
514  loops->resize( sloops.size() );
515  for ( core::Size ii = 1; ii <= sloops.size(); ++ii ) {
516  loops->insert_loop_at_index( LoopFromFileData( sloops[ ii ], filename, prohibit_single_residue_loops ), ii );
517  }
518  return loops;
519 }
520 
522  loop_line_begin_token_( "LOOP" ),
523  linecount_offset_( 0 )
524 {}
525 
528  std::istream & is,
529  std::string const & filename,
530  bool strict_looprelax_checks
531 )
532 {
533  std::string line;
534  core::Size linecount = linecount_offset_;
535  int errcount=50; //if we reach 0 we bail!
536 
537  SerializedLoopList loops;
538 
539  while( getline( is, line) ) {
540  linecount++;
542 
543  SerializedLoop current_loop;
544  if ( tokens.size() > 0 ) {
545  if ( tokens[1].substr(0,3) == "END" ) break;
546  if ( tokens[1] == loop_line_begin_token_ ) {
547  if ( tokens.size() < 3 ) {
548  utility_exit_with_message( "[ERROR] Error parsing " + filename + " ( line " + ObjexxFCL::string_of( linecount ) + " ): " + " Minimum of 3 tokens necessary (begin, end, cutpoint)" );
549  }
550  if ( tokens.size() > 6 ) {
551  utility_exit_with_message( "[ERROR] Error parsing " + filename + " ( line " + ObjexxFCL::string_of( linecount ) + " ): " + " Maximum of 6 tokens allowed (LOOP begin end cutpoint skiprate extended)" );
552  }
553  current_loop.start = (core::Size) atoi(tokens[2].c_str());
554  current_loop.stop = (core::Size) atoi(tokens[3].c_str());
555  current_loop.cut = 0; // default - let LoopRebuild choose cutpoint
556  current_loop.skip_rate = 0.0; // default - never skip
557  std::string extend_loop_str;
558  bool extend_loop = false;
559 
560  if (tokens.size() > 3)
561  current_loop.cut = (core::Size) atoi(tokens[4].c_str());
562  if (tokens.size() > 4)
563  current_loop.skip_rate = atof(tokens[5].c_str());
564  if (tokens.size() > 5){
565  if ( tokens[6] == "X" ){
566  tr.Error << "[ERROR] Error parsing " + filename + " ( line " + ObjexxFCL::string_of( linecount ) + " ): " + "[WARNING] DEPRECATED old style extended marker X is used" << std::endl;
567  extend_loop = true;
568  if ( errcount > 0 ) errcount--;
569  else {
570  utility_exit_with_message( "too many errors in loop-file " + filename );
571  }
572  }else{
573  int extended_token = atoi(tokens[6].c_str());
574  if ( extended_token == 0 ) extend_loop = false;
575  else extend_loop = true;
576  }
577  }
578 
579  current_loop.extended = extend_loop;
580  validate_loop_start_stop( strict_looprelax_checks, current_loop.start, current_loop.stop, filename, linecount );
581  loops.push_back( current_loop );
582  } else if ( tokens[1][0] != '#' ) {
583  if (tokens.size() >= 2) {
584  tr.Error << "[ERROR] Error parsing " + filename + " ( line " + ObjexxFCL::string_of( linecount ) + " ): " + "DEPRECATED r++ style loopfile" << std::endl;
585 
586  if ( errcount>0 ) {
587  errcount--;
588  } else {
589  utility_exit_with_message( "too many errors in loop-file " + filename );
590  }
591 
592  current_loop.start = (core::Size) atoi(tokens[1].c_str());
593  current_loop.stop = (core::Size) atoi(tokens[2].c_str());
594  current_loop.cut = 0; // default - let LoopRebuild choose cutpoint
595  current_loop.skip_rate = 0.0; // default - never skip
596  bool extend_loop = false; // default - not extended
597  if (tokens.size() > 2) {
598  current_loop.cut = (core::Size) atoi(tokens[3].c_str());
599  }
600  if (tokens.size() > 3) {
601  current_loop.skip_rate = atof(tokens[4].c_str());
602  }
603  if (tokens.size() > 4) {
604  if ( tokens[5] == "X" ){
605  tr.Error << "[ERROR] Error parsing " + filename + " ( line " + ObjexxFCL::string_of( linecount ) + " ): " + "[WARNING] DEPRECATED old style extended marker X is used" << std::endl;
606  extend_loop = true;
607  } else {
608  int extended_token = atoi(tokens[5].c_str());
609  if ( extended_token == 0 ) extend_loop = false;
610  else extend_loop = true;
611  }
612  }
613  current_loop.extended = extend_loop;
614 
615  validate_loop_start_stop( strict_looprelax_checks, current_loop.start, current_loop.stop, filename, linecount );
616  loops.push_back( current_loop );
617 
618  } else {
619  tr.Warning << "[WARNING] Skipping line '" << line << "'" << std::endl;
620  }
621  }
622  }
623  } //while
624 
625  return loops;
626 }
627 
629  linecount_offset_ = setting;
630 }
631 
632 /// @brief For code that relys on reading loop-file-formatted ranges if residues
633 /// but which really ought to use
634 void
636  std::string const & token
637 )
638 {
639  loop_line_begin_token_ = token;
640 }
641 
642 
643 
646  std::istream & is,
647  std::string const & filename,
648  bool prohibit_single_residue_loops
649 ){
650  utility::json_spirit::mValue mapped_json;
651 
652  // sanity check
653  if ( utility::json_spirit::read(is, mapped_json) ) utility_exit_with_message( "Unable to read loops file '" + filename + "'." );
654  if ( mapped_json.type() != utility::json_spirit::obj_type ) utility_exit_with_message( "The loop file '" + filename + "' is not formatted correctly. Please see the documenation.");
655 
656  return parse_json_formatted_data( mapped_json, prohibit_single_residue_loops, filename );
657 }
658 
661  utility::json_spirit::mValue & json_data,
662  bool prohibit_single_residue_loops,
663  std::string const & filename
664 ){
665  std::string LoopSetKey = "LoopSet";
666  if ( ! json_data.get_obj().count( LoopSetKey ) ) utility_exit_with_message( "The loop file '" + filename + "' is not formatted correctly. Please see the documenation.");
667  utility::json_spirit::mArray & array = json_data.get_obj()[LoopSetKey].get_array();
668  if ( ! array.size() ) utility_exit_with_message( "The LoopList appears to be empty. Please check your input file, '" + filename + "'." );
669 
670  LoopsFileDataOP loops = new LoopsFileData;
671  core::Size count_lines_approximate = linecount_offset_;
672  for ( core::Size i=0; i < array.size(); ++i )
673  {
674  ensure_all_fields_are_valid( array[ i ], filename );
675  LoopFromFileData current_loop = LoopFromFileData();
676 
677  current_loop.start_res( parse_json_residue_info( array[ i ], start, filename, count_lines_approximate ) );
678  current_loop.end_res( parse_json_residue_info( array[ i ], stop, filename, count_lines_approximate ) );
679  current_loop.cutpoint_res( parse_json_residue_info( array[ i ], cut_point, filename, count_lines_approximate ) );
680  current_loop.prohibit_single_residue_loops( prohibit_single_residue_loops );
681 
682  parse_configuration_options( array[ i ], current_loop );
683  loops->push_back( current_loop );
684  }
685  return loops;
686 }
687 
688 void
689 JSONFormattedLoopsFileReader::ensure_all_fields_are_valid( utility::json_spirit::mValue & json_data, std::string const & fname )
690 {
691  if ( json_data.type() != utility::json_spirit::obj_type )
692  {
693  utility_exit_with_message( "The loop file '" + fname + "' is not formatted correctly. Please see the documenation.");
694  }
695 
697  for (std::map<std::string,utility::json_spirit::mValue>::iterator it = json_data.get_obj().begin(); it != json_data.get_obj().end(); ++it )
698  {
699 
700  if ( std::find( valid_loop_file_keys_.begin(), valid_loop_file_keys_.end(), it->first ) == valid_loop_file_keys_.end() )
701  {
702  utility_exit_with_message( "Unknown key \"" + it->first + ".\" Please check your input file." );
703  }
704  }
705 }
706 
708 {
709  linecount_offset_ = setting;
710 }
711 
712 
713 
716  utility::json_spirit::mValue & json_loop_data,
717  ResidueIdentifier residue_identifier,
718  std::string const & filename,
719  core::Size & approximate_linenumber
720 ) {
721  core::Size resNo = 0;
722  char chain_id;
723  char insert_code = ' ';
724  bool usesPDBNumbering = false;
725 
726  std::string res_identity = name_from_residue_identifier( residue_identifier );
727  if (json_loop_data.get_obj().count( res_identity ) ) {
728  ++approximate_linenumber; // we found the token, ergo, increment the approximate linenumber
729 
730  ensure_all_fields_are_valid( json_loop_data.get_obj()[ res_identity ], filename );
731  utility::json_spirit::mObject json_representation_of_residue_data = json_loop_data.get_obj()[ res_identity ].get_obj();
732 
733  // resSeq - this is the residue number that will be used.
734  std::string residue_number = name_from_loop_configuration( resSeq );
735  if ( json_representation_of_residue_data.count( residue_number ) ) {
736  if ( json_representation_of_residue_data[ residue_number ].type() != utility::json_spirit::int_type ) {
737  utility_exit_with_message( "The \"resSeq\" field must be an integer. Please check your input file, '" + filename + "'." );
738  }
739  resNo = json_representation_of_residue_data[ residue_number ].get_int();
740  } else {
741  utility_exit_with_message( "The \"resSeq\" field for " + res_identity + " must be defined. Please check your input file, '" + filename + "'." );
742  }
743 
744  // chainID - One letter chainID for the residue number. This is necessary when using PDB numbering.
745  std::string chain_identifier = name_from_loop_configuration( chainID );
746  if ( json_representation_of_residue_data.count( chain_identifier ) ) {
747  if ( json_representation_of_residue_data[ chain_identifier ].type() != utility::json_spirit::str_type ){
748  utility_exit_with_message( "The \"chainID\" field must be a one character string. Please check your input file, '" +filename + "'." );
749  }
750  std::string tmp_chainID = json_representation_of_residue_data[ chain_identifier ].get_str();
751  if ( tmp_chainID.length() != 1 ) {
752  utility_exit_with_message( "chainIDs must be exactly one character long. Please check your input file, '" + filename + "'." );
753  }
754  chain_id = char( tmp_chainID[0] );
755  usesPDBNumbering = true;
756  }
757 
758  // iCode - insertion codes are sometimes used in PDBs. This allows any PDB residue to be used to define the loop.
759  std::string insertion_code = name_from_loop_configuration( iCode );
760  if (json_representation_of_residue_data.count( insertion_code ) ) {
761  if ( ! usesPDBNumbering ) {
762  utility_exit_with_message( "Using an insertion code requires specifying the residue's chainID. Please check your input file, '" + filename + "'." );
763  }
764  if ( json_representation_of_residue_data[ insertion_code ].type() != utility::json_spirit::str_type ) {
765  utility_exit_with_message( "The \"iCode\" field must be a one character string or omitted. Please check your input file, '" + filename + "'." );
766  }
767  std::string tmp_iCode = json_representation_of_residue_data[ insertion_code ].get_str();
768  if ( tmp_iCode.length() != 1 ) {
769  utility_exit_with_message( "Insertion codes must be exactly one character long. Please check your input file, '" + filename + "'." );
770  }
771  insert_code = char( tmp_iCode[0] );
772  }
773  } else if ( res_identity.compare( name_from_residue_identifier( cut_point ) )!= 0 ){
774  utility_exit_with_message( "The \"" + res_identity + "\" residue must be specified. Please check your input file '" + filename + "'." );
775  }
776 
777  return usesPDBNumbering ?
778  ResidueIndexDescriptionFromFile( filename, approximate_linenumber, chain_id, resNo, insert_code ) :
779  ResidueIndexDescriptionFromFile( filename, approximate_linenumber, resNo );
780 }
781 
782 void
784  utility::json_spirit::mValue & json_loop_data,
785  LoopFromFileData & loop
786 ){
787  if (json_loop_data.get_obj().count( name_from_loop_configuration( extras ) ) ) {
788 
789  utility::json_spirit::mObject json_representation_of_residue_data = json_loop_data.get_obj()[ name_from_loop_configuration( extras ) ].get_obj();
790 
791  // skip rate
793  if ( json_representation_of_residue_data.count( skip_rate_name ) ) {
794  if ( json_representation_of_residue_data[ skip_rate_name ].type() != utility::json_spirit::real_type && json_representation_of_residue_data[ skip_rate_name ].type() != utility::json_spirit::int_type ) {
795  utility_exit_with_message( "Skip rates in loop files must be a floating point number in [0, 1). Please check your input file." );
796  }
797  loop.skip_rate( json_representation_of_residue_data[ skip_rate_name ].get_real() );
798 
799  if ( !(loop.skip_rate() >= 0.0 && loop.skip_rate() < 1.0) ) {
800  utility_exit_with_message( "Skip rates in loop files must be in [0, 1). Please check your input file." );
801  }
802  }
803 
804  // extend
806  if ( json_representation_of_residue_data.count( extend_name ) ) {
807  if ( json_representation_of_residue_data[ extend_name ].type() != utility::json_spirit::bool_type ) {
808  utility_exit_with_message( "The \"extend\" field must be a boolean. Use the string literals \"true\" or \"false\" to toggle the behavior. If this field is omitted, it will default to \"false.\" Please check your input file." );
809  }
810  loop.extended( json_representation_of_residue_data[ extend_name ].get_bool() );
811  }
812 
813  // use pose numbering
815  if ( json_representation_of_residue_data.count( pose_numbering_name ) ) {
816  if ( json_representation_of_residue_data[ pose_numbering_name ].type() != utility::json_spirit::bool_type ) {
817  utility_exit_with_message( "The \"use_pose_numbering\" field must be a boolean. Use the string literals \"true\" or \"false\" to toggle the behavior. If this field is omitted, it will default to \"false.\" Please check your input file. Note that this field exists only to provide compatibility with the old style loops files." );
818  }
819  if ( json_representation_of_residue_data[ pose_numbering_name ].get_bool() ) {
820 
821  /// Talk to Andrew about this stuff.
822  /*if ( ! loop.start_res().pose_numbered() || loop.start_res().pose_numbered() != loop.end_res().pose_numbered() || loop.start_res().pose_numbered() != loop.cutpoint_res().pose_numbered() ) {
823  utility_exit_with_message( "Unable to reconcile the mixture of Rosetta and PDB numbering. Please check your input file to ensure the correct numbering scheme is being used." );
824  }
825  return;
826  */
827  }
828  }
829  }
830 
831  /// Talk to Andrew about this stuff.
832 
833 
834  // make sure the numbering scheme is consistent
835  /*if ( loop.start_res().pose_numbered() || loop.start_res().pose_numbered() != loop.end_res().pose_numbered() || loop.start_res().pose_numbered() != loop.cutpoint_res().pose_numbered() ) ) {
836  utility_exit_with_message( "Unable to reconcile the mixture of Rosetta and PDB numbering. Please check your input file to ensure the correct numbering scheme is being used." );
837  } */
838  return;
839 }
840 
841 
843 {
844  if ( initialized_ ) return;
845  initialized_ = true;
846 
848  valid_loop_file_keys_[start] = "start";
849  valid_loop_file_keys_[stop] = "stop";
851  valid_loop_file_keys_[extras] = "extras";
852  valid_loop_file_keys_[resSeq] = "resSeq";
853  valid_loop_file_keys_[iCode] = "iCode";
854  valid_loop_file_keys_[chainID] = "chainID";
855  valid_loop_file_keys_[skip_rate] = "skip_rate";
856  valid_loop_file_keys_[extend] = "extend";
857  valid_loop_file_keys_[use_pose_numbering] = "use_pose_numbering";
858 }
859 
861 {
863  return valid_loop_file_keys_[ residue_identifier ];
864 }
865 
867 {
869  return valid_loop_file_keys_[ loop_configuration ];
870 }
871 
872 } // namespace loops
873 } // namespace protocols