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 */
12
13 #include <cdi.h>
14
15 #include "cdo_vlist.h"
16 #include "process_int.h"
17 #include "interpol.h"
18 #include "datetime.h"
19 #include "varray.h"
20 #include "printinfo.h"
21
22 static int
readnextpos(FILE * fp,int calendar,JulianDate * juldate,double * xpos,double * ypos)23 readnextpos(FILE *fp, int calendar, JulianDate *juldate, double *xpos, double *ypos)
24 {
25 *xpos = 0;
26 *ypos = 0;
27
28 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
29 int stat = fscanf(fp, "%d-%d-%d %d:%d:%d %lf %lf", &year, &month, &day, &hour, &minute, &second, xpos, ypos);
30
31 if (stat != EOF)
32 {
33 const auto date = cdiEncodeDate(year, month, day);
34 const auto time = cdiEncodeTime(hour, minute, second);
35 *juldate = juldate_encode(calendar, date, time);
36 }
37
38 return stat;
39 }
40
41 void *
Intgridtraj(void * process)42 Intgridtraj(void *process)
43 {
44 int varID, levelID;
45 int64_t vdate;
46 int vtime;
47 size_t nmiss = 0;
48 double xpos, ypos;
49 int calendar = CALENDAR_STANDARD;
50
51 cdo_initialize(process);
52
53 operator_input_arg("filename with grid trajectories");
54 operator_check_argc(1);
55
56 auto posfile = cdo_operator_argv(0).c_str();
57 auto fp = fopen(posfile, "r");
58 if (fp == nullptr) cdo_abort("Open failed on %s!", posfile);
59
60 JulianDate juldate;
61 readnextpos(fp, calendar, &juldate, &xpos, &ypos);
62
63 const auto streamID1 = cdo_open_read(0);
64 const auto vlistID1 = cdo_stream_inq_vlist(streamID1);
65
66 VarList varList1;
67 varListInit(varList1, vlistID1);
68
69 const auto nvars = vlistNvars(vlistID1);
70
71 const auto maxrecs = vlistNrecs(vlistID1);
72 std::vector<RecordInfo> recList(maxrecs);
73
74 const auto gridsizemax = vlistGridsizeMax(vlistID1);
75 Field field1, field2;
76 field1.resize(gridsizemax);
77 field2.resize(1);
78
79 Varray2D<double> vardata1(nvars), vardata2(nvars);
80
81 for (varID = 0; varID < nvars; varID++)
82 {
83 const auto gridsize = varList1[varID].gridsize;
84 const auto nlevels = varList1[varID].nlevels;
85 vardata1[varID].resize(gridsize * nlevels);
86 vardata2[varID].resize(gridsize * nlevels);
87 }
88
89 const auto gridID2 = gridCreate(GRID_TRAJECTORY, 1);
90 gridDefXsize(gridID2, 1);
91 gridDefYsize(gridID2, 1);
92 gridDefXvals(gridID2, &xpos);
93 gridDefYvals(gridID2, &ypos);
94
95 const auto vlistID2 = vlistDuplicate(vlistID1);
96
97 const auto ngrids = vlistNgrids(vlistID1);
98 for (int index = 0; index < ngrids; index++)
99 {
100 const auto gridID1 = vlistGrid(vlistID1, index);
101
102 if (gridInqType(gridID1) != GRID_LONLAT && gridInqType(gridID1) != GRID_GAUSSIAN)
103 cdo_abort("Unsupported grid type: %s", gridNamePtr(gridInqType(gridID1)));
104
105 vlistChangeGridIndex(vlistID2, index, gridID2);
106 }
107
108 const auto taxisID1 = vlistInqTaxis(vlistID1);
109 const auto taxisID2 = taxisDuplicate(taxisID1);
110 vlistDefTaxis(vlistID2, taxisID2);
111
112 CdoStreamID streamID2 = CDO_STREAM_UNDEF;
113
114 int tsID = 0;
115 auto nrecs = cdo_stream_inq_timestep(streamID1, tsID++);
116 auto juldate1 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
117 for (int recID = 0; recID < nrecs; recID++)
118 {
119 cdo_inq_record(streamID1, &varID, &levelID);
120 const auto gridsize = varList1[varID].gridsize;
121 const auto offset = gridsize * levelID;
122 auto single1 = &vardata1[varID][offset];
123 cdo_read_record(streamID1, single1, &nmiss);
124 if (nmiss) cdo_abort("Missing values unsupported for this operator!");
125 }
126
127 int tsIDo = 0;
128 while (juldate_to_seconds(juldate1) <= juldate_to_seconds(juldate))
129 {
130 nrecs = cdo_stream_inq_timestep(streamID1, tsID++);
131 if (nrecs == 0) break;
132 auto juldate2 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
133
134 for (int recID = 0; recID < nrecs; recID++)
135 {
136 cdo_inq_record(streamID1, &varID, &levelID);
137
138 recList[recID].varID = varID;
139 recList[recID].levelID = levelID;
140 recList[recID].lconst = (varList1[varID].timetype == TIME_CONSTANT);
141
142 const auto gridsize = varList1[varID].gridsize;
143 const auto offset = gridsize * levelID;
144 auto single2 = &vardata2[varID][offset];
145 cdo_read_record(streamID1, single2, &nmiss);
146 if (nmiss) cdo_abort("Missing values unsupported for this operator!");
147 }
148
149 while (juldate_to_seconds(juldate) < juldate_to_seconds(juldate2))
150 {
151 if (juldate_to_seconds(juldate) >= juldate_to_seconds(juldate1)
152 && juldate_to_seconds(juldate) < juldate_to_seconds(juldate2))
153 {
154 if (streamID2 == CDO_STREAM_UNDEF)
155 {
156 streamID2 = cdo_open_write(1);
157 cdo_def_vlist(streamID2, vlistID2);
158 }
159
160 juldate_decode(calendar, juldate, vdate, vtime);
161 taxisDefVdate(taxisID2, vdate);
162 taxisDefVtime(taxisID2, vtime);
163 cdo_def_timestep(streamID2, tsIDo++);
164
165 const auto deltat = juldate_to_seconds(juldate_sub(juldate2, juldate1));
166 const auto fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / deltat;
167 const auto fac2 = juldate_to_seconds(juldate_sub(juldate, juldate1)) / deltat;
168 // printf(" %f %f %f %f %f\n", juldate_to_seconds(juldate), juldate_to_seconds(juldate1),
169 // juldate_to_seconds(juldate2), fac1, fac2);
170 for (int recID = 0; recID < nrecs; recID++)
171 {
172 varID = recList[recID].varID;
173 levelID = recList[recID].levelID;
174 const auto gridsize = varList1[varID].gridsize;
175 const auto offset = gridsize * levelID;
176 auto single1 = &vardata1[varID][offset];
177 auto single2 = &vardata2[varID][offset];
178
179 for (size_t i = 0; i < gridsize; i++) field1.vec_d[i] = single1[i] * fac1 + single2[i] * fac2;
180
181 field1.grid = varList1[varID].gridID;
182 field1.missval = varList1[varID].missval;
183 field1.nmiss = nmiss;
184 field2.grid = gridID2;
185 field2.nmiss = 0;
186
187 intgridbil(field1, field2);
188
189 cdo_def_record(streamID2, varID, levelID);
190 cdo_write_record(streamID2, field2.vec_d.data(), field2.nmiss);
191 }
192 }
193 if (readnextpos(fp, calendar, &juldate, &xpos, &ypos) == EOF) break;
194 gridDefXvals(gridID2, &xpos);
195 gridDefYvals(gridID2, &ypos);
196 }
197
198 juldate1 = juldate2;
199 for (varID = 0; varID < nvars; varID++)
200 {
201 auto vardatap = vardata1[varID];
202 vardata1[varID] = vardata2[varID];
203 vardata2[varID] = vardatap;
204 }
205 }
206
207 if (tsIDo == 0)
208 {
209 juldate_decode(calendar, juldate, vdate, vtime);
210 cdo_warning("Date/time %s %s not found!", date_to_string(vdate).c_str(), time_to_string(vtime).c_str());
211 }
212
213 fclose(fp);
214 if (streamID2 != CDO_STREAM_UNDEF) cdo_stream_close(streamID2);
215 cdo_stream_close(streamID1);
216
217 cdo_finish();
218
219 return nullptr;
220 }
221