Ignore:
Timestamp:
02/10/15 14:23:02 (9 years ago)
Author:
rlacroix
Message:

Add a new user defined calendar type.

A new calendar type "user_defined" is now available. This allows the users to create a custom calendar that we can configured to be suitable for planets other than the Earth.

An user defined calendar is always defined by two mandatory attributes:

  • day_length: the duration of a day, in seconds
  • and either:
    • month_length: an array containing the duration of each month, in days (the number of elements in the array is the number of months in a year)
    • or year_length: the duration of a year, in seconds (in that case, the calendar does not have months).

If the calendar has months (i.e. month_length attribute is set) and only in that case, it is possible to define leap years in order to compensate for the duration of an astronomical year not being a multiple of the day length. The leap years are defined by two mandatory attributes:

  • leap_year_month: the month to which the extra day will be added in case of leap year, expressed as an integer number in the range [1, numberOfMonths]
  • and leap_year_drift: the fraction of a day representing the yearly drift between the calendar year and the astronomical year, expressed as a real number in the range [0, 1).

Optionally, one can define the leap_year_drift_offset attribute to set the original drift at the beginning of the time origin's year, again expressed as a real number in the range [0, 1). If leap_year_drift_offset + leap_year_drift is greater or equal to 1, then the first year will be a leap year.

For example, the following configuration creates a Gregorian-like calendar:

<calendar type="user_defined" start_date="2012-03-01 15:00:00" time_origin="2012-02-28 15:00:00 + 1d" day_length="86400" month_lengths="(1, 12) [31 28 31 30 31 30 31 31 30 31 30 31]" leap_year_month="2" leap_year_drift="0.25" leap_year_drift_offset="0.75" />

Note that dates attributes must be written differently in the configuration file when using an user defined calendar without months:

  • if the year length is greater than the day length, the input format is year-day hh:min:sec instead of year-month-day hh:min:sec
  • if the day length is greater or equal to the year length, the input format is year hh:min:sec.

In all cases, it is still possible to use the date + duration notation to build a date (with both the date and duration parts being optional).

