Skip to content

Commit d12c77d

Browse files
authored
Pybind11_vectorize (#1)
* vectorize the function using pybind11/numpy.h, achieving handling numpy array, float and dtype * add dewpoint, add constants.hpp, adding other functions WIP
1 parent f18d93b commit d12c77d

File tree

4 files changed

+73
-62
lines changed

4 files changed

+73
-62
lines changed

src/calcmod.cpp

Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,12 @@
11
#include "virtual_temperature.hpp"
22
#include <pybind11/pybind11.h>
3+
#include <pybind11/numpy.h>
34
#include <pybind11/stl.h>
45

56
namespace py = pybind11;
67

7-
// Flexible dispatcher that supports scalar/list combinations
8-
std::vector<double> virtual_temperature_py(py::object temperature, py::object mixing_ratio, double epsilon) {
9-
std::vector<double> temperature_vec;
10-
std::vector<double> mixing_ratio_vec;
11-
12-
// Case 1: both are lists
13-
if (py::isinstance<py::list>(temperature) && py::isinstance<py::list>(mixing_ratio)) {
14-
temperature_vec = temperature.cast<std::vector<double>>();
15-
mixing_ratio_vec = mixing_ratio.cast<std::vector<double>>();
16-
if (temperature_vec.size() != mixing_ratio_vec.size()) {
17-
throw std::invalid_argument("Temperature and mixing ratio lists must be the same length.");
18-
}
19-
}
20-
// Case 2: temperature is float, mixing_ratio is list
21-
else if (py::isinstance<py::float_>(temperature) && py::isinstance<py::list>(mixing_ratio)) {
22-
mixing_ratio_vec = mixing_ratio.cast<std::vector<double>>();
23-
temperature_vec = std::vector<double>(mixing_ratio_vec.size(), temperature.cast<double>());
24-
}
25-
// Case 3: temperature is list, mixing_ratio is float
26-
else if (py::isinstance<py::list>(temperature) && py::isinstance<py::float_>(mixing_ratio)) {
27-
temperature_vec = temperature.cast<std::vector<double>>();
28-
mixing_ratio_vec = std::vector<double>(temperature_vec.size(), mixing_ratio.cast<double>());
29-
}
30-
// Case 4: both are floats
31-
else if (py::isinstance<py::float_>(temperature) && py::isinstance<py::float_>(mixing_ratio)) {
32-
temperature_vec = {temperature.cast<double>()};
33-
mixing_ratio_vec = {mixing_ratio.cast<double>()};
34-
}
35-
else {
36-
throw std::invalid_argument("Inputs must be float or list.");
37-
}
38-
39-
return VirtualTemperature(temperature_vec, mixing_ratio_vec, epsilon);
40-
}
41-
428
int add(int i, int j) {
43-
return i - j;
9+
return i + j;
4410
}
4511

4612
PYBIND11_MODULE(_calc_mod, m) {
@@ -49,11 +15,11 @@ PYBIND11_MODULE(_calc_mod, m) {
4915
m.def("add", &add, "Add two numbers");
5016

5117
// Unified binding with default epsilon
52-
m.def("virtual_temperature", &virtual_temperature_py,
53-
py::arg("temperature"), py::arg("mixing_ratio"), py::arg("epsilon") = 0.622,
54-
"Compute virtual temperature.\n"
55-
"Accepts:\n"
56-
" - two lists of equal length\n"
57-
" - one scalar and one list\n"
58-
"Defaults to epsilon = 0.622");
18+
m.def("dewpoint", py::vectorize(DewPoint),
19+
"Calculate dew point from water vapor partial pressure.",
20+
py::arg("vapor_pressure"));
21+
22+
m.def("virtual_temperature", py::vectorize(VirtualTemperature),
23+
"Calculate virtual temperature from temperature and mixing ratio.",
24+
py::arg("temperature"), py::arg("mixing_ratio"), py::arg("epsilon") = 0.622);
5925
}

src/constants.hpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef CONSTANTS_HPP
2+
#define CONSTANTS_HPP
3+
4+
namespace metpy_constants {
5+
// Gas constants (J / kg / K)
6+
constexpr double R = 8.314462618; // Universal gas constant (J / mol / K)
7+
8+
// Dry air
9+
constexpr double Md = 28.96546e-3; // Molar mass of dry air (kg / mol)
10+
constexpr double Rd = R / Md; // Dry air (J / kg / K)
11+
constexpr double dry_air_spec_heat_ratio = 1.4;
12+
constexpr double Cp_d = Rd * dry_air_spec_heat_ratio / (dry_air_spec_heat_ratio - 1.0); // (J / kg / K)
13+
constexpr double Cv_d = Cp_d / dry_air_spec_heat_ratio; // (J / kg / K)
14+
15+
// Water
16+
constexpr double Mw = 18.015268e-3; // Molar mass of water (kg / mol)
17+
constexpr double Rv = R / Mw; // Water vapor (J / kg / K)
18+
constexpr double wv_spec_heat_ratio = 1.33;
19+
constexpr double Cp_v = Rv * wv_spec_heat_ratio / (wv_spec_heat_ratio - 1.0); // (J / kg / K)
20+
constexpr double Cv_v = Cp_v / wv_spec_heat_ratio; // (J / kg / K)
21+
constexpr double Cp_l = 4.2194e3; // Specific heat capacity of liquid water (J / kg / K)
22+
constexpr double Lv = 2.50084e6; // Latent heat of vaporization of water (J / kg)
23+
constexpr double T0 = 273.16; // Triple point of water (K)
24+
25+
// General Meteorological constants
26+
constexpr double epsilon = Mw / Md; // ≈ 0.622
27+
28+
29+
// Standard gravity
30+
constexpr double g = 9.80665; // m / s^2
31+
32+
// Reference pressure
33+
constexpr double P0 = 100000.0; // Pa (hPa = 1000)
34+
35+
}
36+
37+
#endif // CONSTANTS_HPP

src/virtual_temperature.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
1+
#include <cmath>
2+
#include "constants.hpp"
13
#include "virtual_temperature.hpp"
24
//#include <stdexcept>
35

4-
std::vector<double> VirtualTemperature(
5-
const std::vector<double>& temperature,
6-
const std::vector<double>& mixing_ratio,
7-
double epsilon
8-
) {
6+
double water_latent_heat_vaporization(double temperature) {
7+
// Calculate the latent heat of vaporization of water in J/kg at a given temperature.
8+
using namespace metpy_constants;
9+
return Lv - (Cp_l - Cp_v) * (temperature - T0);
10+
}
11+
12+
double _saturation_vapor_pressure(double temperature) {
13+
// Calculate saturation (equilibrium) water vapor (partial) pressure over liquid water.
14+
// Constants for the Magnus-Tetens approximation
15+
//const double a = 17.67;
16+
//const double b = 243.5;
917

10-
std::vector<double> result(temperature.size());
11-
double T, w;
12-
for (size_t i = 0; i < temperature.size(); ++i) {
13-
T = temperature[i];
14-
w = mixing_ratio[i];
15-
result[i] = T * (w + epsilon) / (epsilon * (1 + w));
16-
}
18+
// Calculate saturation vapor pressure using the Magnus-Tetens formula
19+
//return 6.112 * exp((a * temperature) / (b + temperature));
20+
}
21+
22+
double DewPoint(double vapor_pressure) {
23+
double val = log(vapor_pressure / 6.112);
24+
return 243.5 * val / (17.67 - val);
25+
}
1726

18-
return result;
27+
double VirtualTemperature(double temperature, double mixing_ratio, double epsilon) {
28+
return temperature * (mixing_ratio + epsilon) / (epsilon * (1. + mixing_ratio));
1929
}

src/virtual_temperature.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
#ifndef VIRTUAL_TEMPERATURE_HPP // if not defined
22
#define VIRTUAL_TEMPERATURE_HPP // define the header file
33

4-
#include <vector>
4+
//#include <vector>
55

6-
// Compute virtual temperature: vector + vector
7-
std::vector<double> VirtualTemperature(
8-
const std::vector<double>& temperature,
9-
const std::vector<double>& mixing_ratio,
10-
double epsilon);
6+
double DewPoint(double vapor_pressure);
7+
8+
double VirtualTemperature(double temperature, double mixing_ratio, double epsilon);
119

1210
#endif // VIRTUAL_TEMPERATURE_HPP

0 commit comments

Comments
 (0)