void Chart::calculateRates (std::vector <time_t>& sequence) { // If there are no current pending tasks, then it is meaningless to find // rates or estimated completion date. if (bars[sequence.back ()].pending == 0) return; // Calculate how many items we have. int quantity = (int) sequence.size (); int half = quantity / 2; int quarter = quantity / 4; // If the half and quarter indexes match, then there are too few data points // to generate any meaningful rates. if (half == quantity || half == 0 || quarter == 0) { context.debug ("Chart::calculateRates Insufficient data for rate calc"); return; } // How many days do these sums represent? int half_days = 1; int quarter_days = 1; switch (period) { case 'D': half_days = half; quarter_days = quarter; break; case 'W': half_days = half * 7; quarter_days = quarter * 7; break; case 'M': half_days = half * 30; quarter_days = quarter * 30; break; } int total_added_50 = 0; int total_added_75 = 0; int total_removed_50 = 0; int total_removed_75 = 0; for (unsigned int i = half; i < sequence.size (); ++i) { total_added_50 += bars[sequence[i]].added; total_removed_50 += bars[sequence[i]].removed; } for (unsigned int i = half + quarter; i < sequence.size (); ++i) { total_added_75 += bars[sequence[i]].added; total_removed_75 += bars[sequence[i]].removed; } float find_rate_50 = 1.0 * total_added_50 / half_days; float find_rate_75 = 1.0 * total_added_75 / quarter_days; float fix_rate_50 = 1.0 * total_removed_50 / half_days; float fix_rate_75 = 1.0 * total_removed_75 / quarter_days; // Make configurable. float bias = (float) context.config.getReal ("burndown.bias"); find_rate = (find_rate_50 * (1.0 - bias) + find_rate_75 * bias); fix_rate = (fix_rate_50 * (1.0 - bias) + fix_rate_75 * bias); // Q: Why is this equation written out as a debug message? // A: People are going to want to know how the rates and the completion date // are calculated. This may also help debugging. std::stringstream rates; rates << "Chart::calculateRates find rate: " << "(" << total_added_50 << " added / " << half_days << " days) * (1.0 - " << bias << ") + (" << total_added_75 << " added / " << quarter_days << " days) * " << bias << ") = " << find_rate << "\nChart::calculateRates fix rate: " << "(" << total_removed_50 << " removed / " << half_days << " days) * (1.0 - " << bias << ") + (" << total_removed_75 << " added / " << quarter_days << " days) * " << bias << ") = " << fix_rate; context.debug (rates.str ()); // Estimate completion if (fix_rate > find_rate) { int current_pending = bars[sequence.back ()].pending; int remaining_days = (int) (current_pending / (fix_rate - find_rate)); Date now; Duration delta (remaining_days * 86400); now += delta; completion = now.toString (context.config.get ("dateformat")) + " (" + delta.format () + ")"; std::stringstream est; est << "Chart::calculateRates Completion: " << current_pending << " tasks / (" << fix_rate << " - " << find_rate << ") = " << remaining_days << " days = " << completion; context.debug (est.str ()); } else { completion = STRING_CMD_BURN_NO_CONVERGE; } }