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 /*
9 This module contains the following operators:
10
11 Splitsel splitsel Split time selection
12 */
13
14 #include <cdi.h>
15
16 #include "cdo_options.h"
17 #include "process_int.h"
18 #include "param_conversion.h"
19 #include "util_files.h"
20
21 void *
Splitsel(void * process)22 Splitsel(void *process)
23 {
24 cdo_initialize(process);
25
26 if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!");
27
28 const auto dataIsUnchanged = data_is_unchanged();
29
30 cdo_operator_add("splitsel", 0, 0, nullptr);
31
32 // operator_input_arg("nsets <noffset <nskip>>");
33
34 const auto nargc = cdo_operator_argc();
35 if (nargc < 1) cdo_abort("Too few arguments! Need %d found %d.", 1, nargc);
36
37 const auto nsets = parameter_to_int(cdo_operator_argv(0));
38 const auto noffset = (nargc > 1) ? parameter_to_int(cdo_operator_argv(1)) : 0;
39 const auto nskip = (nargc > 2) ? parameter_to_int(cdo_operator_argv(2)) : 0;
40
41 if (Options::cdoVerbose) cdo_print("nsets = %d, noffset = %d, nskip = %d", nsets, noffset, nskip);
42
43 if (nsets < 1) cdo_abort("nsets must be greater than 0!");
44 if (noffset < 0) cdo_abort("noffset must be greater or equal 0!");
45 if (nskip < 0)
46 {
47 if (-nskip >= nsets) cdo_abort("Absolute value of negative nskip must be less than nsets!");
48 if (cdo_assert_files_only() == false) cdo_abort("Negative nskip not allowed in combination with other operators!");
49 }
50
51 const auto streamID1 = cdo_open_read(0);
52
53 const auto vlistID1 = cdo_stream_inq_vlist(streamID1);
54 const auto vlistID2 = vlistDuplicate(vlistID1);
55
56 const auto taxisID1 = vlistInqTaxis(vlistID1);
57 // int taxisID2 = cdo_taxis_create(TAXIS_ABSOLUTE);
58 const auto taxisID2 = taxisDuplicate(taxisID1);
59 vlistDefTaxis(vlistID2, taxisID2);
60
61 VarList varList1;
62 varListInit(varList1, vlistID1);
63
64 char filename[8192];
65 strcpy(filename, cdo_get_obase().c_str());
66 const auto nchars = strlen(filename);
67
68 auto refname = cdo_get_stream_name(0);
69 char filesuffix[32] = { 0 };
70 FileUtils::gen_suffix(filesuffix, sizeof(filesuffix), cdo_inq_filetype(streamID1), vlistID1, refname);
71
72 Varray<double> array;
73 // if (! dataIsUnchanged)
74 {
75 auto gridsizemax = vlistGridsizeMax(vlistID1);
76 if (vlistNumber(vlistID1) != CDI_REAL) gridsizemax *= 2;
77 array.resize(gridsizemax);
78 }
79
80 const auto nvars = vlistNvars(vlistID1);
81 int nconst = 0;
82 for (int varID = 0; varID < nvars; varID++)
83 if (varList1[varID].timetype == TIME_CONSTANT) nconst++;
84
85 FieldVector2D vars;
86 if (nconst)
87 {
88 vars.resize(nvars);
89
90 for (int varID = 0; varID < nvars; varID++)
91 {
92 if (varList1[varID].timetype == TIME_CONSTANT)
93 {
94 const auto gridID = varList1[varID].gridID;
95 const auto gridsize = varList1[varID].gridsize;
96 const auto nlevels = varList1[varID].nlevels;
97
98 vars[varID].resize(nlevels);
99
100 for (int levelID = 0; levelID < nlevels; levelID++)
101 {
102 vars[varID][levelID].grid = gridID;
103 vars[varID][levelID].resize(gridsize);
104 }
105 }
106 }
107 }
108
109 int index = 1;
110 int tsID;
111 int nrecs = 0;
112
113 // offset
114 for (tsID = 0; tsID < noffset; tsID++)
115 {
116 nrecs = cdo_stream_inq_timestep(streamID1, tsID);
117 if (nrecs == 0)
118 {
119 cdo_warning("noffset is larger than number of timesteps!");
120 goto LABEL_END;
121 }
122
123 if (tsID == 0 && nconst)
124 for (int recID = 0; recID < nrecs; recID++)
125 {
126 int varID, levelID;
127 cdo_inq_record(streamID1, &varID, &levelID);
128 if (varList1[varID].timetype == TIME_CONSTANT)
129 {
130 size_t nmiss;
131 cdo_read_record(streamID1, vars[varID][levelID].vec_d.data(), &nmiss);
132 vars[varID][levelID].nmiss = nmiss;
133 }
134 }
135 }
136
137 while (true)
138 {
139 sprintf(filename + nchars, "%06d", index);
140 sprintf(filename + nchars + 6, "%s", filesuffix);
141
142 if (Options::cdoVerbose) cdo_print("create file %s", filename);
143
144 CdoStreamID streamID2 = CDO_STREAM_UNDEF;
145 int tsID2 = 0;
146
147 for (int i = 0; i < nsets; ++i)
148 {
149 nrecs = cdo_stream_inq_timestep(streamID1, tsID);
150 if (nrecs == 0) break;
151
152 cdo_taxis_copy_timestep(taxisID2, taxisID1);
153
154 if (streamID2 == CDO_STREAM_UNDEF)
155 {
156 streamID2 = cdo_open_write(filename);
157 cdo_def_vlist(streamID2, vlistID2);
158 }
159
160 cdo_def_timestep(streamID2, tsID2);
161
162 if (tsID > 0 && tsID2 == 0 && nconst)
163 {
164 for (int varID = 0; varID < nvars; varID++)
165 {
166 if (varList1[varID].timetype == TIME_CONSTANT)
167 {
168 const auto nlevels = varList1[varID].nlevels;
169 for (int levelID = 0; levelID < nlevels; levelID++)
170 {
171 cdo_def_record(streamID2, varID, levelID);
172 const auto nmiss = vars[varID][levelID].nmiss;
173 cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), nmiss);
174 }
175 }
176 }
177 }
178
179 for (int recID = 0; recID < nrecs; recID++)
180 {
181 int varID, levelID;
182 cdo_inq_record(streamID1, &varID, &levelID);
183 cdo_def_record(streamID2, varID, levelID);
184
185 if (dataIsUnchanged && !(tsID == 0 && nconst))
186 {
187 cdo_copy_record(streamID2, streamID1);
188 }
189 else
190 {
191 size_t nmiss;
192 cdo_read_record(streamID1, array.data(), &nmiss);
193 cdo_write_record(streamID2, array.data(), nmiss);
194
195 if (tsID == 0 && nconst)
196 {
197 if (varList1[varID].timetype == TIME_CONSTANT)
198 {
199 varray_copy(varList1[varID].gridsize, array, vars[varID][levelID].vec_d);
200 vars[varID][levelID].nmiss = nmiss;
201 }
202 }
203 }
204 }
205
206 tsID++;
207 tsID2++;
208 }
209
210 cdo_stream_close(streamID2);
211 if (nrecs == 0) break;
212
213 if (cdo_stream_inq_timestep(streamID1, tsID) == 0) break;
214
215 // skip
216 for (int i = 0; i < nskip; ++i)
217 if (cdo_stream_inq_timestep(streamID1, tsID + i) == 0) break;
218
219 tsID += nskip;
220
221 if (cdo_stream_inq_timestep(streamID1, tsID) == 0) break;
222
223 index++;
224 }
225
226 LABEL_END:
227
228 cdo_stream_close(streamID1);
229
230 vlistDestroy(vlistID2);
231
232 cdo_finish();
233
234 return nullptr;
235 }
236