Support for creating high altitude noctilucent clouds in Advanced Weather/ALS
[fg:toms-fgdata.git] / Nasal / local_weather / cloud_placement_lowlevel.nas
1 ########################################################
2 # routines to set up, transform and manage advanced weather
3 # Thorsten Renk, April 2012
4 ########################################################
5
6 # function                      purpose
7 #
8 # create_undulatus              to create an undulating cloud pattern
9 # create_cumulus_alleys         to create an alley pattern of Cumulus clouds
10 # create_layer                  to create a cloud layer with optional precipitation
11
12 ###########################################################
13 # place an undulatus pattern 
14 ###########################################################
15
16 var create_undulatus = func (type, blat, blong, balt, alt_var, nx, xoffset, edgex, x_var, ny, yoffset, edgey, y_var, und_strength, direction, tri) {
17
18 var flag = 0;
19 var path = "Models/Weather/blank.ac";
20 local_weather.calc_geo(blat);
21 var dir = direction * math.pi/180.0;
22
23 var ymin = -0.5 * ny * yoffset;
24 var xmin = -0.5 * nx * xoffset;
25 var xinc = xoffset * (tri-1.0) /ny;
26  
27 var jlow = int(nx*edgex);
28 var ilow = int(ny*edgey);
29
30 var und = 0.0;
31 var und_array = [];
32
33 for (var i=0; i<ny; i=i+1)
34         {
35         und = und + 2.0 * (rand() -0.5) * und_strength;
36         append(und_array,und);
37         }
38
39 for (var i=0; i<ny; i=i+1)
40         {
41         var y = ymin + i * yoffset + 2.0 * (rand() -0.5) * 0.2 * yoffset; 
42         
43         for (var j=0; j<nx; j=j+1)
44                 {
45                 var y0 = y + y_var * 2.0 * (rand() -0.5);
46                 var x = xmin + j * (xoffset + i * xinc) + x_var * 2.0 * (rand() -0.5) + und_array[i];
47                 var lat = blat + m_to_lat * (y0 * math.cos(dir) - x * math.sin(dir));
48                 var long = blong + m_to_lon * (x * math.cos(dir) + y0 * math.sin(dir));
49
50                 var alt = balt + alt_var * 2 * (rand() - 0.5);
51                 
52                 flag = 0;
53                 var rn = 6.0 * rand();
54
55                 if (((j<jlow) or (j>(nx-jlow-1))) and ((i<ilow) or (i>(ny-ilow-1)))) # select a small or no cloud               
56                         {
57                         if (rn > 2.0) {flag = 1;} else {path = select_cloud_model(type,"small");}
58                         }
59                 if ((j<jlow) or (j>(nx-jlow-1)) or (i<ilow) or (i>(ny-ilow-1)))         
60                         {
61                         if (rn > 5.0) {flag = 1;} else {path = select_cloud_model(type,"small");}
62                         }
63                 else    { # select a large cloud
64                         if (rn > 5.0) {flag = 1;} else {path = select_cloud_model(type,"large");}
65                         }
66
67
68                 if (flag==0){
69                         if (thread_flag == 1)
70                                 {create_cloud_vec(path, lat, long, alt, 0.0);}
71                         else
72                                 {local_weather.create_cloud(path, lat, long, alt, 0.0);}
73                         
74
75                                 }
76                 }
77
78         } 
79
80 }
81
82
83 ###########################################################
84 # place an advanced undulatus pattern 
85 ###########################################################
86
87 var create_adv_undulatus = func (arg) {
88
89 var markov_array = [];
90 var rnd_array = [];
91 var max_num_clouds = int(arg.xsize/arg.cloud_spacing)+1;
92 var max_num_streaks = int(arg.ysize/arg.undulatus_spacing)+1;
93 var path = "Models/Weather/blank.ac";
94 var counter = 0;
95
96 append(markov_array,0.0);
97
98 var rn = 0.0;
99 arg.dir = arg.dir + 90.0;
100
101 for (var i=1; i<max_num_clouds; i=i+1)
102         {
103         rn = rand();
104         append(markov_array, markov_array[i-1] + 2.0 * (rn -0.5) * arg.undulatus_amplitude + arg.undulatus_slant);
105         append(rnd_array, rn);
106         }
107
108 for (i=0; i< max_num_streaks; i=i+1)
109         {
110         var streak_ypos = -0.5 * arg.ysize + i * arg.undulatus_spacing;
111         var aspect_num_clouds = int((arg.aspect + (1.0-arg.aspect) * i/max_num_streaks) * max_num_clouds);
112         
113         for (var j = 0; j< aspect_num_clouds; j=j+1)
114                 {
115                 var y = streak_ypos + markov_array[j];
116                 var x = -0.5 * arg.xsize + j * arg.cloud_spacing;
117                 
118                 x = x - arg.Dx + 2.0 * rand() * arg.Dx;
119                 y = y - arg.Dy + 2.0 * rand() * arg.Dy;
120                 
121                 var flag = 0;
122                 var     bias =1.0 - (1.0* math.abs(i-0.5 * max_num_streaks)/max_num_streaks +  1.0* math.abs(j-0.5 * aspect_num_clouds)/aspect_num_clouds);
123                 var comp = -.25 * rnd_array[j] + 0.75 * bias;
124                 
125                 comp = comp + arg.size_bias;
126                 if (comp > 0.7)
127                         {
128                         flag = 1;
129                         path = select_cloud_model(arg.type,"large")
130                         }
131                 else if (comp > 0.4)
132                         {
133                         flag = 1;
134                         path = select_cloud_model(arg.type,"small")
135                         }
136                         
137                 var lat = arg.blat + m_to_lat * (y * math.cos(arg.dir) - x * math.sin(arg.dir));
138                 var lon = arg.blon + m_to_lon * (x * math.cos(arg.dir) + y * math.sin(arg.dir));
139
140                 var alt = arg.balt + arg.alt_var * 2 * (rand() - 0.5);
141                 
142                 if (flag > 0)
143                         {create_cloud_vec(path, lat, lon, alt, 0.0); counter = counter +1;}
144                 }
145         
146         }
147         #print("Cloud count: ",counter);
148
149 }
150
151
152 ###########################################################
153 # place a stick bundle pattern 
154 ###########################################################
155
156 var sgn = func (x) {
157
158 if (x<0.0) {return -1.0;}
159 else {return 1.0;}
160 }
161
162 var create_stick_bundle = func (arg) {
163
164 var path = "Models/Weather/blank.ac";
165 var base_size_scale = local_weather.cloud_size_scale;
166
167 for (var i = 0; i<arg.n_sticks; i=i+1)
168         {
169         var stick_x = 0.5 * math.pow(rand(),2.0) * arg.xsize * sgn(rand()-0.5);
170         var stick_y = 0.5 * math.pow(rand(),2.0) * arg.ysize * sgn(rand()-0.5);
171                 
172         var stick_length = arg.stick_length_min + int(rand() * (arg.stick_length_max - arg.stick_length_min) );
173         var stick_Dphi = arg.stick_Dphi_min + rand() * (arg.stick_Dphi_max - arg.stick_Dphi_min);
174         var stick_size_scale = 0.8 + 0.2 * rand();
175         for (var j=0; j<stick_length;j=j+1)
176                 {
177                 var y = stick_y;
178                 var x = stick_x - 0.5 * stick_length * arg.cloud_spacing;
179                 var inc = j * arg.cloud_spacing;
180                 var pos_size_scale = base_size_scale +  base_size_scale * 2.0* (1.0 - 2.0* math.abs(0.5 * stick_length - j)/stick_length);
181                 local_weather.cloud_size_scale = pos_size_scale;
182                 local_weather.cloud_size_scale = stick_size_scale * local_weather.cloud_size_scale;
183                 inc = inc *  stick_size_scale;
184                 
185                 x = x + inc * math.cos(stick_Dphi);
186                 y = y + inc * math.sin(stick_Dphi);
187
188                 x = x - arg.Dx + 2.0 * rand() * arg.Dx;
189                 y = y - arg.Dy + 2.0 * rand() * arg.Dy;
190
191                 path = select_cloud_model(arg.type,"large");
192
193                 var lat = arg.blat + m_to_lat * (y * math.cos(arg.dir) - x * math.sin(arg.dir));
194                 var lon = arg.blon + m_to_lon * (x * math.cos(arg.dir) + y * math.sin(arg.dir));
195
196                 var alt = arg.balt + arg.alt_var * 2 * (rand() - 0.5);
197
198                 create_cloud_vec(path, lat, lon, alt, 0.0);
199                 }
200         }
201
202 }
203
204 ###########################################################
205 # place a nested domains pattern 
206 ###########################################################
207
208 var create_domains = func (arg) {
209
210 var path = "Models/Weather/blank.ac";
211
212 for (var j=0; j<arg.n_domains; j=j+1)
213         {
214         var domain_pos_x = -0.5 * arg.xsize + rand() * arg.xsize;
215         var domain_pos_y = -0.5 * arg.ysize + rand() * arg.ysize;
216
217         var domain_size_x = arg.min_domain_size_x + rand() * (arg.max_domain_size_x - arg.min_domain_size_x);
218         var domain_size_y = arg.min_domain_size_y + rand() * (arg.max_domain_size_y - arg.min_domain_size_y);
219
220         var n_node = int(arg.node_fraction * arg.n);
221         var n_halo = int(arg.halo_fraction * arg.n);
222         var n_bulk = arg.n - n_node - n_halo;
223         
224         for (var i=0; i<n_halo; i=i+1)
225                 {
226                 var x = domain_pos_x - 0.5 * domain_size_x + rand() * domain_size_x;
227                 var y = domain_pos_y - 0.5 * domain_size_y + rand() * domain_size_y;
228                 var lat = arg.blat + m_to_lat * (y * math.cos(arg.dir) - x * math.sin(arg.dir));
229                 var lon = arg.blon + m_to_lon * (x * math.cos(arg.dir) + y * math.sin(arg.dir));
230                 var alt = arg.balt + arg.alt_var * 2 * (rand() - 0.5);
231                 if ((math.abs(x-domain_pos_x) < 0.3 * domain_size_x) or (math.abs(y-domain_pos_y) < 0.3 * domain_size_y))
232                         {path = select_cloud_model(arg.htype,arg.hsubtype);
233                         create_cloud_vec(path, lat, lon, alt, 0.0);}
234                 }
235         for (i=0; i<n_bulk; i=i+1)
236                 {
237                 x = domain_pos_x - 0.5 * 0.4* domain_size_x + rand() * 0.4* domain_size_x;
238                 y = domain_pos_y - 0.5 * 0.4* domain_size_y + rand() * 0.4* domain_size_y;
239                 lat = arg.blat + m_to_lat * (y * math.cos(arg.dir) - x * math.sin(arg.dir));
240                 lon = arg.blon + m_to_lon * (x * math.cos(arg.dir) + y * math.sin(arg.dir));
241                 alt = arg.balt + arg.alt_var * 2 * (rand() - 0.5);
242                 if ((math.abs(x-domain_pos_x) < 0.4 * domain_size_x) or (math.abs(y-domain_pos_y) < 0.4 * domain_size_y))
243                         {
244                         path = select_cloud_model(arg.type,arg.subtype);
245                         create_cloud_vec(path, lat, lon, alt, 0.0);
246                         }
247                 }
248         for (i=0; i<n_node; i=i+1)
249                 {
250                 x = domain_pos_x - 0.5 * 0.1* domain_size_x + rand() * 0.1* domain_size_x;
251                 y = domain_pos_y - 0.5 * 0.1* domain_size_y + rand() * 0.1* domain_size_y;
252                 lat = arg.blat + m_to_lat * (y * math.cos(arg.dir) - x * math.sin(arg.dir));
253                 lon = arg.blon + m_to_lon * (x * math.cos(arg.dir) + y * math.sin(arg.dir));
254                 alt = arg.balt + arg.alt_var * 2 * (rand() - 0.5);
255                 path = select_cloud_model(arg.ntype,arg.nsubtype);
256                 create_cloud_vec(path, lat, lon, alt, 0.0);
257                 }
258
259         }
260
261
262
263 }
264
265
266
267
268 ###########################################################
269 # place a Cumulus alley pattern 
270 ###########################################################
271
272 var create_cumulus_alleys = func (blat, blon, balt, alt_var, nx, xoffset, edgex, x_var, ny, yoffset, edgey, y_var, und_strength, direction, tri) {
273
274 var flag = 0;
275 var path = "Models/Weather/blank.ac";
276 local_weather.calc_geo(blat);
277 var dir = direction * math.pi/180.0;
278
279 var ymin = -0.5 * ny * yoffset;
280 var xmin = -0.5 * nx * xoffset;
281 var xinc = xoffset * (tri-1.0) /ny;
282  
283 var jlow = int(nx*edgex);
284 var ilow = int(ny*edgey);
285
286 var und = 0.0;
287 var und_array = [];
288
289 var spacing = 0.0;
290 var spacing_array = [];
291
292
293 for (var i=0; i<ny; i=i+1)
294         {
295         und = und + 2.0 * (rand() -0.5) * und_strength;
296         append(und_array,und);
297         }
298
299 for (var i=0; i<nx; i=i+1)
300         {
301         spacing = spacing + 2.0 * (rand() -0.5) * 0.5 * xoffset;
302         append(spacing_array,spacing);
303         }
304
305
306 for (var i=0; i<ny; i=i+1)
307         {
308         var y = ymin + i * yoffset; 
309         var xshift = 2.0 * (rand() -0.5) * 0.5 * xoffset; 
310         x_var = 0.0; xshift = 0.0;
311
312         for (var j=0; j<nx; j=j+1)
313                 {
314                 var y0 = y + y_var * 2.0 * (rand() -0.5);
315                 var x = xmin + j * (xoffset + i * xinc) + x_var * 2.0 * (rand() -0.5) + spacing_array[j] + und_array[i];
316                 var lat = blat + m_to_lat * (y0 * math.cos(dir) - x * math.sin(dir));
317                 var lon = blon + m_to_lon * (x * math.cos(dir) + y0 * math.sin(dir));
318
319                 var alt = balt + alt_var * 2 * (rand() - 0.5);
320                 
321                 flag = 0;
322                 var strength = 0.0;
323                 var rn = 6.0 * rand();
324
325                 if (((j<jlow) or (j>(nx-jlow-1))) and ((i<ilow) or (i>(ny-ilow-1)))) # select a small or no cloud               
326                         {
327                         if (rn > 2.0) {flag = 1;} else {strength = 0.3 + rand() * 0.5;}
328                         }
329                 if ((j<jlow) or (j>(nx-jlow-1)) or (i<ilow) or (i>(ny-ilow-1)))         
330                         {
331                         if (rn > 5.0) {flag = 1;} else {strength = 0.7 + rand() * 0.5;}
332                         }
333                 else    { # select a large cloud
334                         if (rn > 5.0) {flag = 1;} else {strength = 1.1 + rand() * 0.6;}
335                         }
336
337
338                 if (flag==0){create_detailed_cumulus_cloud(lat, lon, alt, strength); }
339                 }
340
341         } 
342
343 }
344
345
346
347 ###########################################################
348 # place a Cumulus alley pattern 
349 ###########################################################
350
351 var create_developing_cumulus_alleys = func (blat, blon, balt, alt_var, nx, xoffset, edgex, x_var, ny, yoffset, edgey, y_var, und_strength, direction, tri) {
352
353 var flag = 0;
354 var path = "Models/Weather/blank.ac";
355 local_weather.calc_geo(blat);
356 var dir = direction * math.pi/180.0;
357
358 var ymin = -0.5 * ny * yoffset;
359 var xmin = -0.5 * nx * xoffset;
360 var xinc = xoffset * (tri-1.0) /ny;
361  
362 var jlow = int(nx*edgex);
363 var ilow = int(ny*edgey);
364
365 var und = 0.0;
366 var und_array = [];
367
368 var spacing = 0.0;
369 var spacing_array = [];
370
371
372 for (var i=0; i<ny; i=i+1)
373         {
374         und = und + 2.0 * (rand() -0.5) * und_strength;
375         append(und_array,und);
376         }
377
378 for (var i=0; i<nx; i=i+1)
379         {
380         spacing = spacing + 2.0 * (rand() -0.5) * 0.5 * xoffset;
381         append(spacing_array,spacing);
382         }
383
384
385 for (var i=0; i<ny; i=i+1)
386         {
387         var y = ymin + i * yoffset; 
388         var xshift = 2.0 * (rand() -0.5) * 0.5 * xoffset; 
389         x_var = 0.0; xshift = 0.0;
390
391         for (var j=0; j<nx; j=j+1)
392                 {
393                 var y0 = y + y_var * 2.0 * (rand() -0.5);
394                 var x = xmin + j * (xoffset + i * xinc) + x_var * 2.0 * (rand() -0.5) + spacing_array[j] + und_array[i];
395                 var lat = blat + m_to_lat * (y0 * math.cos(dir) - x * math.sin(dir));
396                 var lon = blon + m_to_lon * (x * math.cos(dir) + y0 * math.sin(dir));
397
398                 var alt = balt + alt_var * 2 * (rand() - 0.5);
399                 
400                 flag = 0;
401                 var strength = 0.0;
402                 var rn = 6.0 * rand();
403
404                 if (((j<jlow) or (j>(nx-jlow-1))) and ((i<ilow) or (i>(ny-ilow-1)))) # select a small or no cloud               
405                         {
406                         if (rn > 2.0) {flag = 1;} else {strength = 0.1 + rand() * 0.5;}
407                         }
408                 if ((j<jlow) or (j>(nx-jlow-1)) or (i<ilow) or (i>(ny-ilow-1)))         
409                         {
410                         if (rn > 5.0) {flag = 1;} else {strength = 0.4 + rand() * 0.5;}
411                         }
412                 else    { # select a large cloud
413                         if (rn > 5.0) {flag = 1;} else {strength = 0.6 + rand() * 0.6;}
414                         }
415
416
417                 if (flag==0){create_detailed_cumulus_cloud(lat, lon, alt, strength); }
418                 }
419
420         } 
421
422 }
423
424
425 ###########################################################
426 # place a cloud layer 
427 ###########################################################
428
429 var create_layer = func (type, blat, blon, balt, bthick, rx, ry, phi, density, edge, rainflag, rain_density) {
430
431
432 var i = 0;
433 var area = math.pi * rx * ry;
434 var circ = math.pi * (rx + ry); # that's just an approximation
435 var n = int(area/80000000.0 * 100 * density);
436 var m = int(circ/63000.0 * 40 * rain_density);
437 var path = "Models/Weather/blank.ac";
438
439 #print("density: ",n);
440
441 phi = phi * math.pi/180.0;
442
443 if (contains(local_weather.cloud_vertical_size_map, type)) 
444                 {var alt_offset = cloud_vertical_size_map[type]/2.0 * m_to_ft;}
445         else {var alt_offset = 0.0;}
446
447 while(i<n)
448         {
449         var x = rx * (2.0 * rand() - 1.0); 
450         var y = ry * (2.0 * rand() - 1.0); 
451         var alt = balt + bthick * rand() + 0.8 * alt_offset;
452         var res = (x*x)/(rx*rx) + (y*y)/(ry*ry);
453
454         if (res < 1.0)
455                 {
456                 var lat = blat + m_to_lat * (y * math.cos(phi) - x * math.sin(phi));
457                 var lon = blon + m_to_lon * (x * math.cos(phi) + y * math.sin(phi));
458                 if (res > ((1.0 - edge) * (1.0- edge)))
459                         {
460                         if (rand() > 0.4) {
461                                 path = select_cloud_model(type,"small");
462                         if (thread_flag == 1)
463                                 {create_cloud_vec(path, lat, lon, alt, 0.0);}
464                         else
465                                 {compat_layer.create_cloud(path, lat, lon, alt, 0.0);}
466                                 }
467                         }
468                 else {
469                         path = select_cloud_model(type,"large");
470                         if (thread_flag == 1)
471                                 {create_cloud_vec(path, lat, lon, alt, 0.0);}
472                         else 
473                                 {compat_layer.create_cloud(path, lat, lon, alt, 0.0);}
474                         }
475                 i = i + 1;
476                 }
477         }
478
479 i = 0;
480
481 if (rainflag ==1){
482
483 if (local_weather.hardcoded_clouds_flag == 1) {balt = balt + local_weather.offset_map[type]; }
484
485         while(i<m)
486                 {
487                 var alpha = rand() * 2.0 * math.pi;
488                 x = 0.8 * (1.0 - edge) * (1.0-edge) * rx * math.cos(alpha);
489                 y = 0.8 * (1.0 - edge) * (1.0-edge) * ry * math.sin(alpha);
490
491                 lat = blat + m_to_lat * (y * math.cos(phi) - x * math.sin(phi));
492                 lon = blon + m_to_lon * (x * math.cos(phi) + y * math.sin(phi));        
493         
494                 path = "Models/Weather/rain1.xml";
495                 if (contains(cloud_vertical_size_map,type)) {var alt_shift = cloud_vertical_size_map[type];}
496                 else {var alt_shift = 0.0;}
497                 
498                 if (thread_flag == 1)
499                 {create_cloud_vec(path, lat, lon,balt +0.5*bthick+ alt_shift, 0.0);}            
500                 else            
501                 {compat_layer.create_cloud(path, lat, lon, balt + 0.5 * bthick + alt_shift, 0.0);}
502                 i = i + 1;
503                 } # end while   
504         } # end if (rainflag ==1)
505 }
506
507
508 ###########################################################
509 # place a Cumulus layer with excluded regions
510 # to avoid placing cumulus underneath a thunderstorm
511 ###########################################################
512
513 var cumulus_exclusion_layer = func (blat, blon, balt, n, size_x, size_y, alpha, s_min, s_max, n_ex, exlat, exlon, exrad) {
514
515
516 var strength = 0;
517 var flag = 1;
518 var phi = alpha * math.pi/180.0;
519
520 var i_max = int(0.35*n);
521
522
523
524 for (var i =0; i< i_max; i=i+1)
525         {
526         var x = (2.0 * rand() - 1.0) * size_x;
527         var y = (2.0 * rand() - 1.0) * size_y; 
528
529         var lat = blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat;
530         var lon = blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon;
531
532         flag = 1;
533
534         for (var j=0; j<n_ex; j=j+1)
535                 {
536                 if (calc_d_sq(lat, lon, exlat[j], exlon[j]) < (exrad[j] * exrad[j])) {flag = 0;}
537                 }
538         if (flag == 1)
539                 {
540                 strength = s_min + rand() * (s_max - s_min);            
541                 create_detailed_cumulus_cloud(lat, lon, balt, strength);
542                 } 
543
544         } # end for i
545
546 }
547