1
by hhiester
deleting initialisation as none of tools are used any longer. |
1 |
/* Copyright (C) 2006 Imperial College London and others.
|
2 |
|
|
3 |
Please see the AUTHORS file in the main source directory for a full list
|
|
4 |
of copyright holders.
|
|
5 |
||
6 |
Dr Gerard Gorman
|
|
7 |
Applied Modelling and Computation Group
|
|
8 |
Department of Earth Science and Engineering
|
|
9 |
Imperial College London
|
|
10 |
||
11 |
g.gorman@imperial.ac.uk
|
|
12 |
|
|
13 |
This library is free software; you can redistribute it and/or
|
|
14 |
modify it under the terms of the GNU Lesser General Public
|
|
15 |
License as published by the Free Software Foundation,
|
|
16 |
version 2.1 of the License.
|
|
17 |
||
18 |
This library is distributed in the hope that it will be useful,
|
|
19 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
21 |
Lesser General Public License for more details.
|
|
22 |
||
23 |
You should have received a copy of the GNU Lesser General Public
|
|
24 |
License along with this library; if not, write to the Free Software
|
|
25 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
26 |
USA
|
|
27 |
*/
|
|
28 |
#ifndef CALENDAR_H
|
|
29 |
#define CALENDAR_H
|
|
30 |
||
31 |
#include "confdefs.h" |
|
32 |
||
33 |
#include "c++debug.h" |
|
34 |
||
35 |
#include <cassert> |
|
36 |
#include <iostream> |
|
37 |
#include <string> |
|
38 |
||
39 |
#ifdef HAVE_LIBUDUNITS
|
|
40 |
extern "C"{ |
|
41 |
#include <udunits.h> |
|
42 |
// The udunits people forgot to include this in their header file
|
|
43 |
// int utIsInit();
|
|
44 |
extern int utIsInit PROTO(()); |
|
45 |
}
|
|
46 |
#endif
|
|
47 |
#include <stdlib.h> |
|
48 |
||
49 |
/* Adapted from the NetCDF CF-convention
|
|
50 |
In order to calculate a new date and time given a base date, base
|
|
51 |
time and a time increment one must know what calendar to use. For
|
|
52 |
this purpose NetCDF CF-conventions recommend that the calendar be
|
|
53 |
specified by the NetCDF attribute calendar which is assigned to
|
|
54 |
the time coordinate variable. The values currently defined for
|
|
55 |
calendar are:
|
|
56 |
||
57 |
gregorian or standard: Mixed Gregorian/Julian calendar as defined
|
|
58 |
by Udunits. This is the default.
|
|
59 |
||
60 |
proleptic_gregorian: A Gregorian calendar extended to dates
|
|
61 |
before 1582-10-15. That is, a year is a leap year if either (i)
|
|
62 |
it is divisible by 4 but not by 100 or (ii) it is divisible by
|
|
63 |
400.
|
|
64 |
||
65 |
noleap or 365_day: Gregorian calendar without leap years, i.e.,
|
|
66 |
all years are 365 days long.
|
|
67 |
||
68 |
all_leap or 366_day: Gregorian calendar with every year being a
|
|
69 |
leap year, i.e., all years are 366 days long.
|
|
70 |
||
71 |
360_day: All years are 360 days divided into 30 day months.
|
|
72 |
||
73 |
julian: Julian calendar.
|
|
74 |
||
75 |
none: No calendar.
|
|
76 |
||
77 |
The calendar attribute may be set to none in climate experiments
|
|
78 |
that simulate a fixed time of year. The time of year is indicated
|
|
79 |
by the date in the reference time of the units attribute. The
|
|
80 |
time coordinate that might apply in a perpetual July experiment
|
|
81 |
are given in the following example.
|
|
82 |
||
83 |
Example 4.5. Perpetual time axis
|
|
84 |
|
|
85 |
variables:
|
|
86 |
double time(time) ;
|
|
87 |
time:long_name = "time" ;
|
|
88 |
time:units = "days since 1-7-15 0:0:0" ;
|
|
89 |
time:calendar = "none" ;
|
|
90 |
data:
|
|
91 |
time = 0., 1., 2., ...;
|
|
92 |
|
|
93 |
||
94 |
||
95 |
Here, all days simulate the conditions of 15th July, so it does
|
|
96 |
not make sense to give them different dates. The time coordinates
|
|
97 |
are interpreted as 0, 1, 2, etc. days since the start of the
|
|
98 |
experiment.
|
|
99 |
||
100 |
If none of the calendars defined above applies (e.g., calendars
|
|
101 |
appropriate to a different paleoclimate era), a non-standard
|
|
102 |
calendar can be defined. The lengths of each month are explicitly
|
|
103 |
defined with the month_lengths attribute of the time axis:
|
|
104 |
||
105 |
month_lengths: A vector of size 12, specifying the number of days
|
|
106 |
in the months from January to December (in a non-leap year).
|
|
107 |
||
108 |
leap_year: If leap years are included, then two other attributes
|
|
109 |
of the time axis should also be defined:
|
|
110 |
||
111 |
leap_month: An example of a leap year. It is assumed that all
|
|
112 |
years that differ from this year by a multiple of four are also
|
|
113 |
leap years. If this attribute is absent, it is assumed there are
|
|
114 |
no leap years.
|
|
115 |
||
116 |
||
117 |
A value in the range 1-12, specifying which month is lengthened
|
|
118 |
by a day in leap years (1=January). If this attribute is not
|
|
119 |
present, February (2) is assumed. This attribute is ignored if
|
|
120 |
leap_year is not specified.
|
|
121 |
||
122 |
The calendar attribute is not required when a non-standard
|
|
123 |
calendar is being used. It is sufficient to define the calendar
|
|
124 |
using the month_lengths attribute, along with leap_year, and
|
|
125 |
leap_month as appropriate. However, the calendar attribute is
|
|
126 |
allowed to take non-standard values and in that case defining the
|
|
127 |
non-standard calendar using the appropriate attributes is
|
|
128 |
required.
|
|
129 |
||
130 |
Example 4.6. Paleoclimate time axis
|
|
131 |
||
132 |
double time(time) ;
|
|
133 |
time:long_name = "time" ;
|
|
134 |
time:units = "days since 1-1-1 0:0:0" ;
|
|
135 |
time:calendar = "126 kyr B.P." ;
|
|
136 |
time:month_lengths = 34, 31, 32, 30, 29, 27, 28, 28, 28, 32, 32, 34 ;
|
|
137 |
|
|
138 |
The mixed Gregorian/Julian calendar used by Udunits is explained
|
|
139 |
in the following excerpt from the udunits(3) man page:
|
|
140 |
||
141 |
The udunits(3) package uses a mixed Gregorian/Julian calen-
|
|
142 |
dar system. Dates prior to 1582-10-15 are assumed to use
|
|
143 |
the Julian calendar, which was introduced by Julius Caesar
|
|
144 |
in 46 BCE and is based on a year that is exactly 365.25 days
|
|
145 |
long. Dates on and after 1582-10-15 are assumed to use the
|
|
146 |
Gregorian calendar, which was introduced on that date and is
|
|
147 |
based on a year that is exactly 365.2425 days long. (A year
|
|
148 |
is actually approximately 365.242198781 days long.) Seem-
|
|
149 |
ingly strange behavior of the udunits(3) package can result
|
|
150 |
if a user-given time interval includes the changeover date.
|
|
151 |
For example, utCalendar() and utInvCalendar() can be used to
|
|
152 |
show that 1582-10-15 *preceded* 1582-10-14 by 9 days.
|
|
153 |
|
|
154 |
|
|
155 |
Due to problems caused by the discontinuity in the default mixed
|
|
156 |
Gregorian/Julian calendar, we strongly recommend that this
|
|
157 |
calendar should only be used when the time coordinate does not
|
|
158 |
cross the discontinuity. For time coordinates that do cross the
|
|
159 |
discontinuity the proleptic_gregorian calendar should be used
|
|
160 |
instead.
|
|
161 |
*/
|
|
162 |
||
163 |
class Calendar{ |
|
164 |
// This class aims to implement calander tools to conform to NetCDF
|
|
165 |
// Climate and Forecast (CF) Metadata Conventions.
|
|
166 |
//
|
|
167 |
// http://www.cgd.ucar.edu/cms/eaton/cf-metadata/CF-1.0.html
|
|
168 |
public: |
|
169 |
Calendar(); |
|
170 |
Calendar(const Calendar&); |
|
171 |
const Calendar& operator=(const Calendar &); |
|
172 |
||
173 |
~Calendar(); |
|
174 |
||
175 |
int Convert(double from_value, double& to_value); |
|
176 |
int SetTransformation(std::string from_unit, std::string to_unit, std::string calendar); |
|
177 |
||
178 |
private: |
|
179 |
#ifdef HAVE_LIBUDUNITS
|
|
180 |
utUnit from_unit, to_unit; |
|
181 |
#endif
|
|
182 |
bool have_units; |
|
183 |
double slope, intercept; |
|
184 |
std::string calendar; |
|
185 |
};
|
|
186 |
#endif
|