Skip to content

Commit f54eeff

Browse files
authored
Merge pull request #143 from zdaq12/dry_dep
Add loss function support
2 parents 263b0f6 + 45632ed commit f54eeff

File tree

7 files changed

+274
-1
lines changed

7 files changed

+274
-1
lines changed

src/env_state.F90

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,48 @@ subroutine f_env_state_get_rel_humid(ptr_c, rel_humid) bind(C)
6969

7070
end subroutine
7171

72+
subroutine f_env_state_set_height(ptr_c, height) bind(C)
73+
type(env_state_t), pointer :: ptr_f => null()
74+
type(c_ptr), intent(in) :: ptr_c
75+
real(c_double), intent(in) :: height
76+
77+
call c_f_pointer(ptr_c, ptr_f)
78+
79+
ptr_f%height = height
80+
81+
end subroutine
82+
83+
subroutine f_env_state_get_height(ptr_c, height) bind(C)
84+
type(env_state_t), pointer :: ptr_f => null()
85+
type(c_ptr), intent(in) :: ptr_c
86+
real(c_double), intent(out) :: height
87+
88+
call c_f_pointer(ptr_c, ptr_f)
89+
90+
height = ptr_f%height
91+
92+
end subroutine
93+
94+
subroutine f_env_state_set_pressure(ptr_c, pressure) bind(C)
95+
type(env_state_t), pointer :: ptr_f => null()
96+
type(c_ptr), intent(in) :: ptr_c
97+
real(c_double), intent(in) :: pressure
98+
99+
call c_f_pointer(ptr_c, ptr_f)
100+
101+
ptr_f%pressure = pressure
102+
103+
end subroutine
104+
105+
subroutine f_env_state_get_pressure(ptr_c, pressure) bind(C)
106+
type(env_state_t), pointer :: ptr_f => null()
107+
type(c_ptr), intent(in) :: ptr_c
108+
real(c_double), intent(out) :: pressure
109+
110+
call c_f_pointer(ptr_c, ptr_f)
111+
112+
pressure = ptr_f%pressure
113+
114+
end subroutine
115+
72116
end module

src/env_state.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ extern "C" void f_env_state_from_json(const void *ptr) noexcept;
1515
extern "C" void f_env_state_set_temperature(const void *ptr, const double *temperature) noexcept;
1616
extern "C" void f_env_state_get_temperature(const void *ptr, double *temperature) noexcept;
1717
extern "C" void f_env_state_get_rel_humid(const void *ptr, double *rel_humid) noexcept;
18+
extern "C" void f_env_state_set_height(const void *ptr, const double *height) noexcept;
19+
extern "C" void f_env_state_get_height(const void *ptr, double *height) noexcept;
20+
extern "C" void f_env_state_set_pressure(const void *ptr, const double *pressure) noexcept;
21+
extern "C" void f_env_state_get_pressure(const void *ptr, double *pressure) noexcept;
1822

1923
struct EnvState {
2024
PMCResource ptr;
@@ -44,4 +48,26 @@ struct EnvState {
4448
f_env_state_get_rel_humid(&self.ptr, &rel_humid);
4549
return rel_humid;
4650
}
51+
52+
static void set_height(const EnvState &self, const double height) {
53+
f_env_state_set_height(&self.ptr, &height);
54+
}
55+
56+
static double get_height(const EnvState &self) {
57+
double height;
58+
59+
f_env_state_get_height(&self.ptr, &height);
60+
return height;
61+
}
62+
63+
static void set_pressure(const EnvState &self, const double pressure) {
64+
f_env_state_set_pressure(&self.ptr, &pressure);
65+
}
66+
67+
static double get_pressure(const EnvState &self) {
68+
double pressure;
69+
70+
f_env_state_get_pressure(&self.ptr, &pressure);
71+
return pressure;
72+
}
4773
};

src/pypartmc.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ PYBIND11_MODULE(_PyPartMC, m) {
168168
"returns the current temperature of the environment state")
169169
.def_property_readonly("rh", EnvState::rh,
170170
"returns the current relative humidity of the environment state")
171+
.def_property("height", &EnvState::get_height, &EnvState::set_height)
172+
.def_property("pressure", &EnvState::get_pressure, &EnvState::set_pressure)
171173
;
172174

