63 double const scaler_lhs,
64 double const scaler_rhs
74 double const scaler_lhs,
75 double const scaler_rhs
79 throw std::runtime_error(
"Incompatible MassTrees for merging." );
83 if( scaler_lhs != 1.0 ) {
87 #pragma omp parallel for
88 for(
size_t i = 0; i < lhs.
edge_count(); ++i ) {
91 lhs_masses[ rhs_mass.first ] += scaler_rhs * rhs_mass.second;
98 #pragma omp parallel for
99 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
106 #pragma omp parallel for
107 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
109 for(
auto& mass : masses ) {
110 mass.second = -mass.second;
117 #pragma omp parallel for
118 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
120 for(
auto& mass : masses ) {
121 mass.second *= factor;
130 if( total_mass == 0.0 ) {
134 #pragma omp parallel for
135 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
137 mass.second /= total_mass;
144 #pragma omp parallel for
145 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
147 std::map<double, double> relative;
149 for(
auto& mass : edge_data.masses ) {
150 relative[ mass.first / edge_data.branch_length ] += mass.second;
153 edge_data.
masses = relative;
154 edge_data.branch_length = 1.0;
162 #pragma omp parallel for
163 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
167 double central_mass = 0.0;
169 for(
auto const& mass : edge_data.masses ) {
171 work += mass.second * std::abs( branch_center - mass.first );
172 central_mass += mass.second;
175 edge_data.masses.clear();
176 edge_data.masses[ branch_center ] = central_mass;
185 #pragma omp parallel for
186 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
192 if( edge_data.masses.empty() ) {
196 double mass_center = 0.0;
197 double mass_sum = 0.0;
201 for(
auto const& mass : edge_data.masses ) {
202 mass_center += mass.first * mass.second;
203 mass_sum += mass.second;
207 mass_center /= mass_sum;
210 for(
auto const& mass : edge_data.masses ) {
212 work += mass.second * std::abs( mass_center - mass.first );
216 edge_data.masses.clear();
217 edge_data.masses[ mass_center ] = mass_sum;
224 if( number_of_bins == 0 ) {
225 throw std::invalid_argument(
"Cannot use number_of_bins == 0." );
231 auto get_bin_pos = [ number_of_bins ](
double pos,
double bl )
233 auto const nb =
static_cast<double>( number_of_bins );
236 auto const pn = std::min( std::max( 0.0, pos / bl * nb ), std::nextafter( nb, 0.0 ));
240 return ( std::floor( pn ) * bl / nb ) + ( bl / nb / 2.0 );
245 #pragma omp parallel for
246 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
250 auto new_masses = std::map<double, double>();
253 for(
auto const& mass : edge_data.masses ) {
254 auto const bin = get_bin_pos( mass.first, edge_data.branch_length );
256 work += mass.second * std::abs( bin - mass.first );
257 new_masses[ bin ] += mass.second;
261 edge_data.
masses = new_masses;
274 if( mass_trees.size() < 2 ) {
279 size_t const num_edges = mass_trees[0].edge_count();
280 auto avg_br_lens = std::vector<double>( num_edges, 0.0 );
283 for(
auto const& tree : mass_trees ) {
286 if( tree.edge_count() != num_edges ) {
287 throw std::runtime_error(
288 "Cannot make average branch lengths, because trees have different size."
293 assert( avg_br_lens.size() == tree.edge_count() );
294 for(
size_t edge_idx = 0; edge_idx < num_edges; ++edge_idx ) {
295 avg_br_lens[edge_idx] += tree.edge_at( edge_idx ).data<
MassTreeEdgeData>().branch_length;
300 for(
auto& ae : avg_br_lens ) {
301 ae /=
static_cast<double>( mass_trees.size() );
305 for(
auto& tree : mass_trees ) {
307 #pragma omp parallel for
308 for(
size_t edge_idx = 0; edge_idx < tree.edge_count(); ++edge_idx ) {
312 auto new_masses = std::map<double, double>();
315 assert( std::isfinite( avg_br_lens[ edge_idx ] ));
316 assert( std::isfinite( edge_data.branch_length ));
317 auto scaler = avg_br_lens[ edge_idx ] / edge_data.branch_length;
318 if( ! std::isfinite( scaler )) {
319 assert( edge_data.branch_length == 0.0 );
324 for(
auto const& mass : edge_data.masses ) {
326 auto const new_pos = mass.first * scaler;
327 new_masses[ new_pos ] += mass.second;
331 edge_data.
masses = new_masses;
339 auto result = std::vector<double>( tree.
edge_count(), 0.0 );
341 #pragma omp parallel for
342 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
343 auto const& edge = tree.
edge_at(i);
344 assert( i == edge.index() );
358 if( mass_trees.empty() || mass_trees[0].empty() ) {
364 #pragma omp parallel for
365 for(
size_t i = 0; i < mass_trees.size(); ++i ) {
366 if( mass_trees[i].
edge_count() != result.cols() ) {
367 throw std::runtime_error(
368 "Cannot calculate masses per edge for a Tree set with Trees "
369 "with unequal edge count."
382 auto result = std::vector<std::pair<double, double>>( tree.
edge_count(), { 0.0, 0.0 });
384 #pragma omp parallel for
385 for(
size_t i = 0; i < tree.
edge_count(); ++i ) {
386 auto const& edge = tree.
edge_at(i);
390 if( edge_data.masses.empty() ) {
395 double mass_pos = 0.0;
396 double mass_sum = 0.0;
397 for(
auto const& mass : edge_data.masses ) {
398 mass_pos += mass.first * mass.second;
399 mass_sum += mass.second;
403 mass_pos /= mass_sum;
405 result[ edge.index() ].first = mass_pos;
406 result[ edge.index() ].second = mass_sum;
414 double total_mass = 0.0;
415 for(
auto const& edge : tree.
edges() ) {
417 total_mass += mass.second;
427 LOG_INFO <<
"Invalid Tree topology.";
430 if( ! tree_data_is< MassTreeNodeData, MassTreeEdgeData >( tree )) {
431 LOG_INFO <<
"Tree does not only contain Mass Node and Edge data types.";
436 double mass_sum = 0.0;
437 for(
auto const& edge : tree.
edges() ) {
438 auto const edge_data =
dynamic_cast< MassTreeEdgeData const*
>( edge.data_ptr() );
439 if( edge_data ==
nullptr ) {
440 LOG_INFO <<
"Edge data type is not 'MassTreeEdgeData'.";
444 for(
auto const& mass : edge_data->masses ) {
445 if( mass.first < 0.0 ) {
446 LOG_INFO <<
"Mass with branch position < 0.0";
449 if( mass.first > edge_data->branch_length ) {
450 LOG_INFO <<
"Mass with branch position > branch_length";
454 mass_sum += mass.second;
458 if( valid_total_mass_difference >= 0.0 && std::abs(mass_sum) > valid_total_mass_difference ) {
459 LOG_INFO <<
"Total mass difference " << mass_sum
460 <<
" is higher than " << valid_total_mass_difference;