A toolkit for working with phylogenetic data.
v0.24.0
jplace_reader.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2020 Lucas Czech and HITS gGmbH
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
38 
52 
53 #include <algorithm>
54 #include <cassert>
55 #include <cctype>
56 #include <functional>
57 #include <sstream>
58 #include <stdexcept>
59 #include <string>
60 #include <utility>
61 #include <vector>
62 
63 #ifdef GENESIS_OPENMP
64 # include <omp.h>
65 #endif
66 
67 namespace genesis {
68 namespace placement {
69 
70 // =================================================================================================
71 // Reading
72 // =================================================================================================
73 
75  std::shared_ptr<utils::BaseInputSource> source
76 ) const {
77  auto doc = utils::JsonReader().read( source );
78  return read( doc );
79 }
80 
83 ) const {
84  Sample smp;
85 
86  if( ! doc.is_object() ) {
87  throw std::runtime_error( "Json value is not a Json document." );
88  }
89 
90  // Check if the top level keys are according to the standard.
91  auto const& keymap = doc.get_object();
92  for( auto const& kv : keymap ) {
93  auto const& key = kv.first;
94  if(
95  key != "version" && key != "tree" && key != "placements" &&
96  key != "fields" && key != "metadata"
97  ) {
98  LOG_WARN << "Jplace document contains top-level key '" << key << "', which is not part "
99  << "of the jplace standard and hence ignored. This might indicate an issue "
100  << "with the data or the program which generated the document.";
101  }
102  }
103 
104  // Basics.
105  process_jplace_version_( doc );
106  process_jplace_metadata_( doc, smp );
107 
108  // Content.
109  process_jplace_tree_( doc, smp );
110  auto const fields = process_jplace_fields_( doc );
111  process_jplace_placements_( doc, smp, fields );
112 
113  return smp;
114 }
115 
117  std::vector<std::shared_ptr<utils::BaseInputSource>> sources
118 ) const {
119  SampleSet target;
120  read( sources, target );
121  return target;
122 }
123 
125  std::vector<std::shared_ptr<utils::BaseInputSource>> sources,
126  SampleSet& target
127 ) const {
128 
129  // Make a vector of default-constructed Samples of the needed size.
130  // We do this so that the order of input jplace files is kept
131  // when reading with OpenMP.
132  auto tmp = std::vector<Sample>( sources.size() );
133 
134  // Parallel parsing.
135  #pragma omp parallel for
136  for( size_t i = 0; i < sources.size(); ++i ) {
137  tmp[ i ] = read( sources[i] );
138  }
139 
140  // Move to target SampleSet.
141  for( size_t i = 0; i < sources.size(); ++i ) {
142  auto const bn = utils::file_basename( sources[i]->source_string() );
143  auto const ex = utils::file_extension( bn );
144  auto name = bn;
145  if( ex == "jplace" ) {
146  name = utils::file_filename( bn );
147  }
148 
149  target.add( std::move( tmp[i] ), name );
150  }
151 }
152 
153 // =================================================================================================
154 // Processing
155 // =================================================================================================
156 
157 // -------------------------------------------------------------------------
158 // Get Version
159 // -------------------------------------------------------------------------
160 
161 int JplaceReader::get_jplace_version_( utils::JsonDocument const& doc ) const
162 {
163  // Check if there is a version key.
164  auto v_it = doc.find( "version" );
165  if( v_it == doc.end() ) {
166  return -1;
167  }
168 
169  // Try string and int, return -1 otherwise.
170  int version = -1;
171  assert( v_it != doc.end() );
172  if( v_it->is_string() ) {
173  try {
174  version = std::stoi( v_it->get_string() );
175  } catch(...) {
176  version = -1;
177  }
178  } else if( v_it->is_number_unsigned() ) {
179  version = v_it->get_number_unsigned();
180  }
181  return version;
182 }
183 
184 // -------------------------------------------------------------------------
185 // Processing Version
186 // -------------------------------------------------------------------------
187 
188 void JplaceReader::process_jplace_version_( utils::JsonDocument const& doc ) const
189 {
190  auto const version = get_jplace_version_( doc );
191 
192  // Check if there is a valid version key.
193  if( version == -1 ) {
194  LOG_WARN << "Jplace document does not contain a valid version number at key 'version'. "
195  << "Now continuing to parse in the hope that it still works.";
196  return;
197  }
198 
199  // Check if the version is working for us.
200  if( version == 0 || version >= 4 ) {
201  LOG_WARN << "Jplace document has version " << version << " specified at the 'version' key. "
202  << "We can process versions 1-3 of the jplace standard, "
203  << "but now still continue to parse in the hope that it works.";
204  }
205 }
206 
207 // -------------------------------------------------------------------------
208 // Processing Metadata
209 // -------------------------------------------------------------------------
210 
211 void JplaceReader::process_jplace_metadata_( utils::JsonDocument const& doc, Sample& smp ) const
212 {
213  // Check if there is metadata.
214  auto meta_it = doc.find( "metadata" );
215  if( meta_it != doc.end() && meta_it->is_object() ) {
216  for( auto it = meta_it->begin(); it != meta_it->end(); ++it ) {
217 
218  // Only use metadata that is a string. Everything else is ignored.
219  if( it.value().is_string() ) {
220  smp.metadata[ it.key() ] = it.value().get_string();
221  } else {
222  LOG_WARN << "Jplace document contains meta-data at key '" << it.key()
223  << "' that is not stored as a string, and hence ignored.";
224  }
225  }
226  }
227 }
228 
229 // -------------------------------------------------------------------------
230 // Processing Tree
231 // -------------------------------------------------------------------------
232 
233 void JplaceReader::process_jplace_tree_( utils::JsonDocument const& doc, Sample& smp ) const
234 {
235  // Get the jplace version. Version 1 uses Newick comments in brackets [] for the edge_nums,
236  // while later versions store them in "tags" in curly braces {}.
237  // Prepare the Newick reader accordingly.
238  auto const version = get_jplace_version_( doc );
239  auto reader = PlacementTreeNewickReader();
240  if( version == 1 ) {
241  reader.get_edge_num_from_comments( true );
242  }
243 
244  // Find and process the reference tree.
245  auto tree_it = doc.find( "tree" );
246  if( tree_it == doc.end() || ! tree_it->is_string() ) {
247  throw std::runtime_error(
248  "Jplace document does not contain a valid Newick tree at key 'tree'."
249  );
250  }
251  smp.tree() = reader.read( utils::from_string( tree_it->get_string() ));
252 
253  // The tree reader already does all necessary checks of the tree. No need to repeat them here.
254 }
255 
256 // -------------------------------------------------------------------------
257 // Processing Fields
258 // -------------------------------------------------------------------------
259 
260 std::vector<std::string> JplaceReader::process_jplace_fields_( utils::JsonDocument const& doc ) const
261 {
262  // Basics.
263  auto fields_it = doc.find( "fields" );
264  if( fields_it == doc.end() || ! fields_it->is_array() ) {
265  throw std::runtime_error( "Jplace document does not contain field names at key 'fields'." );
266  }
267 
268  // Store the fields in a vecor in the order that they are specified.
269  std::vector<std::string> fields;
270  for( auto const& fields_val : *fields_it ) {
271  if( ! fields_val.is_string() ) {
272  throw std::runtime_error(
273  "Jplace document contains a value of type '" + fields_val.type_name()
274  + "' instead of a string with a field name at key 'fields'."
275  );
276  }
277 
278  // Check field validity.
279  std::string const& field = fields_val.get_string();
280  if( field == "edge_num" || field == "likelihood" || field == "like_weight_ratio" ||
281  field == "distal_length" || field == "pendant_length" || field == "proximal_length"
282  ) {
283  // These are the fields that we use internally.
284  // Check for duplicates.
285  if( std::any_of( fields.begin(), fields.end(), [&]( std::string const& fn ){
286  return fn == field;
287  })) {
288  throw std::runtime_error(
289  "Jplace document contains field name '" + field
290  + "' more than once at key 'fields'."
291  );
292  }
293  } else if(
294  field == "parsimony" || field == "post_prob" || field == "marginal_like" ||
295  field == "marginal_prob" || field == "classification" || field == "map_ratio" ||
296  field == "map_overlap"
297  ) {
298  // These are fields defined by the jplace standard, but not used by us.
299  LOG_WARN << "Jplace document contains a field name '" << field << "' at key 'fields', "
300  << "which is part of the jplace standard, but not used by any of our functions, "
301  << "and hence ignored.";
302  } else {
303  // These are fields that are not part of the standard.
304  LOG_WARN << "Jplace document contains a field name '" << field << "' at key 'fields', "
305  << "which is not part of the jplace standard, and hence ignored.";
306  }
307  fields.push_back(field);
308  }
309 
310  // Check if all required fields are present. First, the must-haves, and then our little
311  // extra thing of offering to have a proximal_length field instead of of distal_length.
312  std::vector<std::string> required_fields = {
313  "edge_num", "likelihood", "like_weight_ratio", "pendant_length"
314  };
315  for( auto const& req : required_fields ) {
316  if( ! utils::contains( fields, req ) ) {
317  throw std::runtime_error(
318  "Jplace document does not contain necessary field '" + req + "' at key 'fields'."
319  );
320  }
321  }
322  auto const contains_distal = utils::contains( fields, "distal_length" );
323  auto const contains_proximal = utils::contains( fields, "proximal_length" );
324  if( ! contains_distal && ! contains_proximal ) {
325  throw std::runtime_error(
326  "Jplace document does not contain one of the necessary fields 'distal_length' "
327  "or 'proximal_length' at key 'fields'."
328  );
329  }
330  if( contains_distal && contains_proximal ) {
331  LOG_WARN << "Jplace document contains both fields 'distal_length', and 'proximal_length'. "
332  << "Currently, only one value is used internally to represent both, which might "
333  << "lead to inconsistency if the sum of both is not equal to the branch length.";
334  }
335  assert( contains_distal || contains_proximal );
336 
337  return fields;
338 }
339 
340 // -------------------------------------------------------------------------
341 // Processing Placements
342 // -------------------------------------------------------------------------
343 
344 void JplaceReader::process_jplace_placements_(
345  utils::JsonDocument& doc,
346  Sample& smp,
347  std::vector<std::string> const& fields
348 ) const {
349  // Create a map from edge nums to the actual edge pointers, for later use when processing
350  // the pqueries. we do not use Sample::EdgeNumMap() here, because we need to do extra
351  // checking for validity first!
352  std::unordered_map<size_t, PlacementTreeEdge*> edge_num_map;
353  for( auto& edge : smp.tree().edges() ) {
354  auto& edge_data = edge.data<PlacementEdgeData>();
355  if (edge_num_map.count( edge_data.edge_num()) > 0) {
356  throw std::runtime_error(
357  "Jplace document contains a tree where the edge_num tag '"
358  + std::to_string( edge_data.edge_num() ) + "' is used more than once, "
359  "and hence cannot be used to uniquely identify edges of the placements. "
360  "This indicates a severe issue with the program that created the jplace file."
361  );
362  }
363  edge_num_map.emplace( edge_data.edge_num(), &edge );
364  }
365 
366  // Find and process the pqueries.
367  auto place_it = doc.find( "placements" );
368  if( place_it == doc.end() || ! place_it->is_array() ) {
369  throw std::runtime_error(
370  "Jplace document does not contain pqueries at key 'placements'."
371  );
372  }
373  for( auto& pqry_obj : *place_it ) {
374  if( ! pqry_obj.is_object() ) {
375  throw std::runtime_error(
376  "Jplace document contains a value of type '" + pqry_obj.type_name()
377  + "' instead of an object with a pquery at key 'placements'."
378  );
379  }
380 
381  // Create new pquery and fill it with the p, n, m, and nm values.
382  auto pquery = Pquery();
383  process_jplace_placements_p_( pqry_obj, pquery, fields, edge_num_map );
384  process_jplace_placements_nm_( pqry_obj, pquery );
385 
386  // Add the pquery to the smp object, and remove the values from the json doc to save memory.
387  smp.add( pquery );
388  pqry_obj.clear();
389  }
390 }
391 
392 // -------------------------------------------------------------------------
393 // Processing Placements P
394 // -------------------------------------------------------------------------
395 
396 void JplaceReader::process_jplace_placements_p_(
397  utils::JsonDocument const& pqry_obj,
398  Pquery& pquery,
399  std::vector<std::string> const& fields,
400  std::unordered_map<size_t, PlacementTreeEdge*> const& edge_num_map
401 ) const {
402 
403  // Helper function that takes a value and input used to report or fix incorrect input,
404  // depnding on the invalid number behaviour setting.
405  auto invalid_number_checker = [this] (
406  double& actual,
407  std::function<bool (double, double)> comparator,
408  double expected,
409  std::string error_message
410  ) {
411  if(
412  comparator( actual, expected ) && (
415  )) {
416  LOG_WARN << error_message;
417  }
418 
419  if(
420  comparator( actual, expected ) && (
423  )) {
424  actual = expected;
425  }
426 
427  if(
428  comparator( actual, expected ) && (
430  )) {
431  throw std::runtime_error( error_message );
432  }
433  };
434 
435  // Check basic validity.
436  assert( pqry_obj.is_object() );
437  auto const pqry_p_arr = pqry_obj.find( "p" );
438  if( pqry_p_arr == pqry_obj.end() || ! pqry_p_arr->is_array() ) {
439  throw std::runtime_error(
440  "Jplace document contains a pquery at key 'placements' that does not contain an "
441  "array of placements at key 'p'."
442  );
443  }
444  if( pqry_p_arr->size() == 0 ) {
445  throw std::runtime_error(
446  "Jplace document contains a pquery at key 'placements' that does not contain any "
447  "placements at key 'p'."
448  );
449  }
450 
451  // Process the placements and store them in the pquery.
452  for( auto const& pqry_fields : *pqry_p_arr ) {
453  if( ! pqry_fields.is_array() ) {
454  throw std::runtime_error(
455  "Jplace document contains a pquery with invalid placement at key 'p'."
456  );
457  }
458 
459  if( pqry_fields.size() != fields.size() ) {
460  throw std::runtime_error(
461  "Jplace document contains a placement fields array with different size "
462  "than the fields name array."
463  );
464  }
465 
466  // Init a placement and set some distal/proximal lengths temps.
467  auto pqry_place = PqueryPlacement();
468  double distal_length = -1.0;
469  pqry_place.proximal_length = 0.0;
470 
471  // Process all fields of the placement.
472  for( size_t i = 0; i < pqry_fields.size(); ++i ) {
473 
474  // Switch on the field name to set the correct value, and store the target value.
475  // We currently only process number fields, as all values in a PqueryPlacement
476  // are of type double. This makes our life here easy.
477  // If we ever decide to also process other values such as strings in the `classification`
478  // field of the jplace standard, the following has to be refactored.
479  double* target = nullptr;
480  if( fields[i] == "edge_num" ) {
481  size_t val_int = pqry_fields.at(i).get_number<size_t>();
482 
483  if( edge_num_map.count( val_int ) == 0 ) {
484  throw std::runtime_error(
485  "Jplace document contains a pquery where field 'edge_num' has value '"
486  + std::to_string( val_int ) + "', which does not correspond to any "
487  "edge_num in the given Newick tree of the document."
488  );
489  }
490  pqry_place.reset_edge( *edge_num_map.at( val_int ) );
491 
492  } else if( fields[i] == "likelihood" ) {
493  target = &pqry_place.likelihood;
494  } else if( fields[i] == "like_weight_ratio" ) {
495  target = &pqry_place.like_weight_ratio;
496  } else if( fields[i] == "distal_length" ) {
497  target = &distal_length;
498  } else if( fields[i] == "proximal_length" ) {
499  target = &pqry_place.proximal_length;
500  } else if( fields[i] == "pendant_length" ) {
501  target = &pqry_place.pendant_length;
502  }
503 
504  // If we set a porper target above, we are at a field that we actually want to process.
505  // Hence, check if it is numercial (again, we currently are only interested in these),
506  // and set it accordingly.
507  if( target ) {
508  if( !pqry_fields.at(i).is_number() ) {
509  throw std::runtime_error(
510  "Jplace document contains a pquery where the field " + fields[i]
511  + " is of type '" + pqry_fields.at(i).type_name()
512  + "' instead of a number."
513  );
514  }
515  *target = pqry_fields.at(i).get_number<double>();
516  }
517  }
518 
519  // The jplace format uses distal length, but we use proximal, so we need to convert here.
520  // We have to do this here (unlike all the other values, which are set in the loop
521  // above), because it may happen that the edge_num field was not yet set while
522  // processing the loop. Also, we only set it if it was actually available in the fields
523  // and not overwritten by the (more appropriate) field for the proximal length.
524  if( distal_length >= 0.0 && pqry_place.proximal_length == 0.0 ) {
525  auto const& edge_data = pqry_place.edge().data<PlacementEdgeData>();
526  pqry_place.proximal_length = edge_data.branch_length - distal_length;
527  }
528 
529  // Check validity of placement values.
530  invalid_number_checker(
531  pqry_place.like_weight_ratio,
532  std::less<double>(),
533  0.0,
534  "Invalid placement with like_weight_ratio < 0.0."
535  );
536  invalid_number_checker(
537  pqry_place.like_weight_ratio,
538  std::greater<double>(),
539  1.0,
540  "Invalid placement with like_weight_ratio > 1.0."
541  );
542  invalid_number_checker(
543  pqry_place.pendant_length,
544  std::less<double>(),
545  0.0,
546  "Invalid placement with pendant_length < 0.0."
547  );
548  invalid_number_checker(
549  pqry_place.proximal_length,
550  std::less<double>(),
551  0.0,
552  "Invalid placement with proximal_length < 0.0."
553  );
554  invalid_number_checker(
555  pqry_place.proximal_length,
556  std::greater<double>(),
557  pqry_place.edge().data<PlacementEdgeData>().branch_length,
558  "Invalid placement with proximal_length > branch_length."
559  );
560 
561  // Add the placement to the query and vice versa.
562  pquery.add_placement( pqry_place );
563  }
564 }
565 
566 // -------------------------------------------------------------------------
567 // Processing Placements P
568 // -------------------------------------------------------------------------
569 
570 void JplaceReader::process_jplace_placements_nm_(
571  utils::JsonDocument const& pqry_obj,
572  Pquery& pquery
573 ) const {
574 
575  // Check name/named multiplicity validity.
576  assert( pqry_obj.is_object() );
577  if( pqry_obj.count("n") > 0 && pqry_obj.count("nm") > 0 ) {
578  throw std::runtime_error(
579  "Jplace document contains a pquery with both an 'n' and an 'nm' key."
580  );
581  }
582  if( pqry_obj.count("n") == 0 && pqry_obj.count("nm") == 0 ) {
583  throw std::runtime_error(
584  "Jplace document contains a pquery with neither an 'n' nor an 'nm' key."
585  );
586  }
587  if( pqry_obj.count("m") > 0 && pqry_obj.count("n") == 0 ) {
588  throw std::runtime_error(
589  "Jplace document contains a pquery with key 'm' but without 'n' key."
590  );
591  }
592 
593  // Process names.
594  if( pqry_obj.count("n") > 0 ) {
595  assert( pqry_obj.count("nm") == 0 );
596 
597  // Get the multiplicity for the name. This is only relevant for the old case of
598  // jplace version 2, which offered an 'm' key for this. If the key is not provided,
599  // we simply use the default multiplicity of 1.
600  double m = 1.0;
601  if( pqry_obj.count("m") > 0 ) {
602 
603  // The 'm' key is expected to be a single float.
604  if( ! pqry_obj[ "m" ].is_number() ) {
605  throw std::runtime_error(
606  "Jplace document contains a pquery where key 'm' has a "
607  "value is not a valid number for the multiplicity."
608  );
609  }
610 
611  // Furthermore, if 'm' is provided, 'n' can only contain a single element,
612  // that is, either be a string, or an array with one string. Both is covered by
613  // the Json Document size() property.
614  if( pqry_obj[ "n" ].size() != 1 ) {
615  throw std::runtime_error(
616  "Jplace document contains a pquery with key 'n' that is an array of size greater "
617  "than one, while also having key 'm' for the multiplicity. This is not allowed."
618  );
619  }
620 
621  // Finally, set the multiplicity to be used for the name.
622  m = pqry_obj[ "m" ].get_number<double>();
623  }
624 
625  // The 'n' key can either be a string or an array containing one string.
626  // Process accordingly.
627  if( pqry_obj[ "n" ].is_array() ) {
628 
629  // Validity check.
630  if( pqry_obj[ "n" ].size() == 0 ) {
631  throw std::runtime_error(
632  "Jplace document contains a pquery with key 'n' that does not contain any values."
633  );
634  }
635 
636  // If we are here, and there is an 'm' key, the array can only have size 1.
637  // We checked this before, so assert it here.
638  assert(!( pqry_obj[ "n" ].size() > 1 && pqry_obj.count("m") > 0 ));
639 
640  // Add all names.
641  for( auto const& pqry_n_val : pqry_obj[ "n" ] ) {
642  if( ! pqry_n_val.is_string() ) {
643  throw std::runtime_error(
644  "Jplace document contains a pquery where key 'n' has a non-string field."
645  );
646  }
647 
648  // Add the name with a default multiplicity.
649  pquery.add_name( pqry_n_val.get_string(), m );
650  }
651 
652  } else if( pqry_obj[ "n" ].is_string() ) {
653  pquery.add_name( pqry_obj[ "n" ].get_string(), m );
654 
655  } else {
656  throw std::runtime_error(
657  "Jplace document contains a pquery with key 'n' that "
658  "is neither an array nor a string."
659  );
660  }
661  }
662 
663  // Process named multiplicities.
664  if( pqry_obj.count("nm") > 0 ) {
665  assert( pqry_obj.count("n") == 0 );
666  assert( pqry_obj.count("m") == 0 );
667 
668  // Validity check.
669  if ( ! pqry_obj[ "nm" ].is_array() ) {
670  throw std::runtime_error(
671  "Jplace document contains a pquery with key 'nm' that is not array."
672  );
673  }
674  if( pqry_obj[ "nm" ].size() == 0 ) {
675  throw std::runtime_error(
676  "Jplace document contains a pquery with key 'nm' that does not contain any values."
677  );
678  }
679 
680  // Add all n/m value pairs to the pquery.
681  for( auto const& pqry_nm_val : pqry_obj[ "nm" ] ) {
682 
683  // Validity checks.
684  if( ! pqry_nm_val.is_array() ) {
685  throw std::runtime_error(
686  "Jplace document contains a pquery where key 'nm' has a non-array field."
687  );
688  }
689  if( pqry_nm_val.size() != 2 ) {
690  throw std::runtime_error(
691  std::string( "Jplace document contains a pquery where key 'nm' has an " )
692  + "array field with size != 2 (one for the name, one for the multiplicity)."
693  );
694  }
695  if( ! pqry_nm_val.at(0).is_string() ) {
696  throw std::runtime_error(
697  std::string( "Jplace document contains a pquery where key 'nm' has an " )
698  + "array whose first value is not a string for the name."
699  );
700  }
701  if( ! pqry_nm_val.at(1).is_number() ) {
702  throw std::runtime_error(
703  std::string( "Jplace document contains a pquery where key 'nm' has an " )
704  + "array whose second value is not a number for the multiplicity."
705  );
706  }
707 
708  // Set the values and create a pquery name.
709  auto pqry_name = PqueryName();
710  pqry_name.name = pqry_nm_val.at(0).get_string();
711  pqry_name.multiplicity = pqry_nm_val.at(1).get_number<double>();
712  if (pqry_name.multiplicity < 0.0) {
713  LOG_WARN << "Jplace document contains pquery with negative multiplicity at "
714  << "name '" << pqry_name.name << "'.";
715  }
716 
717  // Add the name to the pquery.
718  pquery.add_name( pqry_name );
719  }
720  }
721 }
722 
723 } // namespace placement
724 } // namespace genesis
Provides some valuable algorithms that are not part of the C++ 11 STL.
std::string file_extension(std::string const &filename)
Return the extension name of a file.
Definition: fs.cpp:707
Data class for PlacementTreeEdges. Stores the branch length of the edge, and the edge_num, as defined in the jplace standard.
void clear()
Clear all data stored in this Pquery, i.e., clear all PqueryNames and all PqueryPlacements.
Definition: pquery.cpp:43
PlacementTree & tree()
Get the PlacementTree of this Sample.
Definition: sample.cpp:119
Read Json data into a JsonDocument.
A pquery holds a set of PqueryPlacements and a set of PqueryNames.
Definition: pquery.hpp:82
InvalidNumberBehaviour invalid_number_behaviour() const
Return the currenlty set InvalidNumberBehaviour.
#define LOG_WARN
Log a warning. See genesis::utils::LoggingLevel.
Definition: logging.hpp:96
PqueryName & add_name(std::string name="", double multiplicity=1.0)
Create a new PqueryName using the provided parameters, add it to the Pquery and return it...
Definition: pquery.cpp:181
One placement position of a Pquery on a Tree.
Throw an std::runtime_error when encountering an invalid number.
std::string file_filename(std::string const &filename)
Remove extension if present.
Definition: fs.cpp:696
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
Provides some valuable additions to STD.
A name of a Pquery and its multiplicity.
Definition: name.hpp:55
bool contains(const C &v, const T &x)
Returns whether a container object has a certain element.
Definition: algorithm.hpp:74
bool is_object() const
Return true iff the JSON value is an object.
std::string file_basename(std::string const &filename)
Remove directory name from file name if present.
Definition: fs.cpp:685
void add(Sample const &smp, std::string const &name="")
Add a Sample with a name to the SampleSet.
Definition: sample_set.hpp:94
Fix invalid numbers to the next best correct number.
std::unordered_map< std::string, std::string > metadata
Definition: sample.hpp:291
PqueryPlacement & add_placement(PlacementTreeEdge &edge)
Create a new PqueryPlacement at a given PlacementTreeEdge, add it to the Pquery and return it...
Definition: pquery.cpp:92
Store a set of Samples with associated names.
Definition: sample_set.hpp:54
utils::Range< IteratorEdges > edges()
Definition: tree/tree.hpp:452
size_type count(typename ObjectType::key_type key) const
Return the number of occurrences of a key in a JSON object.
Provides some commonly used string utility functions.
Provides functions for accessing the file system.
iterator find(typename JsonDocument::ObjectType::key_type key)
Find an element in a JSON object.
Provides easy and fast logging functionality.
iterator end()
Return an iterator to one past the last element.
double branch_length
Branch length of the edge.
Store a Json value of any kind.
JsonDocument read(std::shared_ptr< BaseInputSource > source) const
Read from a source containing a JSON document and parse its contents into a JsonDocument.
Manage a set of Pqueries along with the PlacementTree where the PqueryPlacements are placed on...
Definition: sample.hpp:68
std::shared_ptr< BaseOutputTarget > to_string(std::string &target_string)
Obtain an output target for writing to a string.
Sample read(std::shared_ptr< utils::BaseInputSource > source) const
Read from an input source.
Pquery & add()
Create an empty Pquery, add it to the Sample and return it.
Definition: sample.cpp:147
std::shared_ptr< BaseInputSource > from_string(std::string const &input_string)
Obtain an input source for reading from a string.