Canoe
Comprehensive Atmosphere N' Ocean Engine
try_equilibrium_tp_vapor_vapor_cloud.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <sstream>
3 
4 // athena
5 #include <athena/athena.hpp>
6 
7 // application
8 #include <application/exceptions.hpp>
9 
10 // canoe
11 #include <air_parcel.hpp>
12 
13 // climath
14 #include <climath/core.h>
15 
16 #include <climath/root.hpp>
17 
18 // snap
19 #include "thermodynamics.hpp"
20 
21 // Calculates phase equilibrium of
22 // a * Vapor1 + b * Vapor2 <=> c * Cloud
23 //
24 // Example phase equilibrium:
25 // NH3 + H2S -> NH4SH(s)
26 //
28  AirParcel const& air, IndexPair ij, Real cv_hat, bool misty) const {
29  auto& info = cloud_reaction_map_.at(ij);
30 
31  int j1 = info.first[0];
32  int j2 = info.first[1];
33  int j3 = info.first[2];
34  auto& stoi = info.second;
35 
36  Real a = stoi[0] / stoi[2], b = stoi[1] / stoi[2];
37 
38  Real ptol = air.w[IPR], temp = air.w[IDN], gmol = 1.;
39 
40 #pragma omp simd reduction(+ : gmol)
41  for (int n = 0; n < NCLOUD; ++n) gmol += -air.c[n];
42 
43  gmol -= air.w[j1] + air.w[j2];
44 
45  Real x0 = a * air.c[j3] + air.w[j1], y0 = b * air.c[j3] + air.w[j2], z0 = 0.,
46  pp1 = x0 / (x0 + y0 + gmol) * ptol, pp2 = y0 / (x0 + y0 + gmol) * ptol;
47 
48  Real mol0 = air.w[j1], mol1 = air.w[j2];
49  Real svp = svp_func2_.at(ij)(air, j1, j2, j3);
50 
51  if (pp1 * pp2 > svp) {
52  Real zeta = svp / (ptol * ptol), rh;
53 
54  int error;
55 
56  if (a * y0 > b * x0) {
57  error = root(0., 1., 1.E-8, &rh, [a, b, x0, y0, gmol, zeta](double r) {
58  Real x = r * x0, y = y0 - b / a * (x0 - x);
59  return (x * y) / sqr(x + y + gmol) - zeta;
60  });
61  y0 -= b / a * (1. - rh) * x0;
62  z0 = (1. - rh) * x0 / a;
63  x0 *= rh;
64  } else {
65  error = root(0., 1., 1.E-8, &rh, [a, b, x0, y0, gmol, zeta](double r) {
66  Real y = r * y0, x = x0 - a / b * (y0 - y);
67  return (x * y) / sqr(x + y + gmol) - zeta;
68  });
69  x0 -= a / b * (1. - rh) * y0;
70  z0 = (1. - rh) * y0 / b;
71  y0 *= rh;
72  }
73 
74  // correction for y0 << x0 and x0 >> y0
75  if (y0 < 1.E-8 * x0) {
76  y0 = (x0 + gmol) * (x0 + gmol) / x0 * zeta;
77  z0 = (b * air.c[j3] + air.w[j2] - y0) / b;
78  x0 = a * air.c[j3] + air.w[j1] - a * z0;
79  } else if (x0 < 1.E-8 * y0) {
80  x0 = (y0 + gmol) * (y0 + gmol) / y0 * zeta;
81  z0 = (a * air.c[j3] + air.w[j1] - x0) / a;
82  y0 = b * air.c[j3] + air.w[j2] - b * z0;
83  }
84 
85  /*if (error) {
86  std::stringstream msg;
87  msg << "Condensation a(A) + b(B) -> c(C) failed" << std::endl;
88  msg << "Air parcel = (" << air << ")" << std::endl;
89  throw RuntimeError("TryEquilibriumTP_VaporVaporCloud", msg.str());
90  }*/
91  }
92 
93  std::array<Real, 3> rates;
94  rates[0] = x0 - air.w[j1];
95  rates[1] = y0 - air.w[j2];
96  rates[2] = z0 - air.c[j3];
97 
98  return rates;
99 }
Real *const w
Definition: air_parcel.hpp:36
Real *const c
cloud data
Definition: air_parcel.hpp:39
std::map< IndexPair, ReactionInfo > cloud_reaction_map_
reaction information map
SVPFunc2Container svp_func2_
saturation vapor pressure function: Vapor + Vapor -> Cloud
RealArray3 TryEquilibriumTP_VaporVaporCloud(AirParcel const &air, IndexPair ij, Real cv_hat=0., bool misty=false) const
Calculate the equilibrium mole transfer by cloud reaction vapor1 + vapor2 -> cloud.
double sqr(double x)
Definition: core.h:14
float temp
Definition: fit_ammonia.py:6
int root(double x1, double x2, double xacc, double *x_root, RootFunction_t func, void *aux)
Definition: root.c:10
std::array< Real, 3 > RealArray3
std::pair< int, int > IndexPair