I thought I'd re-post to the ticketing system from my blog. I thought I might have found a bug the way bcwp was calculated. But I could be wrong, perhaps I misunderstood the intention of the code.
Are there different ways to calculate BCWP?
ProjectLibre, v 1.5, calculates it the following way:
:::java
//[(Actual % of completion / Expected % of completion) of an activity for a given period] * Actual cost of activity
public double bcwp(long start, long end) {
if (!isInRange(start,end))
return NO_VALUE_DOUBLE;
end = Math.min(end,getStatusDate());
if (end == 0)
return 0.0D;
if (AdvancedOption.getInstance().isEarnedValueFieldsCumulative())
start = getStart(); // start from the beginning of the task and ignore the range start
double cost = actualCost(start,end);
if (cost == 0)
return 0;
return efficiency() * cost;
}
When I saw this, my reaction was "Why would the actual cost be part of BCWP?". Wikipedia defines BCWP, as I learned in class, as BAC * % complete.
Now its possible that I'm misinterpreting the function actualCost. When programming, variable names can be confounded with their actual meaning as the code gets bigger and bigger
But when I set % complete to 100% for a task that was due to finish in the future, my SPI is still set to 1. My understanding is that it should be higher than 1. I talk more about this in the projectlibre community forum: http://www.projectlibre.org/discussion/how-bcwp-calculated
So, while acknowledging I could be misunderstanding the output and intent of the code, here's what I think it should be:
:::java
// bac * percent complete -- cyclingzealot
// Changed from:
//[(Actual % of completion / Expected % of completion) of an activity for a given period] * Actual cost of activity
public double bcwp(long start, long end) {
if (!isInRange(start,end))
return NO_VALUE_DOUBLE;
end = Math.min(end,getStatusDate());
if (end == 0)
return 0.0D;
if (AdvancedOption.getInstance().isEarnedValueFieldsCumulative())
start = getStart(); // start from the beginning of the task and ignore the range start
double bac = bac(0,DateTime.getMaxDate().getTime());
double percentComplete = this.getPercentComplete();
if (bac == 0)
return 0;
return percentComplete * bac;
}
Again, totally possible I misunderstood the code. One thing I noticed is that start and end is used in the former calculation, whereas I'll get the bac from 0 to end. Its possible that the former code has use in calculating earned value through time.