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 "cdo_output.h"
11 #include "cdo_fctrans.h"
12 #include "specspace.h"
13 #include <mpim_grid.h>
14
15 void
grid2spec(const SP_Transformation & spTrans,int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)16 grid2spec(const SP_Transformation &spTrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
17 {
18 const auto &fcTrans = spTrans.fcTrans;
19 const long nlev = 1;
20 const long ntr = gridInqTrunc(gridIDout);
21 const long nlon = gridInqXsize(gridIDin);
22 const long nlat = gridInqYsize(gridIDin);
23 const long waves = ntr + 1;
24 const long nfc = waves * 2;
25
26 std::vector<double> fpwork(nlat * nfc * nlev);
27
28 if (fcTrans.use_fftw)
29 gp2fc(arrayIn, fpwork.data(), nlat, nlon, nlev, nfc);
30 else
31 gp2fc(fcTrans.vtrig.data(), fcTrans.ifax, arrayIn, fpwork.data(), nlat, nlon, nlev, nfc);
32
33 fc2sp(fpwork.data(), arrayOut, spTrans.pold.data(), nlev, nlat, nfc, ntr);
34 }
35
36 void
spec2grid(const SP_Transformation & spTrans,int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)37 spec2grid(const SP_Transformation &spTrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
38 {
39 const auto &fcTrans = spTrans.fcTrans;
40 const long nlev = 1;
41 const long ntr = gridInqTrunc(gridIDin);
42 const long nlon = gridInqXsize(gridIDout);
43 const long nlat = gridInqYsize(gridIDout);
44 const long waves = ntr + 1;
45 const long nfc = waves * 2;
46
47 std::vector<double> fpwork(nlat * nfc * nlev);
48
49 sp2fc(arrayIn, fpwork.data(), spTrans.poli.data(), nlev, nlat, nfc, ntr);
50
51 if (fcTrans.use_fftw)
52 fc2gp(fpwork.data(), arrayOut, nlat, nlon, nlev, nfc);
53 else
54 fc2gp(fcTrans.vtrig.data(), fcTrans.ifax, fpwork.data(), arrayOut, nlat, nlon, nlev, nfc);
55 }
56
57 void
four2spec(const SP_Transformation & spTrans,int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)58 four2spec(const SP_Transformation &spTrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
59 {
60 (void) gridIDin;
61 const long nlev = 1;
62 const long ntr = gridInqTrunc(gridIDout);
63 const long nlat = spTrans.nlat;
64 const long waves = ntr + 1;
65 const long nfc = waves * 2;
66
67 fc2sp(arrayIn, arrayOut, spTrans.pold.data(), nlev, nlat, nfc, ntr);
68 }
69
70 void
spec2four(const SP_Transformation & spTrans,int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)71 spec2four(const SP_Transformation &spTrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
72 {
73 const long nlev = 1;
74 const long ntr = gridInqTrunc(gridIDin);
75 long nfc = gridInqSize(gridIDout);
76 const long nlat = nfc_to_nlat(nfc, ntr);
77 const long waves = ntr + 1;
78 nfc = waves * 2;
79
80 sp2fc(arrayIn, arrayOut, spTrans.poli.data(), nlev, nlat, nfc, ntr);
81 }
82
83 void
four2grid(const FC_Transformation & fcTrans,int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)84 four2grid(const FC_Transformation &fcTrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
85 {
86 const long nlev = 1;
87 const long ntr = gridInqTrunc(gridIDin);
88 const long nlon = gridInqXsize(gridIDout);
89 const long nlat = gridInqYsize(gridIDout);
90 const long waves = ntr + 1;
91 const long nfc = waves * 2;
92
93 if (fcTrans.use_fftw)
94 fc2gp(arrayIn, arrayOut, nlat, nlon, nlev, nfc);
95 else
96 fc2gp(fcTrans.vtrig.data(), fcTrans.ifax, arrayIn, arrayOut, nlat, nlon, nlev, nfc);
97 }
98
99 void
grid2four(const FC_Transformation & fcTrans,int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)100 grid2four(const FC_Transformation &fcTrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
101 {
102 const long nlev = 1;
103 const long ntr = gridInqTrunc(gridIDout);
104 const long nlon = gridInqXsize(gridIDin);
105 const long nlat = gridInqYsize(gridIDin);
106 const long waves = ntr + 1;
107 const long nfc = waves * 2;
108
109 if (fcTrans.use_fftw)
110 gp2fc(arrayIn, arrayOut, nlat, nlon, nlev, nfc);
111 else
112 gp2fc(fcTrans.vtrig.data(), fcTrans.ifax, arrayIn, arrayOut, nlat, nlon, nlev, nfc);
113 }
114
115 void
spec2spec(int gridIDin,double * arrayIn,int gridIDout,double * arrayOut)116 spec2spec(int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
117 {
118 const long ntrIn = gridInqTrunc(gridIDin);
119 const long ntrOut = gridInqTrunc(gridIDout);
120
121 sp2sp(arrayIn, ntrIn, arrayOut, ntrOut);
122 }
123
124 void
speccut(int gridIDin,double * arrayIn,double * arrayOut,int * waves)125 speccut(int gridIDin, double *arrayIn, double *arrayOut, int *waves)
126 {
127 const long ntr = gridInqTrunc(gridIDin);
128
129 spcut(arrayIn, arrayOut, ntr, waves);
130 }
131
132 void
trans_uv2dv(const SP_Transformation & spTrans,long nlev,int gridID1,double * gu,double * gv,int gridID2,double * sd,double * svo)133 trans_uv2dv(const SP_Transformation &spTrans, long nlev, int gridID1, double *gu, double *gv, int gridID2, double *sd, double *svo)
134 {
135 if (gridInqType(gridID1) != GRID_GAUSSIAN)
136 cdo_abort("unexpected grid1 type: %s instead of Gaussian", gridNamePtr(gridInqType(gridID1)));
137
138 if (gridInqType(gridID2) != GRID_SPECTRAL)
139 cdo_abort("unexpected grid2 type: %s instead of spectral", gridNamePtr(gridInqType(gridID2)));
140
141 const auto &fcTrans = spTrans.fcTrans;
142 const long ntr = gridInqTrunc(gridID2);
143 const long nlon = gridInqXsize(gridID1);
144 const long nlat = gridInqYsize(gridID1);
145 const long waves = ntr + 1;
146 const long nfc = waves * 2;
147
148 std::vector<double> fpwork1(nlat * nfc * nlev);
149 std::vector<double> fpwork2(nlat * nfc * nlev);
150
151 if (fcTrans.use_fftw)
152 {
153 gp2fc(gu, fpwork1.data(), nlat, nlon, nlev, nfc);
154 gp2fc(gv, fpwork2.data(), nlat, nlon, nlev, nfc);
155 }
156 else
157 {
158 gp2fc(fcTrans.vtrig.data(), fcTrans.ifax, gu, fpwork1.data(), nlat, nlon, nlev, nfc);
159 gp2fc(fcTrans.vtrig.data(), fcTrans.ifax, gv, fpwork2.data(), nlat, nlon, nlev, nfc);
160 }
161
162 scaluv(fpwork1.data(), spTrans.coslat.data(), nlat, nfc * nlev);
163 scaluv(fpwork2.data(), spTrans.coslat.data(), nlat, nfc * nlev);
164
165 uv2dv(fpwork1.data(), fpwork2.data(), sd, svo, spTrans.pol2.data(), spTrans.pol3.data(), nlev, nlat, ntr);
166 }
167
168 void
trans_dv2uv(const SP_Transformation & spTrans,const DV_Transformation & dvTrans,long nlev,int gridID1,double * sd,double * svo,int gridID2,double * gu,double * gv)169 trans_dv2uv(const SP_Transformation &spTrans, const DV_Transformation &dvTrans, long nlev, int gridID1, double *sd, double *svo,
170 int gridID2, double *gu, double *gv)
171 {
172 if (gridInqType(gridID1) != GRID_SPECTRAL)
173 cdo_warning("unexpected grid1 type: %s instead of spectral", gridNamePtr(gridInqType(gridID1)));
174 if (gridInqType(gridID2) != GRID_GAUSSIAN)
175 cdo_warning("unexpected grid2 type: %s instead of Gaussian", gridNamePtr(gridInqType(gridID2)));
176
177 const auto &fcTrans = spTrans.fcTrans;
178 const long ntr = gridInqTrunc(gridID1);
179 const long nlon = gridInqXsize(gridID2);
180 const long nlat = gridInqYsize(gridID2);
181 const long waves = ntr + 1;
182 const long nfc = waves * 2;
183 const long dimsp = (ntr + 1) * (ntr + 2);
184
185 double *su = gu;
186 double *sv = gv;
187
188 dv2uv(sd, svo, su, sv, dvTrans.f1.data(), dvTrans.f2.data(), ntr, dimsp, nlev);
189
190 std::vector<double> fpwork(nlat * nfc * nlev);
191
192 sp2fc(su, fpwork.data(), spTrans.poli.data(), nlev, nlat, nfc, ntr);
193 scaluv(fpwork.data(), spTrans.rcoslat.data(), nlat, nfc * nlev);
194
195 if (fcTrans.use_fftw)
196 fc2gp(fpwork.data(), gu, nlat, nlon, nlev, nfc);
197 else
198 fc2gp(fcTrans.vtrig.data(), fcTrans.ifax, fpwork.data(), gu, nlat, nlon, nlev, nfc);
199
200 sp2fc(sv, fpwork.data(), spTrans.poli.data(), nlev, nlat, nfc, ntr);
201 scaluv(fpwork.data(), spTrans.rcoslat.data(), nlat, nfc * nlev);
202
203 if (fcTrans.use_fftw)
204 fc2gp(fpwork.data(), gv, nlat, nlon, nlev, nfc);
205 else
206 fc2gp(fcTrans.vtrig.data(), fcTrans.ifax, fpwork.data(), gv, nlat, nlon, nlev, nfc);
207 }
208