1 /*
2   This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.
3 
4   Author: Uwe Schulzweida
5 
6 */
7 
8 #include <cdi.h>
9 
10 #include "process_int.h"
11 #include "util_string.h"
12 #include "cdo_options.h"
13 
14 void *
Deltime(void * process)15 Deltime(void *process)
16 {
17   bool copytimestep;
18   int year, month, day;
19   int dday, dmon;
20   const char *cmons[] = { "", "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
21 
22   cdo_initialize(process);
23 
24   const auto dataIsUnchanged = data_is_unchanged();
25 
26   // clang-format off
27   const auto DELDAY   = cdo_operator_add("delday",   0, 0, nullptr);
28   const auto DEL29FEB = cdo_operator_add("del29feb", 0, 0, nullptr);
29   // clang-format on
30 
31   (void) (DELDAY);  // CDO_UNUSED
32 
33   const auto operatorID = cdo_operator_id();
34 
35   if (operatorID == DEL29FEB)
36     {
37       dday = 29;
38       dmon = 2;
39       operator_check_argc(0);
40     }
41   else
42     {
43       int nsel = cdo_operator_argc();
44       if (nsel < 1) cdo_abort("Too few arguments!");
45       if (nsel > 1) cdo_abort("Too many arguments!");
46       const char *sarg = cdo_operator_argv(0).c_str();
47       dday = atoi(sarg);
48       dmon = 0;
49       while (isdigit(*sarg)) sarg++;
50       if (isalpha(*sarg))
51         {
52           char smon[32];
53           strncpy(smon, sarg, sizeof(smon) - 1);
54           smon[sizeof(smon) - 1] = 0;
55           cstr_to_lower_case(smon);
56           int im;
57           for (im = 0; im < 12; ++im)
58             if (memcmp(smon, cmons[im + 1], 3) == 0) break;
59 
60           if (im < 12) dmon = im + 1;
61         }
62     }
63 
64   if (Options::cdoVerbose) cdo_print("delete day %d%s", dday, cmons[dmon]);
65 
66   const auto streamID1 = cdo_open_read(0);
67 
68   const auto vlistID1 = cdo_stream_inq_vlist(streamID1);
69   const auto vlistID2 = vlistDuplicate(vlistID1);
70 
71   const auto taxisID1 = vlistInqTaxis(vlistID1);
72   const auto taxisID2 = taxisDuplicate(taxisID1);
73   taxisDefCalendar(taxisID2, CALENDAR_365DAYS);
74   vlistDefTaxis(vlistID2, taxisID2);
75 
76   const auto streamID2 = cdo_open_write(1);
77   cdo_def_vlist(streamID2, vlistID2);
78 
79   Field field;
80 
81   VarList varList1;
82   varListInit(varList1, vlistID1);
83 
84   int nfound = 0;
85   int tsID = 0;
86   int tsID2 = 0;
87   while (true)
88     {
89       const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID);
90       if (nrecs == 0) break;
91 
92       const auto vdate = taxisInqVdate(taxisID1);
93       // vtime = taxisInqVtime(taxisID1);
94 
95       cdiDecodeDate(vdate, &year, &month, &day);
96 
97       if (day == dday && (month == dmon || dmon == 0))
98         {
99           nfound++;
100           copytimestep = false;
101           if (Options::cdoVerbose) cdo_print("Delete %4.4d-%2.2d-%2.2d at timestep %d", year, month, day, tsID + 1);
102         }
103       else
104         copytimestep = true;
105 
106       if (copytimestep)
107         {
108           cdo_taxis_copy_timestep(taxisID2, taxisID1);
109           cdo_def_timestep(streamID2, tsID2++);
110 
111           for (int recID = 0; recID < nrecs; recID++)
112             {
113               int varID, levelID;
114               cdo_inq_record(streamID1, &varID, &levelID);
115               cdo_def_record(streamID2, varID, levelID);
116               if (dataIsUnchanged)
117                 {
118                   cdo_copy_record(streamID2, streamID1);
119                 }
120               else
121                 {
122                   field.init(varList1[varID]);
123                   cdo_read_record(streamID1, field);
124                   cdo_write_record(streamID2, field);
125                 }
126             }
127         }
128 
129       tsID++;
130     }
131 
132   cdo_stream_close(streamID2);
133   cdo_stream_close(streamID1);
134 
135   if (nfound == 0) cdo_warning("Day %d%s not found!", dday, cmons[dmon]);
136 
137   vlistDestroy(vlistID2);
138 
139   cdo_finish();
140 
141   return nullptr;
142 }
143