ARTS  2.0.49
cloudbox.cc
Go to the documentation of this file.
1 /* Copyright (C) 2002-2008 Claudia Emde <claudia.emde@dlr.de>
2 
3  This program is free software; you can redistribute it and/or modify it
4  under the terms of the GNU General Public License as published by the
5  Free Software Foundation; either version 2, or (at your option) any
6  later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16  USA.
17 */
18 
27 #include "cloudbox.h"
28 
29 extern const Index GFIELD3_P_GRID;
30 extern const Index GFIELD3_LAT_GRID;
31 extern const Index GFIELD3_LON_GRID;
32 extern const Numeric PI;
33 
34 /*===========================================================================
35  === External declarations
36  ===========================================================================*/
37 #include <stdexcept>
38 #include <cmath>
39 
40 #include "arts.h"
41 #include "messages.h"
42 #include "make_vector.h"
43 #include "logic.h"
44 #include "ppath.h"
45 #include "physics_funcs.h"
46 #include "math_funcs.h"
47 #include "check_input.h"
48 
49 
52 
62 void chk_massdensity_field( bool& empty_flag,
63  const Index& dim,
64  const Tensor3& massdensity,
65  const Vector& p_grid,
66  const Vector& lat_grid,
67  const Vector& lon_grid
68  )
69 {
70 
71  // check p
72  if ( massdensity.npages() != p_grid.nelem()) {
73 
74  ostringstream os;
75  os << "The size of *p_grid* ("
76  << p_grid.nelem()
77  << ") is not equal to the number of pages of *massdensity* ("
78  << massdensity.npages()
79  <<").";
80  throw runtime_error(os.str() );
81  }
82 
83  // check lat
84  if(dim >= 2 )
85  {
86  if ( massdensity.nrows() != lat_grid.nelem()) {
87 
88  ostringstream os;
89  os << "The size of *lat_grid* ("
90  << lat_grid.nelem()
91  << ") is not equal to the number of rows of *massdensity* ("
92  << massdensity
93  << ").";
94  throw runtime_error(os.str() );
95 
96  }
97  }
98 
99  // check lon
100  if(dim == 3 )
101  {
102  if ( massdensity.ncols() != lon_grid.nelem()) {
103 
104  ostringstream os;
105  os << "The size of *lon_grid* ("
106  << lon_grid.nelem()
107  << ") is not equal to the number of columns of *massdensity*"
108  << massdensity
109  << ").";
110  throw runtime_error(os.str() );
111 
112  }
113  }
114 
115  empty_flag = false;
116  // set empty_flag to true if a single value of hydromet_field is unequal zero
117  for (Index j=0; j<massdensity.npages(); j++) {
118  for (Index k=0; k<massdensity.nrows(); k++) {
119  for (Index l=0; l<massdensity.ncols(); l++) {
120  if ( massdensity(j,k,l) != 0.0) empty_flag = true;
121  }
122  }
123  }
124 }
125 
127 
135 void chk_if_pnd_zero_p(const Index& i_p,
136  const GriddedField3& pnd_field_raw,
137  const String& pnd_field_file,
138  const Verbosity& verbosity)
139 
140 {
141  const ConstVectorView pfr_p_grid = pnd_field_raw.get_numeric_grid(GFIELD3_P_GRID);
142  const ConstVectorView pfr_lat_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LAT_GRID);
143  const ConstVectorView pfr_lon_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LON_GRID);
144 
145  for (Index i = 0; i < pfr_lat_grid.nelem(); i++ )
146  {
147  for (Index j = 0; j < pfr_lon_grid.nelem(); j++ )
148  {
149  if ( pnd_field_raw.data(i_p, i, j) != 0. )
150  {
152  ostringstream os;
153  os << "Warning: \n"
154  << "The particle number density field contained in the file '"
155  << pnd_field_file << "'\nis non-zero outside the cloudbox "
156  << "or close the cloudbox boundary at the \n"
157  << "following position:\n"
158  << "pressure = " << pfr_p_grid[i_p]
159  << ", p_index = " << i_p << "\n"
160  << "latitude = " << pfr_lat_grid[i]
161  << ", lat_index = " << i << "\n"
162  << "longitude = " << pfr_lon_grid[j]
163  << ", lon_index = " << j << "\n"
164  << "\n";
165  // throw runtime_error( os.str() );
166  out1 << os.str();
167  }
168  }
169  }
170 }
171 
173 
181 void chk_if_pnd_zero_lat(const Index& i_lat,
182  const GriddedField3& pnd_field_raw,
183  const String& pnd_field_file,
184  const Verbosity& verbosity)
185 
186 {
187  const ConstVectorView pfr_p_grid = pnd_field_raw.get_numeric_grid(GFIELD3_P_GRID);
188  const ConstVectorView pfr_lat_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LAT_GRID);
189  const ConstVectorView pfr_lon_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LON_GRID);
190 
191  for (Index i = 0; i < pfr_p_grid.nelem(); i++ )
192  {
193  for (Index j = 0; j < pfr_lon_grid.nelem(); j++ )
194  {
195  if ( pnd_field_raw.data(i, i_lat, j) != 0. )
196  {
198  ostringstream os;
199  os << "Warning: \n"
200  << "The particle number density field contained in the file '"
201  << pnd_field_file << "'\nis non-zero outside the cloudbox "
202  << "or close the cloudbox boundary at the \n"
203  << "following position:\n"
204  << "pressure = " << pfr_p_grid[i] << ", p_index = "
205  << i << "\n"
206  << "latitude = " << pfr_lat_grid[i_lat]
207  << ", lat_index = "<<i_lat<< "\n"
208  << "longitude = " << pfr_lon_grid[j]
209  << ", lon_index = " << j << "\n"
210  << "\n";
211  //throw runtime_error( os.str() );
212  out1 << os.str();
213  }
214  }
215  }
216 }
217 
219 
227 void chk_if_pnd_zero_lon(const Index& i_lon,
228  const GriddedField3& pnd_field_raw,
229  const String& pnd_field_file,
230  const Verbosity& verbosity)
231 
232 {
233  const ConstVectorView pfr_p_grid = pnd_field_raw.get_numeric_grid(GFIELD3_P_GRID);
234  const ConstVectorView pfr_lat_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LAT_GRID);
235  const ConstVectorView pfr_lon_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LON_GRID);
236 
237  for (Index i = 0; i < pfr_p_grid.nelem(); i++ )
238  {
239  for (Index j = 0; j < pfr_lat_grid.nelem(); j++ )
240  {
241  if ( pnd_field_raw.data(i, j, i_lon) != 0. )
242  {
244  ostringstream os;
245  os << "Warning: \n"
246  << "The particle number density field contained in the file '"
247  << pnd_field_file << "'\nis non-zero outside the cloudbox "
248  << "or close the cloudbox boundary at the \n"
249  << "following position:\n"
250  << "pressure = " << pfr_p_grid[i]
251  << ", p_index = " << i << "\n"
252  << "latitude = " << pfr_lat_grid[j]
253  << ", lat_index = " << j << "\n"
254  << "longitude = " << pfr_lon_grid[i_lon]
255  << ", lon_index = "
256  << i_lon << "\n"
257  << "\n";
258  //throw runtime_error( os.str() );
259  out1 << os.str();
260  }
261  }
262  }
263 }
264 
265 
267 
284  const GriddedField3& pnd_field_raw,
285  const String& pnd_field_file,
286  const Index& atmosphere_dim,
287  ConstVectorView p_grid,
288  ConstVectorView lat_grid,
289  ConstVectorView lon_grid,
290  const ArrayOfIndex& cloudbox_limits,
291  const Verbosity& verbosity)
292 {
294 
295  const ConstVectorView pfr_p_grid = pnd_field_raw.get_numeric_grid(GFIELD3_P_GRID);
296  const ConstVectorView pfr_lat_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LAT_GRID);
297  const ConstVectorView pfr_lon_grid = pnd_field_raw.get_numeric_grid(GFIELD3_LON_GRID);
298 
299  // The consistency of the dimensions is checked in the reading routine.
300  // Here we have to check whether the atmospheric dimension is correct and whether
301  // the particle number density is 0 on the cloudbox boundary and outside the cloudbox.
302 
303  out3 << "Check particle number density file " << pnd_field_file
304  << "\n";
305 
306  Index i_p;
307 
308  // Lower pressure limit
309  for (i_p = 0; pfr_p_grid[i_p] > p_grid[cloudbox_limits[0]]; i_p++)
310  { chk_if_pnd_zero_p(i_p, pnd_field_raw, pnd_field_file, verbosity); }
311  // The first point inside the cloudbox also needs to be zero !!
312  //chk_if_pnd_zero_p(i_p, pnd_field_raw, pnd_field_file);
313 
314  //Upper pressure limit
315  for (i_p = pfr_p_grid.nelem()-1;
316  pfr_p_grid[i_p] < p_grid[cloudbox_limits[1]]; i_p--)
317  { chk_if_pnd_zero_p(i_p, pnd_field_raw, pnd_field_file, verbosity); }
318  //chk_if_pnd_zero_p(i_p, pnd_field_raw, pnd_field_file);
319 
320  if (atmosphere_dim == 1 && (pfr_lat_grid.nelem() != 1
321  || pfr_lon_grid.nelem() != 1) )
322  {
323  ostringstream os;
324  os << "The atmospheric dimension is 1D but the particle "
325  << "number density file * " << pnd_field_file
326  << " is for a 3D atmosphere. \n";
327  throw runtime_error( os.str() );
328  }
329 
330 
331  else if( atmosphere_dim == 3)
332  {
333  if(pfr_lat_grid.nelem() == 1
334  || pfr_lon_grid.nelem() == 1)
335  {
336  ostringstream os;
337  os << "The atmospheric dimension is 3D but the particle "
338  << "number density file * " << pnd_field_file
339  << " is for a 1D or a 2D atmosphere. \n";
340  throw runtime_error( os.str() );
341  }
342 
343  Index i_lat;
344  Index i_lon;
345 
346  // Lower latitude limit
347  for (i_lat = 0; pfr_lat_grid[i_lat] >
348  lat_grid[cloudbox_limits[2]]; i_lat++)
349  { chk_if_pnd_zero_lat(i_lat, pnd_field_raw, pnd_field_file, verbosity); }
350 
351  // The first point inside the cloudbox also needs to be zero !!
352  // chk_if_pnd_zero_lat(i_lat+1, pnd_field_raw, pnd_field_file);
353 
354  //Upper latitude limit
355  for (i_lat = pfr_lat_grid.nelem()-1;
356  pfr_lat_grid[i_lat] < lat_grid[cloudbox_limits[3]];
357  i_lat--)
358  { chk_if_pnd_zero_lat(i_lat, pnd_field_raw, pnd_field_file, verbosity); }
359  //chk_if_pnd_zero_lat(i_lat-1, pnd_field_raw, pnd_field_file, verbosity);
360 
361  // Lower longitude limit
362  for (i_lon = 0; pfr_lon_grid[i_lon] >
363  lon_grid[cloudbox_limits[4]]; i_lon++)
364  { chk_if_pnd_zero_lon(i_lon, pnd_field_raw, pnd_field_file, verbosity); }
365  // The first point inside the cloudbox also needs to be zero !!
366  // chk_if_pnd_zero_lon(i_lon+1, pnd_field_raw, pnd_field_file, verbosity);
367 
368  //Upper longitude limit
369  for (i_lon = pfr_lon_grid.nelem()-1;
370  pfr_lon_grid[i_lon] < lon_grid[cloudbox_limits[5]];
371  i_lon--)
372  { chk_if_pnd_zero_lon(i_lon, pnd_field_raw, pnd_field_file, verbosity); }
373  //chk_if_pnd_zero_lon(i_lon-1, pnd_field_raw, pnd_field_file, verbosity);
374  }
375 
376  out3 << "Particle number density data is o.k. \n";
377 
378 }
379 
381 
395  const ArrayOfGriddedField3& pnd_field_raw,
396  const String& pnd_field_file,
397  const Index& atmosphere_dim,
398  ConstVectorView p_grid,
399  ConstVectorView lat_grid,
400  ConstVectorView lon_grid,
401  const ArrayOfIndex& cloudbox_limits,
402  const Verbosity& verbosity
403  )
404 {
406 
407  for( Index i = 0; i < pnd_field_raw.nelem(); i++)
408  {
409  out3 << "Element in pnd_field_raw_file:" << i << "\n";
410  chk_pnd_data(pnd_field_raw[i],
411  pnd_field_file, atmosphere_dim,
412  p_grid, lat_grid, lon_grid, cloudbox_limits, verbosity);
413  }
414 }
415 
417 
428  const ArrayOfScatteringMetaData& scat_data_meta_array,
429  const Verbosity&)
430 {
431  if (scat_data_raw.nelem() != scat_data_meta_array.nelem())
432  {
433  ostringstream os;
434  os << "The number of elments in *scat_data_raw*\n"
435  << "and *scat_data_meta_array* do not match.\n"
436  << "Each SingleScattering file must correspond\n"
437  << "to one ScatteringMeta data file.";
438  throw runtime_error( os.str());
439  }
440 
441 }
442 
444 
454 void chk_scattering_meta_data(const ScatteringMetaData& scat_data_meta,
455  const String& scat_data_meta_file,
456  const Verbosity& verbosity)
457 {
459  out2 << " Check scattering meta properties file "<< scat_data_meta_file << "\n";
460 
461  if (scat_data_meta.type != "Ice" && scat_data_meta.type != "Water" && scat_data_meta.type != "Aerosol")
462  {
463  ostringstream os;
464  os << "Type in " << scat_data_meta_file << " must be 'Ice', 'Water' or 'Aerosol'\n";
465  throw runtime_error( os.str() );
466  }
467  //(more) checks need to be included
468 }
469 
470 
472 
487  const String& scat_data_file,
488  ConstVectorView f_grid,
489  const Verbosity& verbosity)
490 {
492  out2 << " Check single scattering properties file "<< scat_data_file
493  << "\n";
494 
495  if (scat_data_raw.ptype != 10 &&
496  scat_data_raw.ptype != 20 &&
497  scat_data_raw.ptype != 30)
498  {
499  ostringstream os;
500  os << "Ptype value in file" << scat_data_file << "is wrong."
501  << "It must be \n"
502  << "10 - arbitrary oriented particles \n"
503  << "20 - randomly oriented particles or \n"
504  << "30 - horizontally aligned particles.\n";
505  throw runtime_error( os.str() );
506  }
507 
508  chk_interpolation_grids("scat_data_raw.f_grid to f_grid",
509  scat_data_raw.f_grid,
510  f_grid);
511 
512 /* if (!(scat_data_raw.f_grid[0] <= f_grid[0] &&
513  last(f_grid) <=
514  last(scat_data_raw.f_grid) ))
515  {
516  ostringstream os;
517  os << "The range of frequency grid in the single scattering"
518  << " properties datafile "
519  << scat_data_file << " does not contain all values of"
520  << "*f_grid*.";
521  throw runtime_error( os.str() );
522  }*/
523 
524  // Here we only check whether the temperature grid is of the unit K, not
525  // whether it corresponds to the required values it T_field. The second
526  // option is not trivial since here one has to look whether the pnd_field
527  // is none zero for the corresponding temperature. This check done in the
528  // functions where the multiplication with the particle number density is
529  // done.
530 
531  if (!(0. < scat_data_raw.T_grid[0] && last(scat_data_raw.T_grid) < 1001.))
532  {
533  ostringstream os;
534  os << "The temperature values in " << scat_data_file
535  << " are negative or very large. Check whether you have used the "
536  << "right unit [Kelvin].";
537  throw runtime_error( os.str() );
538  }
539 
540  if (scat_data_raw.za_grid[0] != 0.)
541  {
542  ostringstream os;
543  os << "The first value of the za grid in the single"
544  << " scattering properties datafile "
545  << scat_data_file << " must be 0.";
546  throw runtime_error( os.str() );
547  }
548 
549  if (last(scat_data_raw.za_grid) != 180.)
550  {
551  ostringstream os;
552  os << "The last value of the za grid in the single"
553  << " scattering properties datafile "
554  << scat_data_file << " must be 180.";
555  throw runtime_error( os.str() );
556  }
557 
558  if (scat_data_raw.ptype == 10 && scat_data_raw.aa_grid[0] != -180.)
559  {
560  ostringstream os;
561  os << "For ptype = 10 (general orientation) the first value"
562  << " of the aa grid in the single scattering"
563  << " properties datafile "
564  << scat_data_file << "must be -180.";
565  throw runtime_error( os.str() );
566  }
567 
568  if (scat_data_raw.ptype == 30 && scat_data_raw.aa_grid[0] != 0.)
569  {
570  ostringstream os;
571  os << "For ptype = 30 (horizontal orientation)"
572  << " the first value"
573  << " of the aa grid in the single scattering"
574  << " properties datafile "
575  << scat_data_file << "must be 0.";
576  throw runtime_error( os.str() );
577  }
578 
579  if (scat_data_raw.ptype == 30 && last(scat_data_raw.aa_grid) != 180.)
580  {
581  ostringstream os;
582  os << "The last value of the aa grid in the single"
583  << " scattering properties datafile "
584  << scat_data_file << " must be 180.";
585  throw runtime_error( os.str() );
586  }
587 
588  ostringstream os_pha_mat;
589  os_pha_mat << "pha_mat* in the file *" << scat_data_file;
590  ostringstream os_ext_mat;
591  os_ext_mat << "ext_mat* in the file * " << scat_data_file;
592  ostringstream os_abs_vec;
593  os_abs_vec << "abs_vec* in the file * " << scat_data_file;
594 
595  switch (scat_data_raw.ptype){
596 
598 
599  out2 << " Datafile is for arbitrarily orientated particles. \n";
600 
601  chk_size(os_pha_mat.str(), scat_data_raw.pha_mat_data,
602  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
603  scat_data_raw.za_grid.nelem(), scat_data_raw.aa_grid.nelem(),
604  scat_data_raw.za_grid.nelem(), scat_data_raw.aa_grid.nelem(),
605  16);
606 
607  chk_size(os_ext_mat.str(), scat_data_raw.ext_mat_data,
608  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
609  scat_data_raw.za_grid.nelem(), scat_data_raw.aa_grid.nelem(),
610  7);
611 
612  chk_size(os_abs_vec.str(), scat_data_raw.abs_vec_data,
613  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
614  scat_data_raw.za_grid.nelem(), scat_data_raw.aa_grid.nelem(),
615  4);
616  break;
617 
619 
620  out2 << " Datafile is for randomly oriented particles, i.e., "
621  << "macroscopically isotropic and mirror-symmetric scattering "
622  << "media. \n";
623 
624  chk_size(os_pha_mat.str(), scat_data_raw.pha_mat_data,
625  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
626  scat_data_raw.za_grid.nelem(), 1, 1, 1, 6);
627 
628  chk_size(os_ext_mat.str(), scat_data_raw.ext_mat_data,
629  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
630  1, 1, 1);
631 
632  chk_size(os_abs_vec.str(), scat_data_raw.abs_vec_data,
633  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
634  1, 1, 1);
635  break;
636 
638 
639  out2 << " Datafile is for horizontally aligned particles. \n";
640 
641  chk_size(os_pha_mat.str(), scat_data_raw.pha_mat_data,
642  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
643  scat_data_raw.za_grid.nelem(), scat_data_raw.aa_grid.nelem(),
644  scat_data_raw.za_grid.nelem()/2+1, 1,
645  16);
646 
647  chk_size(os_ext_mat.str(), scat_data_raw.ext_mat_data,
648  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
649  scat_data_raw.za_grid.nelem()/2+1, 1,
650  3);
651 
652  chk_size(os_abs_vec.str(), scat_data_raw.abs_vec_data,
653  scat_data_raw.f_grid.nelem(), scat_data_raw.T_grid.nelem(),
654  scat_data_raw.za_grid.nelem()/2+1, 1,
655  2);
656  break;
657 
659  throw runtime_error(
660  "Special case for spherical particles not"
661  "implemented."
662  "Use p20 (randomly oriented particles) instead."
663  );
664 
665  }
666 
667 }
668 
669 
670 
671 
672 
690  const GridPos& gp_lat,
691  const GridPos& gp_lon,
692  const ArrayOfIndex& cloudbox_limits,
693  const bool include_boundaries)
694 
695 {
696  bool result=true;
697  // Pressure dimension
698  double ipos = fractional_gp( gp_p );
699  if (include_boundaries){
700  if( ipos < double( cloudbox_limits[0] ) ||
701  ipos > double( cloudbox_limits[1] ) )
702  { result=false; }
703 
704  else {
705  // Latitude dimension
706  ipos = fractional_gp( gp_lat );
707  if( ipos < double( cloudbox_limits[2] ) ||
708  ipos > double( cloudbox_limits[3] ) )
709  { result=false; }
710 
711  else
712  {
713  // Longitude dimension
714  ipos = fractional_gp( gp_lon );
715  if( ipos < double( cloudbox_limits[4] ) ||
716  ipos > double( cloudbox_limits[5] ) )
717  { result=false; }
718  }
719  }
720  }
721  else
722  {
723  if( ipos <= double( cloudbox_limits[0] ) ||
724  ipos >= double( cloudbox_limits[1] ) )
725  { result=false; }
726 
727  else {
728  // Latitude dimension
729  ipos = fractional_gp( gp_lat );
730  if( ipos <= double( cloudbox_limits[2] ) ||
731  ipos >= double( cloudbox_limits[3] ) )
732  { result=false; }
733 
734  else
735  {
736  // Longitude dimension
737  ipos = fractional_gp( gp_lon );
738  if( ipos <= double( cloudbox_limits[4] ) ||
739  ipos >= double( cloudbox_limits[5] ) )
740  { result=false; }
741  }
742  }
743  }
744  return result;
745 
746 }
747 
748 
764 bool is_inside_cloudbox(const Ppath& ppath_step,
765  const ArrayOfIndex& cloudbox_limits,
766  const bool include_boundaries)
767 
768 {
769  const Index np=ppath_step.np;
770 
771  return is_gp_inside_cloudbox(ppath_step.gp_p[np-1],ppath_step.gp_lat[np-1],
772  ppath_step.gp_lon[np-1],cloudbox_limits,include_boundaries);
773 
774 }
775 
787  //input
788  const Numeric& p,
789  const Numeric& dh
790  )
791 
792 {
793  /* taken from: Seite „Barometrische Höhenformel“. In: Wikipedia,
794  * Die freie Enzyklopädie. Bearbeitungsstand: 3. April 2011, 20:28 UTC.
795  * URL: http://de.wikipedia.org/w/index.php?title=Barometrische_H%C3%B6henformel&oldid=87257486
796  * (Abgerufen: 15. April 2011, 15:41 UTC)
797  */
798 
799 
800  //barometric height formula
801  Numeric M = 0.02896; //mean molar mass of air [kg mol^-1]
802  Numeric g = 9.807; //earth acceleration [kg m s^-1]
803  Numeric R = 8.314; //universal gas constant [J K^−1 mol^−1]
804  Numeric T = 253; //median tropospheric reference temperature [K]
805 
806  // calculation
807  Numeric p1 = p * exp(-(-dh)/(R*T/(M*g)));
808 
809  return p1;
810 
811 }
812 
829  const Numeric dm,
830  const Numeric t,
831  const Numeric density)
832 {
833  // skip calculation if IWC is 0.0
834  if ( iwc == 0.0 )
835  {
836  return 0.0;
837  }
838  Numeric dN1;
839  Numeric dN2;
840  Numeric dN;
841  // convert m to microns
842  Numeric Dm = dm * 1e6;
843  //convert T from Kelvin to Celsius
844  Numeric T = t-273.15;
845  //split IWC in IWCs100 and IWCl100
846  Numeric a=0.252; //g/m^3
847  Numeric b1=0.837;
848  Numeric IWC0=1; //g/m^3
849  Numeric IWCs100=min ( iwc,a*pow ( iwc/IWC0,b1 ) );
850  Numeric IWCl100=iwc-IWCs100;
851 
852 
853  //Gamma distribution component
854 
855  Numeric b2=-4.99*1e-3; //micron^-1
856  Numeric m=0.0494; //micron^-1
857  Numeric alphas100=b2-m*log10 ( IWCs100/IWC0 ); //micron^-1
858  // for large IWC alpha, hence dN1, goes negative. avoid that.
859  // towards this limit, particles anyway get larger 100um, i.e.,
860  // outside the size region gamma distrib is intended for
861  if (alphas100>0.)
862  {
863  Numeric Ns100=6*IWCs100*pow ( alphas100,5. ) / ( PI*density*gamma_func ( 5. ) );//micron^-5
864  Numeric Nm1=Ns100*Dm*exp ( -alphas100*Dm ); //micron^-4
865  dN1 = Nm1*1e18; // m^-3 micron^-1
866  }
867  else
868  {
869  dN1 = 0.;
870  }
871 
872 
873 
874  //Log normal distribution component
875 
876  // for small IWC, IWCtotal==IWC<100 & IWC>100=0.
877  // this will give dN2=NaN. avoid that by explicitly setting to 0
878  if (IWCl100>0.)
879  {
880  Numeric aamu=5.20;
881  Numeric bamu=0.0013;
882  Numeric abmu=0.026;
883  Numeric bbmu=-1.2*1e-3;
884  Numeric amu=aamu+bamu*T;
885  Numeric bmu=abmu+bbmu*T;
886  Numeric mul100=amu+bmu*log10 ( IWCl100/IWC0 );
887 
888  Numeric aasigma=0.47;
889  Numeric basigma=2.1*1e-3;
890  Numeric absigma=0.018;
891  Numeric bbsigma=-2.1*1e-4;
892  Numeric asigma=aasigma+basigma*T;
893  Numeric bsigma=absigma+bbsigma*T;
894  Numeric sigmal100=asigma+bsigma*log10 ( IWCl100/IWC0 );
895 
896  Numeric D0=1.0; //micron
897  Numeric a1=6*IWCl100; //g/m^3
898  Numeric a2=pow ( PI,3./2. ) *density*sqrt ( 2 ) *exp ( 3*mul100+9./2.*pow ( sigmal100,2 ) ) *sigmal100*pow ( D0,3 ) *Dm; //g/m^3/micron^4
899  Numeric Nm2=a1/a2*exp ( -0.5*pow ( ( log ( Dm/D0 )-mul100 ) /sigmal100,2 ) ); //micron^-4
900  dN2 = Nm2*1e18; // m^-3 micron^-1
901  }
902  else
903  {
904  dN2 = 0.;
905  }
906 
907 
908 
909  dN = ( dN1+dN2 ) *1e6; // m^-3 m^-1
910  if (isnan(dN)) dN = 0.0;
911  return dN;
912 }
913 
927 Numeric psd_H11 ( const Numeric xwc,
928  const Numeric d,
929  const Numeric t)
930 {
931  // skip calculation if LWC is 0.0
932  if ( xwc == 0.0 )
933  {
934  return 0.0;
935  }
936 
937  Numeric dN;
938  Numeric la;
939  Numeric mu;
940  // convert m to cm
941  Numeric D = d * 1e2;
942  //convert T from Kelvin to Celsius
943  Numeric T = t-273.15;
944  //choose parametrization depending on T
945  if ( T >= -56. )
946  {
947  la= 12.13 * exp( -0.055*T );
948  }
949  else
950  {
951  la= 0.83 * exp( -0.103*T );
952  }
953  if ( T >= -68. )
954  {
955  mu= -0.57 - 0.028*T;
956  }
957  else
958  {
959  mu= -30.93 - 0.472*T;
960  }
961 
962  //Distribution function H11
963 
964  dN = pow( D, mu ) * exp ( -la * D );
965 
966  if (isnan(dN)) dN = 0.0;
967  return dN;
968 }
969 
983 Numeric LWCtopnd (const Numeric lwc, //[g/m^3]
984  //const Numeric density,
985  const Numeric r // [m]
986  )
987 {
988  // skip calculation if LWC is 0.0
989  if ( lwc == 0.0 )
990  {
991  return 0.0;
992  }
993  Numeric rc = 4.7; //[micron]
994  Numeric alpha = 5.0;
995  Numeric gam = 1.05;
996 
997  Numeric B=(alpha/gam)/pow(rc,gam);
998  // factor 1e12 is density of water [1 g/cm^3] in units of [g/micron^3]
999  Numeric A=(((3*lwc*gam*pow(B,((alpha+4)/gam))*1e12)/4)/PI)/gamma_func((alpha+4)/gam);
1000  Numeric n=A*(pow(r*1e6,alpha)*exp(-B*pow(r*1e6,gam)))*1e6; //
1001  // n in [# m^-3 m^-1]
1002 
1003  if (isnan(n)) n = 0.0;
1004  return n;
1005 }
1006 
1007 // ONLY FOR TESTING PURPOSES
1008 Numeric LWCtopnd2 (//const Numeric vol, //[g/m^3]
1009  //const Numeric density,
1010  const Numeric r // [m]
1011  )
1012 {
1013  Numeric rc = 4.7; //micron
1014  Numeric alpha = 5.0;
1015  Numeric gam = 1.05;
1016 
1017  Numeric B=(alpha/gam)/pow(rc,gam);
1018  Numeric A=gam*pow(B,((alpha+1)/gam))/gamma_func((alpha+1)/gam);
1019  Numeric n=A*(pow(r*1e6,alpha)*exp(-B*pow(r*1e6,gam)))*1e6;
1020  // [# m^-3 m^-1]
1021 
1022  if (isnan(n)) n = 0.0;
1023  return n;
1024 }
1025 
1026 
1040 void scale_pnd ( Vector& w,
1041  const Vector& x,
1042  const Vector& y)
1043 {
1044  // check if vectors have same size
1045  if (x.nelem() != y.nelem())
1046  {
1047  throw std::logic_error("x and y must be the same size");
1048  }
1049 
1050  // calc. weights (derived from trapezoid integration)
1051  for (Index i = 0; i<x.nelem(); i++)
1052  {
1053  if (i == 0) // first value
1054  {
1055  w[i] = 0.5*(x[i+1]-x[i])*y[i]; // m^-3
1056  }
1057  else if (i == x.nelem()-1) //last value
1058  {
1059  w[i] = 0.5*(x[i]-x[i-1])*y[i]; // m^-3
1060  }
1061  else { // all values inbetween
1062  w[i] = 0.5*(x[i+1]-x[i-1])*y[i]; // m^-3
1063  }
1064  }
1065 
1066 }
1067 
1080 void chk_pndsum (Vector& pnd,
1081  const Numeric xwc,
1082  const Vector& vol,
1083  const Vector& density,
1084  const Index& p,
1085  const Index& lat,
1086  const Index& lon,
1087  const Verbosity& verbosity)
1088 
1089 {
1090  CREATE_OUT2
1091 
1092  // set vector x to pnd size
1093  Vector x ( pnd.nelem(), 0.0 );
1094  Numeric error;
1095 
1096  for ( Index i = 0; i<pnd.nelem(); i++ )
1097  {
1098  // convert from particles/m^3 to g/m^3
1099  x[i] = pnd[i]*density[i]*vol[i];
1100  //out0<<x[i]<<"\n"<< pnd[i]<< "\n";
1101  }
1102 
1103  //cout<<"at p = "<<p<<", lat = "<<lat<<", lon = "<<lon
1104  //<<" given mass density: "<<xwc<<", calc mass density: "<<x.sum();
1105  if ( x.sum() == 0.0 )
1106  if ( xwc == 0.0 )
1107  {
1108  // set error and all pnd values to zero, IF there is
1109  // no scattering particles at this atmospheric level.
1110  error = 0.0;
1111  pnd = 0.0;
1112  }
1113  else
1114  { // when x.sum()==0, but xwc!=0, obviously something went wrong in pnd calc
1115  ostringstream os;
1116  os<< "ERROR: in WSM chk_pndsum in pnd_fieldSetup!\n"
1117  << "Given mass density != 0, but calculated mass density == 0.\n"
1118  << "Seems, something went wrong in pnd_fieldSetup. Check!\n"
1119  << "The problem occured at: p = "<<p<<", lat = "<<lat<<", lon = "<<lon<<".\n";
1120  throw runtime_error ( os.str() );
1121  }
1122  else
1123  {
1124  error = xwc/x.sum();
1125  // correct all pnd values with error
1126  pnd *= error;
1127  // give warning if deviations are more than 10%
1128  if ( error > 1.10 || error < 0.90 )
1129  {
1130  CREATE_OUT1
1131  //ostringstream os;
1132  out1<< "WARNING: in WSM chk_pndsum in pnd_fieldSetup!\n"
1133  << "The deviation of the sum of nodes in the particle size distribution\n"
1134  << "to the initial input mass density (IWC/LWC) is larger than 10%!\n"
1135  << "The deviation of: "<< error-1.0<<" occured in the atmospheric level: p = "<<p<<", lat = "<<lat<<", lon = "<<lon<<".\n";
1136  //cerr<<os;
1137  }
1138  }
1139  //cout<<", error: "<<error<<"corrected to: "<<x.sum()*error<<"\n";
1140 
1141  out2 << "PND scaling factor in atm. level (p = "<<p<<", lat = "<<lat<<", lon = "<<lon<<"): "<< error <<"\n";
1142  //cout<<"\npnd_scaled\t"<<pnd<<endl;
1143  //cout<<"\nPND\t"<<pnd.sum()<<"\nXWC\t"<<xwc<<"\nerror\t"<<error<<endl;
1144  //cout<<"\n"<<x.sum()<<"\n"<<xwc<<"\n"<<error<<endl;
1145 }
1146 
1158 void scale_H11 (Vector& pnd,
1159  const Numeric xwc,
1160  const Vector& density,
1161  const Vector& vol)
1162  // const Index& p,
1163  // const Index& lat,
1164  // const Index& lon,
1165  // const Verbosity& verbosity)
1166 
1167 {
1168  // set vector x to pnd size
1169  Vector x (pnd.nelem(), 0.0);
1170  Numeric ratio;
1171 
1172  for ( Index i = 0; i<pnd.nelem(); i++ )
1173  {
1174  // convert from particles/m^3 to g/m^3
1175  x[i] = pnd[i]*density[i]*vol[i];
1176  //out0<<x[i]<<"\n"<< pnd[i]<< "\n";
1177  }
1178 
1179  if ( x.sum() == 0.0 )
1180  {
1181  // set ratio and all pnd values to zero, IF there are
1182  // no scattering particles at this atmospheric level.
1183  ratio = 0.0;
1184  pnd = 0.0;
1185  }
1186  else
1187  {
1188  // calculate the ratio of initial massdensity (xwc) to sum of pnds
1189  ratio = xwc/x.sum();
1190  // scale each pnd to represent the total massdensity
1191  pnd *= ratio;
1192  }
1193 
1194 }
1195 
1205 void parse_part_type (//WS Output:
1206  String& part_type,
1207  // WS Input:
1208  const String& part_string)
1209 {
1210 
1211  ArrayOfString strarr;
1212 
1213  // split part_species string at "-" and write to ArrayOfString
1214  part_string.split ( strarr, "-" );
1215 
1216  //first entry is hydrometeor type (e.g. "IWC", "LWC" etc.)
1217  part_type = strarr[0];
1218 
1219  if ( part_type != "IWC" &&
1220  part_type != "Snow" &&
1221  part_type != "LWC" &&
1222  part_type != "Rain" )
1223  {
1224  ostringstream os;
1225  os << "First substring in " << part_string << " must be rather 'LWC', 'IWC', 'Rain' or 'Snow'\n"
1226  <<"Ckeck input in *part_species*!\n";
1227  throw runtime_error ( os.str() );
1228  }
1229 }
1230 
1231 
1240 void parse_psd_param (//WS Output:
1241  String& psd_param,
1242  // WS Input:
1243  const String& part_string)
1244 {
1245  ArrayOfString strarr;
1246 
1247  // split part_species string at "-" and write to ArrayOfString
1248  part_string.split ( strarr, "-" );
1249  // second entry is particle size distribution parametrisation ( e.g."MH97")
1250  psd_param = strarr[1];
1251 
1252  if ( psd_param != "MH97" && psd_param != "liquid" && psd_param != "H11" )
1253  {
1254  ostringstream os;
1255  os <<"The chosen PSD parametrisation in " << part_string << " can not be handeled in the moment.\n"
1256  <<"Choose either 'MH97', 'H11' or 'liquid'!\n" ;
1257  throw runtime_error ( os.str() );
1258  }
1259 }
1260 
1270 void parse_part_size (//WS Output:
1271  Numeric& sizemin,
1272  Numeric& sizemax,
1273  // WS Input:
1274  const String& part_string)
1275 {
1276  ArrayOfString strarr;
1277 
1278  // split part_species string at "-" and write to ArrayOfString
1279  part_string.split ( strarr, "-" );
1280 
1281  // convert String for size range, into Numeric
1282  // 1. third entry is minimum particle radius
1283  if ( strarr.nelem() < 3 || strarr[2] == "*" )
1284  {
1285  sizemin = 0.;
1286  }
1287  else
1288  {
1289  istringstream os1 ( strarr[2] );
1290  os1 >> sizemin;
1291  }
1292  // 2. fourth entry is maximum particle radius
1293  if ( strarr.nelem() < 4 || strarr[3] == "*" )
1294  {
1295  sizemax = -1.;
1296  }
1297  else
1298  {
1299  istringstream os2 ( strarr[3] );
1300  os2 >> sizemax;
1301  }
1302 
1303 }
chk_pndsum
void chk_pndsum(Vector &pnd, const Numeric xwc, const Vector &vol, const Vector &density, const Index &p, const Index &lat, const Index &lon, const Verbosity &verbosity)
Definition: cloudbox.cc:1080
psd_H11
Numeric psd_H11(const Numeric xwc, const Numeric d, const Numeric t)
Definition: cloudbox.cc:927
scale_pnd
void scale_pnd(Vector &w, const Vector &x, const Vector &y)
Definition: cloudbox.cc:1040
SingleScatteringData::za_grid
Vector za_grid
Definition: optproperties.h:79
PARTICLE_TYPE_GENERAL
@ PARTICLE_TYPE_GENERAL
Definition: optproperties.h:56
GFIELD3_P_GRID
const Index GFIELD3_P_GRID
SingleScatteringData::f_grid
Vector f_grid
Definition: optproperties.h:77
Tensor3
The Tensor3 class.
Definition: matpackIII.h:340
chk_scattering_meta_data
void chk_scattering_meta_data(const ScatteringMetaData &scat_data_meta, const String &scat_data_meta_file, const Verbosity &verbosity)
Check scattering data meta files.
Definition: cloudbox.cc:454
last
Numeric last(ConstVectorView x)
last
Definition: math_funcs.cc:183
SingleScatteringData::ptype
ParticleType ptype
Definition: optproperties.h:75
is_gp_inside_cloudbox
bool is_gp_inside_cloudbox(const GridPos &gp_p, const GridPos &gp_lat, const GridPos &gp_lon, const ArrayOfIndex &cloudbox_limits, const bool include_boundaries)
Definition: cloudbox.cc:689
SingleScatteringData::aa_grid
Vector aa_grid
Definition: optproperties.h:80
PARTICLE_TYPE_MACROS_ISO
@ PARTICLE_TYPE_MACROS_ISO
Definition: optproperties.h:57
PARTICLE_TYPE_SPHERICAL
@ PARTICLE_TYPE_SPHERICAL
Definition: optproperties.h:59
fractional_gp
Numeric fractional_gp(const GridPos &gp)
fractional_gp
Definition: interpolation.cc:504
CREATE_OUT2
#define CREATE_OUT2
Definition: messages.h:207
GriddedField::get_numeric_grid
ConstVectorView get_numeric_grid(Index i) const
Get a numeric grid.
Definition: gridded_fields.cc:91
Ppath
The structure to describe a propagation path and releated quantities.
Definition: ppath.h:59
Ppath::gp_p
ArrayOfGridPos gp_p
Definition: ppath.h:66
CREATE_OUT1
#define CREATE_OUT1
Definition: messages.h:206
GriddedField3
Definition: gridded_fields.h:274
SingleScatteringData
Structure which describes the single scattering properties of a.
Definition: optproperties.h:74
ConstTensor3View::npages
Index npages() const
Returns the number of pages.
Definition: matpackIII.h:151
chk_scattering_data
void chk_scattering_data(const ArrayOfSingleScatteringData &scat_data_raw, const ArrayOfScatteringMetaData &scat_data_meta_array, const Verbosity &)
Check scattering data general.
Definition: cloudbox.cc:427
parse_part_size
void parse_part_size(Numeric &sizemin, Numeric &sizemax, const String &part_string)
Definition: cloudbox.cc:1270
Array< Index >
GriddedField3::data
Tensor3 data
Definition: gridded_fields.h:323
CREATE_OUT3
#define CREATE_OUT3
Definition: messages.h:208
Ppath::gp_lat
ArrayOfGridPos gp_lat
Definition: ppath.h:67
scale_H11
void scale_H11(Vector &pnd, const Numeric xwc, const Vector &density, const Vector &vol)
Definition: cloudbox.cc:1158
messages.h
Declarations having to do with the four output streams.
LWCtopnd
Numeric LWCtopnd(const Numeric lwc, const Numeric r)
Definition: cloudbox.cc:983
my_basic_string
The implementation for String, the ARTS string class.
Definition: mystring.h:62
ScatteringMetaData
Definition: optproperties.h:99
SingleScatteringData::ext_mat_data
Tensor5 ext_mat_data
Definition: optproperties.h:82
GFIELD3_LON_GRID
const Index GFIELD3_LON_GRID
Ppath::gp_lon
ArrayOfGridPos gp_lon
Definition: ppath.h:68
Ppath::np
Index np
Definition: ppath.h:61
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:175
is_inside_cloudbox
bool is_inside_cloudbox(const Ppath &ppath_step, const ArrayOfIndex &cloudbox_limits, const bool include_boundaries)
Definition: cloudbox.cc:764
chk_if_pnd_zero_p
void chk_if_pnd_zero_p(const Index &i_p, const GriddedField3 &pnd_field_raw, const String &pnd_field_file, const Verbosity &verbosity)
Check whether particle number density is zero at a specified pressure level.
Definition: cloudbox.cc:135
physics_funcs.h
ConstVectorView::sum
Numeric sum() const
The sum of all elements of a Vector.
Definition: matpackI.cc:181
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Verbosity
Definition: messages.h:50
parse_psd_param
void parse_psd_param(String &psd_param, const String &part_string)
Definition: cloudbox.cc:1240
chk_pnd_data
void chk_pnd_data(const GriddedField3 &pnd_field_raw, const String &pnd_field_file, const Index &atmosphere_dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid, const ArrayOfIndex &cloudbox_limits, const Verbosity &verbosity)
Check particle number density files.
Definition: cloudbox.cc:283
math_funcs.h
make_vector.h
The class MakeVector is a special kind of Vector that can be initialized explicitly from one or more ...
IWCtopnd_MH97
Numeric IWCtopnd_MH97(const Numeric iwc, const Numeric dm, const Numeric t, const Numeric density)
Definition: cloudbox.cc:828
gamma_func
Numeric gamma_func(Numeric xx)
Gamma Function.
Definition: math_funcs.cc:497
ConstTensor3View::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackIII.h:154
cloudbox.h
Internal cloudbox functions.
my_basic_string::split
void split(Array< my_basic_string< charT > > &aos, const my_basic_string< charT > &delim) const
Split string into substrings.
Definition: mystring.h:223
GridPos
Structure to store a grid position.
Definition: interpolation.h:74
ppath.h
Propagation path structure and functions.
LWCtopnd2
Numeric LWCtopnd2(const Numeric r)
Definition: cloudbox.cc:1008
logic.h
Header file for logic.cc.
chk_if_pnd_zero_lat
void chk_if_pnd_zero_lat(const Index &i_lat, const GriddedField3 &pnd_field_raw, const String &pnd_field_file, const Verbosity &verbosity)
Check whether particle number density is zero at a specified latitude.
Definition: cloudbox.cc:181
ConstTensor3View::ncols
Index ncols() const
Returns the number of columns.
Definition: matpackIII.h:157
min
#define min(a, b)
Definition: continua.cc:13096
GFIELD3_LAT_GRID
const Index GFIELD3_LAT_GRID
chk_single_scattering_data
void chk_single_scattering_data(const SingleScatteringData &scat_data_raw, const String &scat_data_file, ConstVectorView f_grid, const Verbosity &verbosity)
Check single scattering data files.
Definition: cloudbox.cc:486
PARTICLE_TYPE_HORIZ_AL
@ PARTICLE_TYPE_HORIZ_AL
Definition: optproperties.h:58
SingleScatteringData::abs_vec_data
Tensor5 abs_vec_data
Definition: optproperties.h:83
PI
const Numeric PI
chk_if_pnd_zero_lon
void chk_if_pnd_zero_lon(const Index &i_lon, const GriddedField3 &pnd_field_raw, const String &pnd_field_file, const Verbosity &verbosity)
Check whether particle number density is zero at a specified longitude.
Definition: cloudbox.cc:227
chk_pnd_raw_data
void chk_pnd_raw_data(const ArrayOfGriddedField3 &pnd_field_raw, const String &pnd_field_file, const Index &atmosphere_dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid, const ArrayOfIndex &cloudbox_limits, const Verbosity &verbosity)
Check particle number density files (pnd_field_raw)
Definition: cloudbox.cc:394
chk_size
void chk_size(const String &x_name, ConstVectorView x, const Index &c)
Runtime check for size of Vector.
Definition: check_input.cc:911
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
check_input.h
M
#define M
Definition: rng.cc:196
ScatteringMetaData::type
String type
Definition: optproperties.h:101
Vector
The Vector class.
Definition: matpackI.h:555
SingleScatteringData::pha_mat_data
Tensor7 pha_mat_data
Definition: optproperties.h:81
ConstVectorView
A constant view of a Vector.
Definition: matpackI.h:300
SingleScatteringData::T_grid
Vector T_grid
Definition: optproperties.h:78
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:172
chk_massdensity_field
void chk_massdensity_field(bool &empty_flag, const Index &dim, const Tensor3 &massdensity, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid)
Check whether hydromet grid size is equal to atmospheric grid size and if hydromet profile is zero (n...
Definition: cloudbox.cc:62
parse_part_type
void parse_part_type(String &part_type, const String &part_string)
Definition: cloudbox.cc:1205
arts.h
The global header file for ARTS.
chk_interpolation_grids
void chk_interpolation_grids(const String &which_interpolation, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
Check interpolation grids.
Definition: check_input.cc:390
barometric_heightformula
Numeric barometric_heightformula(const Numeric &p, const Numeric &dh)
Definition: cloudbox.cc:786