Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
annotated_sequence.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/pose/annotated_sequence.cc
11 /// @brief utility functions for making poses from sequences
12 /// @author P. Douglas Renfrew
13 /// @author Sam Deluca
14 /// @author Labonte (carbohydrate versions)
15 
16 // Unit Headers
18 
19 // Package Headers
24 #include <core/chemical/AA.hh>
28 
29 
30 // Project Headers
31 #include <core/types.hh>
32 #include <core/pose/Pose.hh>
33 #include <core/pose/util.hh>
34 
35 
36 // Utility Headers
37 #include <basic/Tracer.hh>
38 #include <utility/vector1.hh>
39 
40 // ObjexxFCL Headers
41 #include <ObjexxFCL/string.functions.hh>
42 
43 namespace core {
44 namespace pose {
45 
46 static basic::Tracer tr("core.pose");
47 
48 using namespace core;
49 using namespace core::conformation;
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 /// @details Given a protein sequence where each character represents an amino
53 /// acid, and a ResidueTypeSet, return the residue types that match the
54 /// sequence. NOTE: support making residue types from a fully annotated sequence
55 /// now, that is, for each residue variant or ligand which cannot be deduced
56 /// from one letter code directly, a [] is added directly following the one
57 /// letter code containing the residue's fullname, for example
58 /// K[lys_p:NtermProteinFull]ADFGCH[HIS_D]QNVE[glu_p:CtermProteinFull]Z[ZN].
59 /// This allows a pose to be constructed with full features from a silent output
60 /// file, such as with distinguished HIS tautomers, various chain termini and
61 /// cutpoint variants etc. Currently not working with disulfide variant CYD, but
62 /// this is on to-do list.
64  std::string const & sequence_in,
65  chemical::ResidueTypeSet const & residue_set,
66  bool const auto_termini /* true */
67 )
68 {
69  chemical::ResidueTypeCOPs requested_types;
70 
71  using namespace core::chemical;
72 
73  if ( !sequence_in.size() ) return requested_types;
74 
75  // deal with the sequence read in; any non-standard protein AA name including lig should be put within a bracket[]
76  // following the one-letter AA character. X for aa_vrt and Z for aa_unk
77  std::string fullname;
78  utility::vector1< std::string > fullname_list; // a vector of non-standard full names
79  std::vector< Size > oneletter_to_fullname_index; // for each one-letter sequence, zero means no fullname given
80 
81  // we start with the first character in sequence and that should be a standard AA.
82  std::string one_letter_sequence = sequence_in.substr( 0,1 );
83  Size last_index = 0; // zero means this one-letter name does not have a fullname specified in bracket.
84  bool in_bracket = false; // currently whether scanning fullname in bracket or not.
85 
86  for ( Size seqpos = 1; seqpos < sequence_in.length(); ++seqpos ) {
87  // inside the bracket will be the base name of this residue;
88  char aa = sequence_in[ seqpos ];
89 
90  // note that a full-name aa will also have its one-letter code present e.g. C[CYS]
91  // hence the seqpos-count is not messed up
92  if ( aa == '[' ) { // bracket starts, turn on flag and reset fullname string
93  in_bracket = true;
94  fullname = "";
95  continue;
96  } else if ( sequence_in[ seqpos ] == ']' ) { // bracket ends, save fullname and map its index
97  in_bracket = false;
98  fullname_list.push_back( fullname );
99  last_index = fullname_list.size();
100  continue;
101  }
102 
103  if ( in_bracket ) { // in bracket, get fullname one char at a time
104  fullname += aa;
105  continue;
106  } else { // outside bracket, save regular one-letter sequence.
107  one_letter_sequence += aa;
108  oneletter_to_fullname_index.push_back( last_index );
109  last_index = 0;
110  }
111  } // finish reading in the whole sequence.
112 
113  oneletter_to_fullname_index.push_back( last_index );
114  tr.Debug << "one_letter: " << one_letter_sequence << std::endl;
115  tr.Debug << "seq_in: " << sequence_in << std::endl;
116 
117  // setup the pose by appending the appropriate residues
118  for ( Size seqpos = 1; seqpos <= one_letter_sequence.length(); ++seqpos ) {
119  char aa = one_letter_sequence[ seqpos-1 ]; // string indexing is zero-based!
121 
122  bool is_lower_terminus(false), is_upper_terminus(false);
123 
124  // is there an annotated fullname defined for this one-letter code?
125  Size index = oneletter_to_fullname_index[ seqpos-1 ];
126  if ( index ) { // fullname defined and get it directly from name_map
127  // The next call requires reference -> CAP because ResidueTypeSet's
128  // methods are not yet consistent in handing out ref vs CAP.
129  requested_types.push_back( &residue_set.name_map( fullname_list[ index ] ) );
130  is_lower_terminus = ( *requested_types.back() ).has_variant_type( chemical::LOWER_TERMINUS );
131  is_upper_terminus = ( *requested_types.back() ).has_variant_type( chemical::UPPER_TERMINUS );
132  } else {
133  // use aa_map to find list of possible ResidueTypes
134  chemical::ResidueTypeCOPs const & rsd_type_list( residue_set.aa_map( my_aa ) );
135  // for non-annotated sequence, assume single chain for now
136  is_lower_terminus = auto_termini && ( seqpos == 1 );
137  is_upper_terminus = auto_termini && ( seqpos == one_letter_sequence.length() );
138  bool const is_terminus( is_lower_terminus || is_upper_terminus ); // redundant, but for convenience
139 
140  Size best_index = 0;
141  // iterate over rsd_types, pick one.
142  for ( Size j = 1; j <= rsd_type_list.size(); ++j ) {
143  chemical::ResidueType const & rsd_type( *(rsd_type_list[ j ]) );
144 
145  bool const is_polymer( rsd_type.is_polymer() );
146  // pick a ResidueType
147  Size nvariants = rsd_type.variant_types().size();
148  if ( is_polymer && ( is_terminus && ( nvariants == 0 ) ) ) continue;
149  if ( is_polymer && ( is_lower_terminus != rsd_type.has_variant_type( chemical::LOWER_TERMINUS ) ||
150  is_upper_terminus != rsd_type.has_variant_type( chemical::UPPER_TERMINUS ) ) ) continue;
151 
152  best_index = j;
153  break;
154  }
155  if ( !best_index ) utility_exit_with_message( " can't find residue type at pos " + ObjexxFCL::string_of(seqpos) +
156  "in sequence "+ sequence_in);
157  // add the ResidueTypeCOP
158  requested_types.push_back( rsd_type_list[ best_index ] );
159  }
160 
161  tr.Trace << "residue_types_from_sequence(): seqpos: " << seqpos << " aa " << aa << " " << my_aa << std::endl;
162 
163  } // for seqpos
164 
165  return requested_types;
166 }
167 
168 
169 // Return a list of carbohydrate ResidueTypes corresponding to an annotated polysaccharide sequence.
170 /// @param[in] <sequence>: an annotated polysaccharide sequence,
171 /// e.g., "alpha-D-Glcp-(1->4)-alpha-D-Glcp-(1->4)-D-Glcp"
172 /// @param[in] <residue_set>: the desired residue set
173 /// @return a 1-indexed vector of ResidueType owning pointers, from left-to-right, as indicated by the sequence
174 /// @details Format for <sequence>:\n
175 /// Prefixes apply to the residue to which they are attached, below indicated by residue n.\n
176 /// Residues are listed from N to 1, where N is the total number of residues in the saccharide.\n
177 /// The sequence is parsed by reading to the next hyphen, so hyphens are crucial.\n
178 /// Linkage indication: "(a->x)-" specifies the linkage of residue n, where a is the anomeric carbon number of residue
179 /// (n+1) and x is the oxygen number of residue n. The first residue listed in the annotated sequence (residue N)
180 /// need not have the linkage prefix. A ->4) ResidueType will automatically be assigned by default if not specified.\n
181 /// Anomer indication: The strings "alpha-" or "beta-" are supplied next, which determines the stereochemistry of the
182 /// anomeric carbon of the residue to which it is prefixed. An alpha ResidueType will automatically be assigned by
183 /// default.\n
184 /// Stereochemical indication: "L-" or "D-" specifies whether residue n is an L- or D-sugar. The default is "D-".\n
185 /// 3-Letter code: A three letter code (in sentence case) MUST be supplied next. This specifies the "base sugar name",
186 /// e.g., Glc is for glucose. (A list of all recognized 3-letter codes for sugars can be found in
187 /// src/core/chemical/carbohydrates/CarbohydrateInfo.cc.)\n
188 /// 1-Letter suffix: If no suffix follows, residue n will be linear. If a letter is present, it indicates the ring
189 /// size, where "f" is furanose, "p" is puranose, and "s" is septanose.
190 /// @remarks At present time, param files only exist for two variations of glucopyranose! ~ Labonte
193  chemical::ResidueTypeSet const & residue_set)
194 {
195  using namespace std;
196  using namespace chemical;
197  using namespace carbohydrates;
198 
199  ResidueTypeCOPs residue_types;
200 
201  if (!sequence.size()) {
202  return residue_types;
203  }
204 
205  // Add delimiter to end of sequence.
206  string sequence_with_hyphen = sequence + '-';
207 
208  // Loop through sequence one character at a time, form affixes and 3-letter codes, and assign ResidueTypes.
209  uint const sequence_end = sequence_with_hyphen.length();
210  char character;
211  string morpheme = "";
212  string residue_type_name = "";
213  bool linkage_assigned = false;
214  bool anomer_assigned = false;
215  bool L_or_D_assigned = false;
216  for (uint chr_num = 0; chr_num < sequence_end; ++chr_num) {
217  character = sequence_with_hyphen[chr_num];
218 
219  if (character != '-') { // '-' is the morpheme delimiter
220  morpheme += character;
221  } else { // The morpheme is complete; interpret it....
222  // Linkage indication, first half (ignored)
223  if (morpheme[0] == '(') {
224  morpheme = ""; // The "(_" information is not needed; continue on to the next morpheme.
225 
226  // Linkage indication, second half
227  } else if (morpheme[0] == '>') {
228  if (anomer_assigned || L_or_D_assigned) {
229  utility_exit_with_message("Saccharide sequence input error: "
230  "the linkage notation must precede other prefixes.");
231  } else {
232  residue_type_name += '-' + morpheme + '-';
233  linkage_assigned = true;
234  morpheme = "";
235  }
236 
237  // Anomer indication
238  } else if (morpheme == "alpha" || morpheme == "beta") {
239  if (L_or_D_assigned) {
240  utility_exit_with_message("Saccharide sequence input error: "
241  "alpha/beta notation must precede L- or D- prefixes.");
242  } else {
243  // Set default linkage if missed.
244  if (!linkage_assigned) {
245  residue_type_name += "->4)-";
246  linkage_assigned = true;
247  }
248  residue_type_name += morpheme + '-';
249  anomer_assigned = true;
250  morpheme = "";
251  }
252 
253  // L/D indication
254  } else if (morpheme == "L" || morpheme == "D") {
255  // Set other defaults if missed.
256  if (!linkage_assigned) {
257  residue_type_name += "->4)-";
258  linkage_assigned = true;
259  }
260  if (!anomer_assigned) {
261  residue_type_name += "alpha-";
262  anomer_assigned = true;
263  }
264  residue_type_name += morpheme + '-';
265  L_or_D_assigned = true;
266  morpheme = "";
267 
268  // 3-Letter code (must be found in map of allowed 3-letter codes) and suffix
269  } else if (morpheme.length() >= 3 &&
270  CarbohydrateInfo::CODE_TO_ROOT_MAP.count(morpheme.substr(0, 3))) {
271  // Set defaults if missed.
272  if (!linkage_assigned) {
273  residue_type_name += "->4)-";
274  }
275  if (!anomer_assigned) {
276  residue_type_name += "alpha-";
277  }
278  if (!L_or_D_assigned) {
279  residue_type_name += "D-";
280  }
281 
282  // Assign 3-letter code.
283  residue_type_name += morpheme.substr(0, 3);
284 
285  // Check for 1-letter suffix
286  if (morpheme.length() == 4) {
287  char suffix = morpheme[3];
288  if (suffix == 'f' || suffix == 'p' || suffix == 's') {
289  residue_type_name += suffix;
290  } else {
291  utility_exit_with_message("Saccharide sequence input error: "
292  "Rosetta currently only supports 5-, 6-, or 7-membered rings.");
293  }
294  } else if (morpheme.length() > 4) {
295  utility_exit_with_message("Saccharide sequence input error: "
296  "Unrecognized modified sugar indicated by suffix.");
297  }
298 
299  // Select a matching ResidueType and add to list (or exit without a match).
300  residue_types.push_back(& residue_set.name_map(residue_type_name));
301 
302  // Reset variables.
303  morpheme = "";
304  residue_type_name = "";
305  linkage_assigned = false;
306  anomer_assigned = false;
307  L_or_D_assigned = false;
308 
309  // Unrecognized morpheme
310  } else {
311  utility_exit_with_message("Saccharide sequence input error: "
312  "Unrecognized sugar and/or notation in sequence.");
313  }
314  }
315  } // next chr_num
316 
317  return residue_types;
318 } // residue_types_from_saccharide_sequence()
319 
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// @details Given a Pose, a protein sequence where each character represents an
323 /// amino acid, and a ResidueTypeSet, give the Pose a conformation of covalently
324 /// linked residues that match the sequence. NOTE: support making pose from a
325 /// fully annotated sequence now, that is, for each residue variant or ligand
326 /// which cannot be deduced from one letter code directly, a [] is added
327 /// directly following the one letter code containing the residue's fullname, e.g.
328 /// K[lys_p:NtermProteinFull]ADFGCH[HIS_D]QNVE[glu_p:CtermProteinFull]Z[ZN].
329 /// This allows a pose to be constructed with full features from a silent output
330 /// file, such as with distinguished HIS tautomers, various chain termini and
331 /// cutpoint variants etc. Currently not working with disulfide variant CYD, but
332 /// this is on to-do list.
334  pose::Pose & pose,
335  std::string const & sequence_in,
336  chemical::ResidueTypeSet const & residue_set,
337  bool const auto_termini /* true */
338 )
339 {
340  // grab residue types
341  chemical::ResidueTypeCOPs requested_types = core::pose::residue_types_from_sequence( sequence_in, residue_set, auto_termini );
342  assert( core::pose::annotated_to_oneletter_sequence( sequence_in ).length() == requested_types.size() );
343 
344  // clear the pose
345  pose.clear();
346 
347  // make the pose
348  bool jump_to_next = false;
349  for ( Size i = 1, ie = requested_types.size(); i <= ie; ++i ) {
350  // grab the new residue
351  chemical::ResidueType const & rsd_type = *requested_types[ i ];
352  core::conformation::ResidueOP new_rsd( NULL );
353  new_rsd = conformation::ResidueFactory::create_residue( rsd_type );
354 
355  // yab 20090219: The following error check was in the original
356  // code prior to the split into core::pose::residue_types_from_sequence()
357  // and this function, but it doesn't appear to be triggerable
358  // because ResidueFactory always returns a residue. I leave it
359  // in for now, but consider taking it out.
360  // I'm taking it out. ~ Labonte
361  //if ( !new_rsd ) {
362  // std::cerr << "cannot create a residue that matches the residue type "
363  // << rsd_type.name1() << " " << rsd_type.name() << " at position " << i << '\n';
364  // utility_exit_with_message( "make_pose_from_sequence fails\n" );
365  //}
366 
367  tr.Trace << "make_pose_from_sequence(): seqpos: " << i << " " << new_rsd->aa() << std::endl;
368 
369  // do the actual append
370  if ( rsd_type.has_variant_type( chemical::LOWER_TERMINUS ) ||
372  new_rsd->aa() == chemical::aa_unk ||
373  new_rsd->aa() == chemical::aa_vrt ||
374  jump_to_next ) {
375  if ( new_rsd->aa() == chemical::aa_unk || new_rsd->aa() == chemical::aa_vrt ) {
376  //fpd tr.Warning << "found unknown aminoacid or X in sequence at position " << i << std::endl;
377  //fpd if ( i< ie ) {
378  //fpd utility_exit_with_message( "found unknown aminoacid or X in sequence\n this leads to a seg-fault if we keep going...\n");
379  //fpd }
380 
381  // if you don't think so ... make the code more stable and remove this
382  // but only if this sequence doesn't seg-fault: KPAFGTNQEDYASYIXNGIIK" );
383 
384  //fpd ^^^ the problem is that the residue following the X should be connected by a jump as well.
385  // it should be of LOWER_TERMINUS variant type, but if not, we'll recover & spit out a warning for now.
386  // same thing for ligands???
387  jump_to_next = true;
388  } else if ( jump_to_next ) {
389  jump_to_next = false;
390  if ( !rsd_type.has_variant_type( chemical::LOWER_TERMINUS ) )
391  tr.Warning << "Residue following X, Z, or an upper terminus is _not_ a lower terminus type! Continuing ..." << std::endl;
392  }
393  pose.append_residue_by_jump( *new_rsd, 1, "", "", true ); // each time this happens, a new chain should be started
394  } else {
395  pose.append_residue_by_bond( *new_rsd, true );
396 
397  //fpd If res i is an upper terminus but (i+1) is not a lower terminus, the code exits on a failed assertion
398  //fpd Don't let this happen; always jump in these cases
399  if (rsd_type.has_variant_type( chemical::UPPER_TERMINUS )) jump_to_next = true;
400  }
401  }
402 
403  tr.Debug << "sequence in pose: " << pose.sequence() << std::endl;
404  tr.Debug << "annotated seq: " << pose.annotated_sequence() << std::endl;
405 
406 } // core::pose::make_pose_from_sequence
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// @details overloaded version of make_pose_from_sequence, does the same
410 /// function, but reads in a string of the residue type set instead of a
411 /// ResidueTypeSet object. Made for PyRosetta.
412 // olange: DONT DUPLICATE CODE sid!
413 // --- I removed the duplication by calling the original "core::pose::make_pose_from_sequence"
415  pose::Pose & pose,
416  std::string const & sequence_in,
417  std::string const & type_set_name,
418  //chemical::ResidueTypeSet const & residue_set,
419  bool const auto_termini /* true */
420 ) {
421  chemical::ResidueTypeSetCAP residue_set( chemical::ChemicalManager::get_instance()->residue_type_set( type_set_name ) );
422  core::pose::make_pose_from_sequence( pose, sequence_in, *residue_set, auto_termini );
423 }
424 
425 
426 // Creates a Pose from an annotated polysaccharide sequence <sequence> with ResidueTypeSet <residue_set> and stores it
427 // in <pose>.
428 /// @param[in] <pose>: the Pose to fill
429 /// @param[in] <sequence>: an annotated polysaccharide sequence,
430 /// e.g., "alpha-D-Glcp-(1->4)-alpha-D-Glcp-(1->4)-D-Glcp"
431 /// @param[in] <residue_set>: the desired residue set
432 /// @param[in] <auto_termini>: if true (default) creates termini variants of terminal residues
433 /// @details Format for <sequence>:\n
434 /// Prefixes apply to the residue to which they are attached, below indicated by residue n.\n
435 /// Residues are listed from N to 1, where N is the total number of residues in the saccharide.\n
436 /// The sequence is parsed by reading to the next hyphen, so hyphens are crucial.\n
437 /// Linkage indication: "(a->x)-" specifies the linkage of residue n, where a is the anomeric carbon number of residue
438 /// (n+1) and x is the oxygen number of residue n. The first residue listed in the annotated sequence (residue N)
439 /// need not have the linkage prefix. A ->4) ResidueType will automatically be assigned by default if not specified.\n
440 /// Anomer indication: The strings "alpha-" or "beta-" are supplied next, which determines the stereochemistry of the
441 /// anomeric carbon of the residue to which it is prefixed. An alpha ResidueType will automatically be assigned by
442 /// default.\n
443 /// Stereochemical indication: "L-" or "D-" specifies whether residue n is an L- or D-sugar. The default is "D-".\n
444 /// 3-Letter code: A three letter code (in sentence case) MUST be supplied next. This specifies the "base sugar name",
445 /// e.g., Glc is for glucose. (A list of all recognized 3-letter codes for sugars can be found in
446 /// src/core/chemical/carbohydrates/CarbohydrateInfo.cc.)\n
447 /// 1-Letter suffix: If no suffix follows, residue n will be linear. If a letter is present, it indicates the ring
448 /// size, where "f" is furanose, "p" is puranose, and "s" is septanose.
449 /// @remarks The order of residues in the created pose is in the opposite direction as the annotated sequence of
450 /// saccharide residues, as sugars are named with the 1st residue as the "main chain", with all other residues named as
451 /// substituents and written as prefixes. In other words, sugars are usually drawn and named with residue 1 to the
452 /// right.\n
453 /// At present time, param files only exist for two variations of glucopyranose! ~ Labonte
454 void
456  std::string const & sequence,
457  chemical::ResidueTypeSet const & residue_set,
458  bool const auto_termini)
459 {
460  using namespace std;
461  using namespace chemical;
462  using namespace conformation;
463 
464  // Get list of carbohydrate residue types.
465  ResidueTypeCOPs residue_types = residue_types_from_saccharide_sequence(sequence, residue_set);
466 
467  // Clear the pose.
468  pose.clear();
469 
470  // Make the pose.
471  // Loop backwards through list, since the lower terminus (reducing end) is the last residue given in an
472  // annotated polysaccharide sequence.
473  uint last_index = residue_types.size();
474  for (uint i = last_index; i >= 1; --i) {
475  ResidueType const & rsd_type = *residue_types[i];
476  ResidueOP new_rsd(NULL);
477  new_rsd = ResidueFactory::create_residue(rsd_type);
478 
479  if (i == last_index) {
480  pose.append_residue_by_jump(*new_rsd, 1, "", "", true);
481  } else {
482  pose.append_residue_by_bond(*new_rsd, true);
483  }
484  }
485 
486  // TEMP: Fix inter-residue torsion angel (in this case phi) until I can understand how to fix this problem globally
487  // for Rosetta. (The default setting is 0.0, which sucks.) ~ Labonte
488  for (uint res_num = 2; res_num <= pose.total_residue(); ++res_num) {
489  pose.set_phi(res_num, -120.0);
490  }
491 
492  if (auto_termini) {
495  }
496 
497  tr.Debug << "Created carbohydrate pose with sequence: " << pose.chain_sequence(1) << endl;
498 }
499 
500 // Creates a Pose from an annotated polysaccharide sequence <sequence> with residue type set name <type_set_name> and
501 // stores it in <pose>.
502 /// @details Overloaded version of make_pose_from_saccharide_sequence() that takes the string name for a residue type
503 /// set instead of a ResidueTypeSet object. A convenience method for PyRosetta.
504 void
506  std::string const & sequence,
507  std::string const & type_set_name /*"fa_standard"*/,
508  bool const auto_termini /*true*/)
509 {
510  using namespace chemical;
511 
512  ResidueTypeSetCAP type_set(ChemicalManager::get_instance()->residue_type_set(type_set_name));
513  make_pose_from_saccharide_sequence(pose, sequence, *type_set, auto_termini);
514 }
515 
516 // Return a Pose from an annotated polysaccharide sequence <sequence> with residue type set name <type_set_name>.
517 /// @details A convenience method for PyRosetta.
520  std::string const & type_set_name /*"fa_standard"*/,
521  bool const auto_termini /*true*/)
522 {
523  using namespace pose;
524 
525  PoseOP pose = new Pose();
526  make_pose_from_saccharide_sequence(*pose, sequence, type_set_name, auto_termini);
527  return pose;
528 }
529 
530 
531 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
532 
534  std::string const & annotated_seq
535 ) {
536  bool add( true );
537  std::string oneletter_seq;
538  for ( Size i = 0; i < annotated_seq.length(); ++i ) {
539  if ( annotated_seq.at(i) == '[' ) add = false;
540  if ( add ) oneletter_seq += annotated_seq.at(i);
541  if ( annotated_seq.at(i) == ']' ) add = true;
542  }
543 
544  return oneletter_seq;
545 }
546 
547 
548 } // namespace core
549 } // namespace pose