77 for (
Index iD = 0; iD < nD; iD++) d_um[iD] = 1e6 * diameter[iD];
85 Numeric sig_a = 0., sig_b1 = 0.;
86 Numeric sig_b2 = 0., sig_m = 0.;
87 Numeric sig_aamu = 0., sig_bamu = 0.;
88 Numeric sig_abmu = 0., sig_bbmu = 0.;
89 Numeric sig_aasigma = 0., sig_basigma = 0;
90 Numeric sig_absigma = 0., sig_bbsigma = 0.;
98 sig_a = 0.068, sig_b1 = 0.054;
99 sig_b2 = 5.5e-3, sig_m = 0.0029;
100 sig_aamu = 0.02, sig_bamu = 0.0005;
101 sig_abmu = 0.023, sig_bbmu = 0.5e-3;
102 sig_aasigma = 0.02, sig_basigma = 0.5e-3;
103 sig_absigma = 0.023, sig_bbsigma = 4.7e-4;
125 Numeric IWCl100 = ciwc - IWCs100;
131 Numeric alphas100 =
b2 - m * log10(IWCs100);
141 if (alphas100 > 0.) {
142 Numeric Ns100 = 6 * IWCs100 *
pow(alphas100, 5.) /
143 (
PI * cdensity * tgamma(5.));
144 for (
Index iD = 0; iD < nD; iD++)
145 dNdD1[iD] = 1e18 * Ns100 * d_um[iD] *
146 exp(-alphas100 * d_um[iD]);
157 Numeric aamu = 5.20 + sig_aamu;
158 Numeric bamu = 0.0013 + sig_bamu;
159 Numeric abmu = 0.026 + sig_abmu;
160 Numeric bbmu = -1.2e-3 + sig_bbmu;
161 Numeric amu = aamu + bamu * Tc;
162 Numeric bmu = abmu + bbmu * Tc;
163 Numeric mul100 = amu + bmu * log10(IWCl100);
165 Numeric aasigma = 0.47 + sig_aasigma;
166 Numeric basigma = 2.1e-3 + sig_basigma;
167 Numeric absigma = 0.018 + sig_absigma;
168 Numeric bbsigma = -2.1e-4 + sig_bbsigma;
169 Numeric asigma = aasigma + basigma * Tc;
170 Numeric bsigma = absigma + bbsigma * Tc;
171 Numeric sigmal100 = asigma + bsigma * log10(IWCl100);
173 if ((mul100 > 0.) & (sigmal100 > 0.)) {
176 exp(3 * mul100 + 9. / 2. *
pow(sigmal100, 2)) *
177 sigmal100 *
pow(1., 3);
179 for (
Index iD = 0; iD < nD; iD++)
180 dNdD2[iD] = 1e18 *
a1 / (a2_fac * d_um[iD]) *
181 exp(-0.5 *
pow((log(d_um[iD]) - mul100) / sigmal100, 2));
186 for (
Index iD = 0; iD < nD; iD++) {
191 psd[iD] = (dNdD1[iD] + dNdD2[iD]) * 1e6;
217 if (nin < 1 || nin > 4)
219 "The number of columns in *pnd_agenda_input* must "
222 throw runtime_error(
"*scat_species_a* should be > 0.");
223 if (scat_species_b <= 0 || scat_species_b >= 5)
224 throw runtime_error(
"*scat_species_b* should be > 0 and < 5.");
232 if (n0_depend + mu_depend + la_depend + ga_depend != 2)
234 "Two (but only two) of n0, mu, la and ga must be NaN, "
235 "to flag that these parameters are the ones dependent of "
236 "mass content and mean particle size.");
237 if (mu_depend || ga_depend)
239 "Sorry, mu and la are not yet allowed to be a "
240 "dependent parameter.");
242 const Index n0_fixed = (
Index) !(n0_depend || std::isnan(n0));
243 const Index mu_fixed = (
Index) !(mu_depend || std::isnan(mu));
244 const Index la_fixed = (
Index) !(la_depend || std::isnan(la));
245 const Index ga_fixed = (
Index) !(ga_depend || std::isnan(ga));
247 if (nin + n0_fixed + mu_fixed + la_fixed + ga_fixed != 4)
249 "This PSD has four free parameters. This means that "
250 "the number\nof columns in *pnd_agenda_input* and the "
251 "number of numerics\n(i.e. not -999 or NaN) and among "
252 "the GIN arguments n0, mu, la and\nga must add up to "
253 "four. And this was found not to be the case.");
256 Vector mgd_pars(4), ext_pars(2);
263 }
else if (!n0_depend) {
264 mgd_i_pai[0] = nhit++;
268 }
else if (!mu_depend) {
269 mgd_i_pai[1] = nhit++;
273 }
else if (!la_depend) {
274 mgd_i_pai[2] = nhit++;
278 }
else if (!ga_depend) {
279 mgd_i_pai[3] = nhit++;
295 for (
Index i = 0; i < ndx; i++) {
300 }
else if (dx2in[i] == 1)
306 for (
Index j = 0; j < 4; j++) {
307 if (dx2in[i] == mgd_i_pai[j]) {
317 for (
Index ip = 0; ip < np; ip++) {
321 if (ext_pars[1] <= 0) {
323 os <<
"Negative " << something <<
"found.\nThis is not allowed.";
324 throw std::runtime_error(os.str());
327 for (
Index i = 0; i < 4; i++) {
328 if (mgd_i_pai[i] >= 0) {
335 if ((ext_pars[0] == 0.) && (!ndx)) {
340 if (t < t_min || t > t_max) {
343 os <<
"Method called with a temperature of " << t <<
" K.\n"
344 <<
"This is outside the specified allowed range: [ max(0.," << t_min
345 <<
"), " << t_max <<
" ]";
346 throw runtime_error(os.str());
354 Numeric mu1 = 0, mub1 = 0, eterm = 0, gterm = 0;
355 Numeric scfac1 = 0, scfac2 = 0, gab = 0;
358 if (something ==
"mean size") {
359 if (n0_depend && la_depend) {
362 throw runtime_error(
"Bad MGD parameter detected: mu + b + 1 <= 0");
363 eterm = mub1 / mgd_pars[3];
365 scfac2 =
pow(eterm, mgd_pars[3]);
366 mgd_pars[2] = scfac2 *
pow(ext_pars[1], -mgd_pars[3]);
368 gterm = tgamma(eterm);
371 mgd_pars[0] = scfac1 * ext_pars[0];
378 else if (something ==
"median size") {
379 if (n0_depend && la_depend) {
382 throw runtime_error(
"Bad MGD parameter detected: mu + b + 1 <= 0");
383 eterm = mub1 / mgd_pars[3];
385 scfac2 = (mgd_pars[1] + 1 +
scat_species_b - 0.327 * mgd_pars[3]) /
387 mgd_pars[2] = scfac2 *
pow(ext_pars[1], -mgd_pars[3]);
389 gterm = tgamma(eterm);
392 mgd_pars[0] = scfac1 * ext_pars[0];
399 else if (something ==
"mean particle mass") {
400 if (n0_depend && la_depend) {
401 mu1 = mgd_pars[1] + 1;
403 throw runtime_error(
"Bad MGD parameter detected: mu + 1 <= 0");
405 gterm = tgamma(eterm);
409 mgd_pars[2] = scfac2 *
pow(ext_pars[1], -gab);
413 mgd_pars[0] = scfac1 * ext_pars[0];
419 else if (something ==
"Ntot") {
420 if (n0_depend && la_depend) {
421 mu1 = mgd_pars[1] + 1;
423 throw runtime_error(
"Bad MGD parameter detected: mu + 1 <= 0");
425 gterm = tgamma(eterm);
429 mgd_pars[2] = scfac2 *
pow(ext_pars[1] / ext_pars[0], gab);
433 mgd_pars[0] = scfac1 * ext_pars[0];
445 if (mgd_pars[2] <= 0)
446 throw runtime_error(
"Bad MGD parameter detected: la <= 0");
447 if (mgd_pars[3] <= 0)
448 throw runtime_error(
"Bad MGD parameter detected: ga <= 0");
459 (
bool)mgd_do_jac[0] || n0_depend,
460 (
bool)mgd_do_jac[1] || mu_depend,
461 (
bool)mgd_do_jac[2] || la_depend,
462 (
bool)mgd_do_jac[3] || ga_depend);
465 if (ext_do_jac[0] | ext_do_jac[1]) {
467 if (something ==
"mean size") {
468 if (n0_depend && la_depend) {
480 ext_pars[0] * mgd_pars[3] * eterm *
487 -mgd_pars[3] * scfac2 *
pow(ext_pars[1], -(mgd_pars[3] + 1));
495 else if (something ==
"median size") {
496 if (n0_depend && la_depend) {
508 ext_pars[0] * mgd_pars[3] * eterm *
515 -mgd_pars[3] * scfac2 *
pow(ext_pars[1], -(mgd_pars[3] + 1));
523 else if (something ==
"mean particle mass") {
524 if (n0_depend && la_depend) {
536 ext_pars[0] * mgd_pars[3] * eterm *
544 pow(ext_pars[1], -(gab + 1));
551 else if (something ==
"Ntot") {
552 if (n0_depend && la_depend) {
554 const Numeric dn0dla = ext_pars[0] * mgd_pars[3] * eterm *
555 pow(mgd_pars[2], eterm - 1) /
560 const Numeric dladw = scfac2 *
pow(ext_pars[1], gab) *
562 pow(ext_pars[0], -(gab + 1));
583 scfac2 *
pow(ext_pars[0], -gab) *
598 for (
Index i = 0; i < 4; i++) {
614 const Index& species_index,
625 if (nss == 0)
throw runtime_error(
"*scat_meta* is empty!");
626 if (nss < species_index + 1) {
628 os <<
"Selected scattering species index is " << species_index
630 <<
"is not allowed since *scat_meta* has only " << nss <<
" elements.";
631 throw runtime_error(os.str());
635 os <<
"This method only works with scattering species consisting of a\n"
636 <<
"single element, but your data do not match this demand.\n"
637 <<
"Selected scattering species index is " << species_index <<
".\n"
638 <<
"This species has " <<
scat_meta[species_index].nelem()
640 throw runtime_error(os.str());
644 throw runtime_error(
"*pnd_agenda_input* must have one column.");
647 "This method demands that length of "
648 "*psd_size_grid* is 1.");
652 if (type ==
"mass") {
653 pmass =
scat_meta[species_index][0].mass;
656 for (
Index ip = 0; ip < np; ip++) {
662 if ((
x == 0.) && (!ndx)) {
667 if (t < t_min || t > t_max) {
670 os <<
"Method called with a temperature of " << t <<
" K.\n"
671 <<
"This is outside the specified allowed range: [ max(0.," << t_min
672 <<
"), " << t_max <<
" ]";
673 throw runtime_error(os.str());
681 if (type ==
"ntot") {
687 }
else if (type ==
"mass") {
714 Numeric base = c1 / rwc * a * tgamma(4);
715 Numeric exponent = 1. / (4 - b);
722 for (
Index iD = 0; iD < nD; iD++) {
723 psd[iD] = N0 * exp(-lambda * diameter[iD]);
750 throw runtime_error(
"*pnd_agenda_input* must have one column.");
754 if (psd_name ==
"Abel12" || psd_name ==
"Wang16"){
755 if (scat_species_b < 2.9 || scat_species_b > 3.1) {
757 os <<
"This PSD treats rain, using Dveq as size grid.\n"
758 <<
"This means that *scat_species_b* should be close to 3,\n"
759 <<
"but it is outside of the tolerated range of [2.9,3.1].\n"
761 throw runtime_error(os.str());
763 if (scat_species_a < 500 || scat_species_a > 540) {
765 os <<
"This PSD treats rain, using Dveq as size grid.\n"
766 <<
"This means that *scat_species_a* should be close to 520,\n"
767 <<
"but it is outside of the tolerated range of [500,540].\n"
769 throw runtime_error(os.str());
774 if (psd_name ==
"Field19"){
775 if (scat_species_b < 2.8 || scat_species_b > 3.2) {
777 os <<
"This PSD treats graupel, assuming a constant effective density.\n"
778 <<
"This means that *scat_species_b* should be close to 3,\n"
779 <<
"but it is outside of the tolerated range of [2.8,3.2].\n"
781 throw runtime_error(os.str());
785 for (
Index ip = 0; ip < np; ip++) {
791 if ((water_content == 0.) && (!ndx)) {
796 if (t < t_min || t > t_max) {
799 os <<
"Method called with a temperature of " << t <<
" K.\n"
800 <<
"This is outside the specified allowed range: [ max(0.," << t_min
801 <<
"), " << t_max <<
" ]";
802 throw runtime_error(os.str());
810 if (water_content < 0) {
812 water_content *= -1.0;
820 if (psd_name ==
"Abel12"){
826 else if (psd_name ==
"Wang16"){
833 else if (psd_name ==
"Field19"){
839 else if (psd_name ==
"generic"){
840 n_alpha = n_alpha_in;
852 Numeric expo = 1.0 / (n_b - k - 1);
854 Numeric lam =
pow(water_content*gamma/denom, expo);
860 if (water_content != 0) {
870 for (
Index i = 0; i < nsi; i++) {
871 psd_data(ip, i) = psd_weight * psd_1p[i];
876 const Numeric dlam_dwc =
pow(gamma/denom, expo) * expo *
pow(water_content, expo-1);
877 const Numeric dn_0_dwc = n_alpha * n_b *
pow(lam, n_b-1) * dlam_dwc;
878 for (
Index i = 0; i < nsi; i++) {
879 dpsd_data_dx(0, ip, i) = psd_weight * (jac_data(0,i)*dn_0_dwc +
880 jac_data(2,i)*dlam_dwc);
913 assert((regime ==
"TR") || (regime ==
"ML"));
917 q = {152., -12.4, 3.28, -0.78, -1.94};
919 q = {141., -16.8, 102., 2.07, -4.82};
922 Vector Aq{13.6, -7.76, 0.479};
923 Vector Bq{-0.0361, 0.0151, 0.00149};
924 Vector Cq{0.807, 0.00581, 0.0457};
933 An = exp(Aq[0] + Aq[1] *
beta + Aq[2] *
pow(
beta, 2));
937 base = M2 * exp(-Bn * Tc) / An;
947 An = exp(Aq[0] + Aq[1] * n + Aq[2] *
pow(n, 2));
948 Bn = Bq[0] + Bq[1] * n + Bq[2] *
pow(n, 2);
949 Cn = Cq[0] + Cq[1] * n + Cq[2] *
pow(n, 2);
952 Mn = An * exp(Bn * Tc) *
pow(M2, Cn);
954 M2Mn =
pow(M2, 4.) /
pow(Mn, 3.);
956 for (
Index iD = 0; iD < nD; iD++) {
958 x = diameter[iD] * M2 / Mn;
961 phi23 =
q[0] * exp(
q[1] *
x) +
q[2] *
pow(
x,
q[3]) * exp(
q[4] *
x);
973 psd[iD] = phi23 * M2Mn;
982 const String& hydrometeor_type) {
1004 if (hydrometeor_type ==
"cloud_ice")
1010 }
else if (hydrometeor_type ==
"rain")
1016 }
else if (hydrometeor_type ==
"snow")
1022 }
else if (hydrometeor_type ==
"graupel")
1028 }
else if (hydrometeor_type ==
"hail")
1034 }
else if (hydrometeor_type ==
"cloud_water")
1042 os <<
"You use a wrong tag! ";
1043 throw runtime_error(os.str());
1074 arg2 = (mu + 2) / gamma;
1075 arg1 = (mu + 1) / gamma;
1082 brk = M0 / M1 * c2 / c1;
1083 brkMu1 =
pow(brk, (mu + 1));
1086 Lambda =
pow(brk, gamma);
1088 L1 =
pow(Lambda, arg1);
1091 N0 = M0 * gamma / tgamma(arg1) * L1;
1094 for (
Index iD = 0; iD < nD; iD++) {
1098 if (std::isnan(psd[iD])) psd[iD] = 0.0;
1099 if (std::isinf(psd[iD])) psd[iD] = 0.0;
1102 mMu =
pow(mass[iD], mu);
1103 mGamma =
pow(mass[iD], gamma);
1106 dpsd(iD, 0) = gamma / c1 * M0 / M1 * mMu * exp(-Lambda * mGamma) *
1107 brkMu1 * (-1 - mu + gamma * mGamma * Lambda);
1110 dpsd(iD, 1) = -gamma / c1 * mMu * exp(-Lambda * mGamma) * brkMu1 *
1111 (-2 - mu - gamma * mGamma * Lambda);
1120 const Vector& diameter_max,
1142 if (psd_type ==
"cloud_ice")
1148 }
else if (psd_type ==
"rain")
1154 }
else if (psd_type ==
"snow")
1160 }
else if (psd_type ==
"graupel")
1166 }
else if (psd_type ==
"hail")
1172 }
else if (psd_type ==
"cloud_water")
1180 os <<
"You use a wrong tag! ";
1181 throw runtime_error(os.str());
1194 if (M1 > 0.0 && M0 > 0) {
1196 arg2 = (mu +
beta + 1) / gamma;
1197 arg1 = (mu + 1) / gamma;
1204 temp = alpha * M0 / M1 * c2 / c1;
1209 Lmg =
pow(Lambda, arg1);
1212 N0 = M0 * gamma / c1 * Lmg;
1217 for (
Index iD = 0; iD < nD; iD++) {
1218 psd[iD] =
mod_gamma_dist(diameter_max[iD], N0, Lambda, mu, gamma);
1220 if (std::isnan(psd[iD])) psd[iD] = 0.0;
1221 if (std::isinf(psd[iD])) psd[iD] = 0.0;
1224 DMu =
pow(diameter_max[iD], mu);
1225 DGamma =
pow(diameter_max[iD], gamma);
1228 dpsd(iD, 0) = (DMu * exp(-DGamma * Lambda) * gamma * M0 * Lmg *
1229 (-1 - mu + DGamma * gamma * Lambda) / (M1 *
beta * c1));
1232 dpsd(iD, 1) = (DMu * exp(-DGamma * Lambda) * gamma * Lmg *
1233 (1 +
beta + mu - DGamma * gamma * Lambda) / (
beta * c1));
1245 return pow(256.0 * iwc /
PI / rho / n0, 0.25);
1251 return 256.0 * iwc /
PI / rho /
pow(dm, 4.0);