1 /* Copyright (c) 2010 Alexey Ozeritsky
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "barvortex.h"
34 using namespace linal;
36 SphereBarvortex::SphereBarvortex (const SphereBarvortex::Conf & conf) : SphereNorm(conf.nlat, conf.nlon),
37 conf (conf), op (conf.nlat, conf.nlon, 0), lapl(op), jac (op),
38 lh (conf.nlat * conf.nlon)
40 long nlat = conf.nlat;
41 long nlon = conf.nlon;
42 double dlat = M_PI / (nlat-1);
43 double dlon = 2. * M_PI /nlon;
46 for (int i = 0; i < nlat; ++i)
48 double phi = -0.5 * M_PI + i * dlat;
49 for (int j = 0; j < nlon; ++j)
51 double lambda = j * dlon;
53 lh[i * nlon + j] = conf.cor(phi, lambda, 0, &conf);
54 } else if (conf.cor2) {
55 lh[i * nlon + j] = conf.cor2[i * nlon + j];
61 SphereBarvortex::~SphereBarvortex()
65 void SphereBarvortex::S_step (double * out, const double * u, double t)
67 long nlat = conf.nlat;
68 long nlon = conf.nlon;
69 long n = conf.nlat * conf.nlon;
70 double dlat = M_PI / (nlat - 1);
71 double dlon = 2. * M_PI / nlon;
72 double tau = conf.tau;
73 double theta = conf.theta;
75 double sigma = conf.sigma;
78 double nr, nr0 = norm(u);
80 array_t w (n); // w = L(u)
81 array_t dw (n); // dw = L(w) = LL(u)
99 // генерируем правую часть
100 // w/dt + mu (1-theta) L w - \sigma(1-theta) w -
101 // - k1 J(0.5(u+u), 0.5(w+w)) - k2 J(0.5(u+u), l + h) + f(x, y)
104 lapl.calc (&w[0], &u[0]);
106 lapl.calc (&dw[0], &w[0]);
108 // w/dt + mu (1-theta) L w
109 vec_sum1 (&FC[0], &w[0], &dw[0], 1.0 / tau,
110 mu * (1.0 - theta), n);
111 // w/dt + mu (1-theta) L w - \sigma (1-theta) w
112 vec_sum1 (&FC[0], &FC[0], &w[0], 1.0,
113 -sigma * (1.0 - theta), n);
115 for (int i = 0; i < nlat; ++i)
117 double phi = -0.5 * M_PI + i * dlat;
118 for (int j = 0; j < nlon; ++j)
120 double lambda = j * dlon;
123 FC[i * nlon + j] += conf.rp (phi, lambda, t, &conf);
124 } else if (conf.rp2) {
125 FC[i * nlon + j] += conf.rp2[i * nlon + j];
130 memcpy(&u_n[0], &u[0], n * sizeof(double));
131 memcpy(&w_n[0], &w[0], n * sizeof(double));
133 // в FC содержится правая часть, которая не меняется при итерациях!
135 for (int it = 0; it < 1000; ++it) {
136 // k1 J(0.5(u+u), 0.5(w+w)) + k2 J(0.5(u+u), l + h) =
137 // = J(0.5 (u+u), 0.5 k1 (w+w)) + J(0.5 (u+u), k2 (l + h)) =
138 // = J(0.5 (u+u), 0.5 k1 (w+w) + k2 (l + h))
139 vec_sum1(&tmp1[0], &w_n[0], &w[0], k1 * theta,
140 k1 * (1.0 - theta), n);
141 vec_sum1(&tmp1[0], &tmp1[0], &lh[0], 1.0, k2, n);
143 vec_sum1(&tmp2[0], &u_n[0], &u[0], theta,
145 // - k1 J(0.5(u+u), 0.5(w+w)) - k2 J(0.5(u+u), l + h)
146 jac.calc(&jac0[0], &tmp2[0], &tmp1[0]);
147 vec_sum1(&F[0], &FC[0], &jac0[0], 1.0, -1.0, n);
148 lapl.solve(&w_n[0], &F[0], -theta * mu, 1.0 / tau + theta * sigma);
149 lapl.solve(&u_n1[0], &w_n[0]);
151 nr = dist(&u_n1[0], &u_n[0]);
153 if (nr / nr0 < 1e-14 || isnan(nr)) {
158 memcpy(out, &u_n[0], n * sizeof(double));
161 void SphereBarvortex::L_step(double *u1, const double *u, const double * z)
163 long nlat = conf.nlat;
164 long nlon = conf.nlon;
165 long n = conf.nlat * conf.nlon;
166 double theta = conf.theta;
168 double sigma = conf.sigma;
169 double tau = conf.tau;
172 double nr, nr0 = norm(u);
196 lapl.calc(&dz[0], z);
200 lapl.calc(&dw[0], &w[0]);
202 // w/dt + mu (1-theta) L w
203 vec_sum1 (&FC[0], &w[0], &dw[0], 1.0 / tau,
204 mu * (1.0 - theta), n);
205 // w/dt + mu (1-theta) L w - \sigma (1-theta) w
206 vec_sum1 (&FC[0], &FC[0], &w[0], 1.0,
207 -sigma * (1.0 - theta), n);
209 memcpy(&u_n[0], &u[0], n * sizeof(double));
210 memcpy(&w_n[0], &w[0], n * sizeof(double));
212 // в FC содержится правая часть, которая не меняется при итерациях!
214 for (int it = 0; it < 1000; ++it) {
215 // k1 J(0.5(u+u), dz) + k1 J(z, 0.5(w+w)) + k2 J(0.5(u+u), l + h)
217 vec_sum1(&tmp1[0], &w_n[0], &w[0], theta,
219 vec_sum1(&tmp2[0], &u_n[0], &u[0], theta,
223 jac.calc(&jac0[0], &tmp2[0], &dz[0]);
225 jac.calc(&jac1[0], &z[0], &tmp1[0]);
226 // J(0.5(u+u), l + h)
227 jac.calc(&jac2[0], &tmp2[0], &lh[0]);
229 vec_sum1(&jac0[0], &jac0[0], &jac1[0], k1, k1, n);
230 vec_sum1(&jac0[0], &jac0[0], &jac2[0], 1.0, k2, n);
232 vec_sum1(&F[0], &FC[0], &jac0[0], 1.0, -1.0, n);
234 lapl.solve(&w_n[0], &F[0], -theta * mu, 1.0 / tau + theta * sigma);
235 lapl.solve(&u_n1[0], &w_n[0]);
237 nr = dist(&u_n1[0], &u_n[0]);
239 if (nr / nr0 < 1e-14 || isnan(nr)) {
244 memcpy(u1, &u_n[0], n * sizeof(double));
247 void SphereBarvortex::LT_step(double *v1, const double *v, const double * z)
249 long nlat = conf.nlat;
250 long nlon = conf.nlon;
251 long n = conf.nlat * conf.nlon;
252 double theta = conf.theta;
254 double sigma = conf.sigma;
255 double tau = conf.tau;
259 array_t pt1 (n); //лаплас, умноженный на коэф
260 array_t pt2 (n); //лаплас в квадрате, умноженный на коэф
261 array_t pt3 (n); //якобиан, умноженный на коэф
263 lapl.calc(&z_lapl[0], z);
266 lapl.solve(v1, v1, - theta * mu, 1.0 / tau + theta * sigma);
268 lapl.calc(&pt1[0], v1);
269 vec_mult_scalar(&pt1[0], &pt1[0], 1.0 / tau - (1. - theta) * sigma, n);
271 lapl.calc(&pt2[0], v1);
272 lapl.calc(&pt2[0], &pt2[0]);
274 vec_mult_scalar(&pt2[0], &pt2[0], (1. - theta) * mu, n);
278 jac.calc_t(&tmp[0], v1, &lh[0]);
279 jac.calc_t(&p_lapl[0], z, v1);
280 lapl.calc(&p_lapl[0], &p_lapl[0]);
281 jac.calc_t(&pt3[0], v1, &z_lapl[0]);
282 vec_sum(&pt3[0], &pt3[0], &p_lapl[0], n);
283 vec_sum(&pt3[0], &pt3[0], &tmp[0], n);
285 //vector_mult_scalar(&pt3[0], &pt3[0], -conf->rho, nn); //TODO: k1, k2
287 memset(v1, 0, n * sizeof(double));
288 vec_sum(v1, v1, &pt1[0], n);
289 vec_sum(v1, v1, &pt2[0], n);
290 vec_sum(v1, v1, &pt3[0], n);
293 void SphereBarvortex::L_1_step(double *u1, const double *u, const double * z)
295 long nlat = conf.nlat;
296 long nlon = conf.nlon;
297 long n = conf.nlat * conf.nlon;
298 double theta = conf.theta;
300 double sigma = conf.sigma;
301 double tau = conf.tau;
306 array_t pt1 (n); //лаплас, умноженный на коэф
307 array_t pt2 (n); //лаплас в квадрате, умноженный на коэф
308 array_t pt3 (n); //якобиан, умноженный на коэф
310 lapl.calc(&z_lapl[0], z);
311 lapl.calc(&pt1[0], u); //первая часть - лаплас, умноженный на коэф,
313 jac.calc(&pt3[0], &u[0], &lh[0]);
314 jac.calc(&tmp[0], z, &pt1[0]); vec_sum(&pt3[0], &pt3[0], &tmp[0], n);
315 jac.calc(&tmp[0], &u[0], &z_lapl[0]); vec_sum(&pt3[0], &pt3[0], &tmp[0], n);
316 //vec_mult_scalar(&pt3[0], &pt3[0], conf->rho, n); // TODO: k1, k2
318 lapl.calc(&pt2[0], &pt1[0]);
319 vec_mult_scalar(&pt2[0], &pt2[0], ( - theta) * mu, n);
321 vec_mult_scalar(&pt1[0], &pt1[0], 1 / tau + theta * sigma, n);
323 memset(u1, 0, n * sizeof(double));
324 vec_sum(u1, u1, &pt1[0], n);
325 vec_sum(u1, u1, &pt2[0], n);
326 vec_sum(u1, u1, &pt3[0], n);
328 lapl.solve(u1, u1, (1.0 - theta) * mu, 1 / tau - (1.0 - theta) * sigma);
332 void SphereBarvortex::p2u(double * u, const double * p)
334 memcpy(u, p, conf.nlat * conf.nlon * sizeof(double));
337 void SphereBarvortex::u2p(double * p, const double * u)
339 memcpy(p, u, conf.nlat * conf.nlon * sizeof(double));