173175
py::class_<Scenario>(m,
@@ -271,6 +273,16 @@ PYBIND11_MODULE(_PyPartMC, m) {
271273
"Convert diameter (m) to radius (m)."
272274
);
273275

276+
m.def(
277+
"loss_rate_dry_dep", &loss_rate_dry_dep, py::return_value_policy::copy,
278+
"Compute and return the dry deposition rate for a given particle."
279+
);
280+
281+
m.def(
282+
"loss_rate", &loss_rate, py::return_value_policy::copy,
283+
"Evaluate a loss rate function."
284+
);
285+
274286
m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
275287

276288
m.attr("__all__") = py::make_tuple(
@@ -293,6 +305,8 @@ PYBIND11_MODULE(_PyPartMC, m) {
293305
"sphere_vol2rad",
294306
"rad2diam",
295307
"sphere_rad2vol",
296-
"diam2rad"
308+
"diam2rad",
309+
"loss_rate_dry_dep",
310+
"loss_rate"
297311
);
298312
}

src/scenario.F90

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,58 @@ subroutine f_scenario_from_json(gas_ptr_c, aer_ptr_c, ptr_c) bind(C)
3939
call spec_file_read_scenario(file, gas_ptr_f, aer_ptr_f, ptr_f)
4040
end subroutine
4141

42+
subroutine f_scenario_loss_rate( &
43+
scenario_ptr_c, vol, &
44+
density, aero_data_ptr_c, &
45+
env_state_ptr_c, &
46+
rate &
47+
) bind (C)
48+
49+
type(scenario_t), pointer :: scenario_ptr_f => null()
50+
type(aero_data_t), pointer :: aero_data_ptr_f => null()
51+
type(env_state_t), pointer :: env_state_ptr_f => null()
52+
real(c_double), intent(in) :: vol, density
53+
type(c_ptr), intent(in) :: scenario_ptr_c, aero_data_ptr_c, env_state_ptr_c
54+
real(c_double), intent(out) :: rate
55+
56+
call c_f_pointer(scenario_ptr_c, scenario_ptr_f)
57+
call c_f_pointer(aero_data_ptr_c, aero_data_ptr_f)
58+
call c_f_pointer(env_state_ptr_c, env_state_ptr_f)
59+
60+
rate = scenario_loss_rate( &
61+
scenario_ptr_f, &
62+
vol, &
63+
density, &
64+
aero_data_ptr_f, &
65+
env_state_ptr_f &
66+
)
67+
68+
end subroutine
69+
70+
subroutine f_scenario_loss_rate_dry_dep( &
71+
vol, &
72+
density, &
73+
aero_data_ptr_c, &
74+
env_state_ptr_c, &
75+
rate &
76+
) bind(C)
77+
78+
type(aero_data_t), pointer :: aero_data_ptr_f => null()
79+
type(env_state_t), pointer :: env_state_ptr_f => null()
80+
real(c_double), intent(in) :: vol, density
81+
type(c_ptr), intent(in) :: aero_data_ptr_c, env_state_ptr_c
82+
real(c_double), intent(out) :: rate
83+
84+
call c_f_pointer(aero_data_ptr_c, aero_data_ptr_f)
85+
call c_f_pointer(env_state_ptr_c, env_state_ptr_f)
86+
87+
rate = scenario_loss_rate_dry_dep( &
88+
vol, &
89+
density, &
90+
aero_data_ptr_f, &
91+
env_state_ptr_f &
92+
)
93+
94+
end subroutine
95+
4296
end module

src/scenario.hpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "gimmicks.hpp"
1010
#include "pmc_resource.hpp"
1111
#include "aero_data.hpp"
12+
#include "env_state.hpp"
1213
#include "gas_data.hpp"
1314

1415
extern "C" void f_scenario_ctor(void *ptr) noexcept;
@@ -22,6 +23,21 @@ extern "C" void f_scenario_from_json(
2223
noexcept
2324
#endif
2425
;
26+
extern "C" void f_scenario_loss_rate(
27+
const void *scenario,
28+
const double *vol,
29+
const double *density,
30+
const void *aero_data,
31+
const void *env_state,
32+
double *rate
33+
) noexcept;
34+
extern "C" void f_scenario_loss_rate_dry_dep(
35+
const double *vol,
36+
const double *density,
37+
const void *aero_data,
38+
const void *env_state,
39+
double *rate
40+
) noexcept;
2541

2642
struct Scenario {
2743
PMCResource ptr;
@@ -49,3 +65,38 @@ struct Scenario {
4965
}
5066
};
5167

68+
double loss_rate(
69+
const Scenario &scenario,
70+
const double vol,
71+
const double density,
72+
const AeroData &aero_data,
73+
const EnvState &env_state
74+
) {
75+
double rate;
76+
f_scenario_loss_rate(
77+
&scenario.ptr,
78+
&vol,
79+
&density,
80+
&aero_data.ptr,
81+
&env_state.ptr,
82+
&rate
83+
);
84+
return rate;
85+
}
86+
87+
double loss_rate_dry_dep(
88+
const double vol,
89+
const double density,
90+
const AeroData &aero_data,
91+
const EnvState &env_state
92+
) {
93+
double rate;
94+
f_scenario_loss_rate_dry_dep(
95+
&vol,
96+
&density,
97+
&aero_data.ptr,
98+
&env_state.ptr,
99+
&rate
100+
);
101+
return rate;
102+
}

tests/test_env_state.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,27 @@ def test_dtor():
4444
# assert
4545
pass
4646

47+
@staticmethod
48+
def test_height():
49+
# arrange
50+
sut = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
51+
value = 1
52+
53+
# act
54+
sut.height = value
55+
56+
# assert
57+
assert value == sut.height
58+
59+
@staticmethod
60+
def test_pressure():
61+
# arrange
62+
sut = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
63+
value = 101325
64+
65+
# act
66+
sut.pressure = value
67+
68+
# assert
69+
assert value == sut.pressure
70+

tests/test_scenario.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
# Authors: https://github.com/open-atmos/PyPartMC/graphs/contributors #
55
####################################################################################################
66

7+
from cmath import nan
78
import gc
89
import json
910
import pytest
11+
import numpy as np
1012
import PyPartMC as ppmc
13+
from PyPartMC import si
1114

1215
from .test_gas_data import GAS_DATA_CTOR_ARG_MINIMAL
1316
from .test_aero_data import AERO_DATA_CTOR_ARG_MINIMAL
17+
from .test_env_state import ENV_STATE_CTOR_ARG_MINIMAL
1418

1519

1620
SCENARIO_CTOR_ARG_MINIMAL = {
@@ -117,3 +121,59 @@ def test_str():
117121
# assert
118122
assert json_actual == SCENARIO_CTOR_ARG_MINIMAL
119123

124+
@staticmethod
125+
@pytest.mark.parametrize("loss_function_params", (
126+
{'loss_function': 'none'},
127+
{'loss_function': 'constant'},
128+
{'loss_function': 'volume'},
129+
{'loss_function': 'drydep'},
130+
{
131+
'loss_function': 'chamber',
132+
'chamber_vol': 84.3 * si.m**3,
133+
'area_diffuse': 103 * si.m**2,
134+
'area_sedi': 12.6 * si.m**2,
135+
'prefactor_BL': 0.005 * si.m,
136+
'exponent_BL': 0.274
137+
}
138+
))
139+
def test_loss_rate(loss_function_params:str):
140+
# arrange
141+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
142+
env_state = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
143+
gas_data = ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)
144+
scenario_ctor_arg = {**SCENARIO_CTOR_ARG_MINIMAL, **loss_function_params}
145+
scenario = ppmc.Scenario(gas_data, aero_data, scenario_ctor_arg)
146+
vol = (4/3)*np.pi*(1e-6)**3
147+
density = 1
148+
env_state.height = 1
149+
env_state.set_temperature(300)
150+
env_state.pressure = 101325
151+
aero_data.frac_dim = 3
152+
aero_data.prime_radius = 1e-8
153+
aero_data.vol_fill_factor = 1
154+
155+
# act
156+
rate = ppmc.loss_rate(scenario, vol, density, aero_data, env_state)
157+
158+
# assert
159+
assert rate is not nan
160+
161+
@staticmethod
162+
def test_loss_rate_dry_dep():
163+
# arrange
164+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
165+
env_state = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
166+
vol = (4/3)*np.pi*(1e-6)**3
167+
density = 1
168+
env_state.height = 1
169+
env_state.set_temperature(300)
170+
env_state.pressure = 101325
171+
aero_data.frac_dim = 3
172+
aero_data.prime_radius = 1e-8
173+
aero_data.vol_fill_factor = 1
174+
175+
# act
176+
rate = ppmc.loss_rate_dry_dep(vol, density, aero_data, env_state)
177+
178+
# assert
179+
assert rate is not nan

0 commit comments

Comments
 (0)