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