Analysis: Addressing the RW 6.6 Unit Conversion Method Design Deficiency
Phil, 3-26-2015

In the course of addressing a problem with the Time Aggregation Series Slot (Gnats 5614*), it became apparent that we are not correctly converting standard flow values within an annual series to a "per month" unit. Furthermore, our convention of supplying the unit conversion methods with a timestep Date_Time to accomodate irreguilar time units isn't actually sufficient for this particular case. What we really need instead is the number of seconds in the timestep for which the unit conversion is being done. This is needed only when that timestep has irregular time units. This is the only use of Date_Times in the unit conversion methods.

*See the 5614 gnats record, and an image from yesterday's status update:

     

This diagram illustrates the calling relationship between the general unit converion methods. These are in UnitMgr and SlotGUIUtils.

http://cadswes2.colorado.edu/~philw/2015/UnitConvert/UnitMgrConversionMethods.png

The Date_Time value currently being presented to these methods is ultimately used in only the lowest level private method, UnitMgr::doConversion(). See the implementation of that method, here:

The problem can be seen in use of the Date_Time ("when") in this stanzas. (There are four such stanzas in this method):

if (toUnitDef->isPerMonth() && whenIsValid &&
    (daysIn = when.daysInMonth()) != 31)
{
   coeffFromStd *= double(daysIn) / double(31);
}

The hard-coded factor in per-month assume a month of 31 days (and per-year units assume a year of 365 days). Adjustments to those factors need to be made if the month or year for which the conversion is being made is of a different length.

This logically needs to be recoded as something like this:

if (toUnitDef->isPerMonth()
{
   if ( ( <context timestep logical size> <= <monthly> ) &&
        ( <context timestep actual size> != 31 Days)     )
   {
      coeffFromStd *= <context timestep month days> / double(31);
   }
   else if ( <context timestep logical size> == <annual> ) &&
   {
      coeffFromStd *= <context timestep year average month days> / double(31);
   }
}

In the cases of converting to or from irregular time units, we need the following two pieces of information:

  1. The logical size of the series timestep (e.g. a DeltaTime indicating One Month or One Year).
  2. The actual size of that timestep, in seconds.

The latter could either be directly provided (in which case, a Date_Time would not be needed) -- OR could be computed from the provided Date_Time and the first item, using this Date_Time method:

In progress ... I'm still working on devising a specific recommendation for specific changes to the conversion method parameters, with an eye towards keeping application-level changes to a minimum. [Phil, 3-26-2015].

--- (end) ---