The Fortran interface has been updated accordingly so that xios_define_calendar can accept the new attributes necessary to define custom calendars.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • XIOS/trunk/src/date.cpp

    r549 r550  
    8787      } 
    8888 
    89       StdIStream& operator>>(StdIStream& in, CDate& date) // Non testée. 
    90       { 
    91         char sep = '-'; // Le caractÚre c est utilisé pour "recueillir" les séparateurs "/" et ":". 
    92         char c; 
    93  
    94         // Default initialize the date 
    95         date.year = 0; 
    96         date.month = 1; 
    97         date.day = 1; 
    98         date.hour = 0; 
    99         date.minute = 0; 
    100         date.second = 0; 
    101  
    102         in >> date.year >> c; 
    103         if (c == sep) 
    104         { 
    105           in >> date.month >> c; 
    106           if (c == sep) 
    107           { 
    108             in >> date.day; 
    109             c = in.get(); 
    110             sep = ' '; 
    111             if (c == sep) 
    112             { 
    113               in >> date.hour >> c; 
    114               sep = ':'; 
    115               if (c == sep) 
    116               { 
    117                 in>>date.minute >> c; 
    118                 if (c == sep) 
    119                 { 
    120                   in >> date.second; 
    121                   in >> c; 
    122                 } 
    123               } 
    124             } 
    125           } 
    126         } 
    127  
    128         // Delay the verification until we get a calendar we can compare the date to 
    129         if (date.relCalendar && !date.checkDate()) 
    130           ERROR("StdIStream& operator >> (StdIStream& in, CDate& date)", 
    131                 << "Bad date format or not conform to calendar"); 
    132  
    133         if (c == '+') // We will be adding a duration to the date 
    134         { 
    135           CDuration dur; 
    136           in >> dur; 
    137           date = date + dur; 
    138         } 
    139         else if (!in.eof()) 
    140           ERROR("StdIStream& operator >> (StdIStream& in, CDate& date)", 
    141                 << "Invalid date format: unexpected trailing character(s)"); 
     89      StdIStream& operator>>(StdIStream& in, CDate& date) 
     90      { 
     91        if (date.relCalendar) 
     92          date.relCalendar->parseDate(in, date); 
     93        else 
     94          CCalendar::parseDateDefault(in, date); 
    14295 
    14396        return in; 
     
    152105        Time retvalue = getSecondOfYear() - c.getTimeOrigin().getSecondOfYear(); 
    153106 
    154         if ((c.getId().compare("D360")    == 0) || 
    155             (c.getId().compare("AllLeap") == 0) || 
    156             (c.getId().compare("NoLeap")  == 0)) 
    157         return (retvalue + (getYear() - c.getTimeOrigin().getYear()) 
    158                                       * c.getYearTotalLength(*this)); 
    159  
    160         for (CDate _d(c.getTimeOrigin()); _d.getYear() < getYear(); _d.setYear(_d.getYear() + 1)) 
    161            retvalue += c.getYearTotalLength(_d); 
     107        if (c.hasLeapYear()) 
     108        { 
     109          for (CDate _d(c.getTimeOrigin()); _d.getYear() < getYear(); _d.setYear(_d.getYear() + 1)) 
     110            retvalue += c.getYearTotalLength(_d); 
     111        } 
     112        else 
     113          retvalue += (getYear() - c.getTimeOrigin().getYear()) * c.getYearTotalLength(*this); 
     114 
    162115 
    163116        return retvalue; 
     
    168121      bool CDate::checkDate(void) 
    169122      { 
    170         bool retValue = true; 
    171  
    172         // This will check that a calendar was correctly associated to the date 
    173         const CCalendar& c = getRelCalendar(); 
    174  
    175         // Vérification de la valeur du mois. 
    176         if (month  < 1) { retValue = false; month  = 1; } 
    177         if (month  > c.getYearLength()) 
    178         { retValue = false; month = c.getYearLength(); } 
    179  
    180         // Vérification de la valeur du jour. 
    181         if (day    < 1) { retValue = false; day  = 1; } 
    182         if (day    > c.getMonthLength(*this)) 
    183         { retValue = false; day = c.getMonthLength(*this); } 
    184  
    185         // Vérification de la valeur de l'heure. 
    186         if (hour   < 0) { retValue = false; hour  = 0; } 
    187         if (hour   >= c.getDayLength()) 
    188         { retValue = false; hour = c.getDayLength() - 1; } 
    189  
    190         // Vérification de la valeur des minutes. 
    191         if (minute < 0) { retValue = false; minute = 0; } 
    192         if (minute >= c.getHourLength()) 
    193         { retValue = false; minute = c.getHourLength() - 1; } 
    194  
    195         // Vérification de la valeur des secondes. 
    196         if (second < 0) { retValue = false; second = 0; } 
    197         if (second >= c.getMinuteLength()) 
    198         { retValue = false; second = c.getMinuteLength() - 1; } 
    199  
    200         return retValue; 
     123        // This will also check that a calendar was correctly associated to the date 
     124        return getRelCalendar().checkDate(*this); 
    201125      } 
    202126 
     
    238162          nbDay += c.getMonthLength(yearStart); 
    239163 
    240         return ((((nbDay + getDay() - 1) * c.getDayLength() + getHour()) * c.getHourLength() 
    241                    + getMinute()) * c.getMinuteLength() + getSecond()); 
     164        // We need to use getDayLengthInSeconds instead of getDayLength since we might 
     165        // have a non-integral number of hours per day for user defined calendars 
     166        return ((nbDay + getDay() - 1) * c.getDayLengthInSeconds() 
     167                  + (getHour() * c.getHourLength() + getMinute()) * c.getMinuteLength() + getSecond()); 
    242168      } 
    243169 
Note: See TracChangeset for help on using the changeset viewer.