Skip to content

Commit f924d65

Browse files
authored
Add missing EnvState features (#462)
1 parent 1490a37 commit f924d65

File tree

4 files changed

+315
-4
lines changed

4 files changed

+315
-4
lines changed

src/env_state.F90

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ subroutine f_env_state_get_height(ptr_c, height) bind(C)
8787
type(env_state_t), pointer :: ptr_f => null()
8888
type(c_ptr), intent(in) :: ptr_c
8989
real(c_double), intent(out) :: height
90-
90+
9191
call c_f_pointer(ptr_c, ptr_f)
9292

9393
height = ptr_f%height
@@ -109,7 +109,7 @@ subroutine f_env_state_get_additive_kernel_coefficient(ptr_c, target) bind(C)
109109
type(env_state_t), pointer :: ptr_f => null()
110110
type(c_ptr), intent(in) :: ptr_c
111111
real(c_double), intent(out) :: target
112-
112+
113113
call c_f_pointer(ptr_c, ptr_f)
114114

115115
target = ptr_f%additive_kernel_coefficient
@@ -141,7 +141,7 @@ subroutine f_env_state_get_pressure(ptr_c, pressure) bind(C)
141141
subroutine f_env_state_get_elapsed_time(ptr_c, elapsed_time) bind(C)
142142
type(env_state_t), pointer :: ptr_f => null()
143143
type(c_ptr), intent(in) :: ptr_c
144-
real(c_double), intent(out) :: elapsed_time
144+
real(c_double), intent(out) :: elapsed_time
145145

146146
call c_f_pointer(ptr_c, ptr_f)
147147

@@ -171,4 +171,116 @@ subroutine f_env_state_air_dens(ptr_c, air_density) bind(C)
171171

172172
end subroutine
173173

174+
subroutine f_env_state_air_molar_dens(ptr_c, air_molar_density) bind(C)
175+
type(env_state_t), pointer :: ptr_f => null()
176+
type(c_ptr), intent(in) :: ptr_c
177+
real(c_double), intent(out) :: air_molar_density
178+
179+
call c_f_pointer(ptr_c, ptr_f)
180+
181+
air_molar_density = env_state_air_molar_den(ptr_f)
182+
183+
end subroutine
184+
185+
subroutine f_env_state_get_latitude(ptr_c, latitude) bind(C)
186+
type(env_state_t), pointer :: ptr_f => null()
187+
type(c_ptr), intent(in) :: ptr_c
188+
real(c_double), intent(out) :: latitude
189+
190+
call c_f_pointer(ptr_c, ptr_f)
191+
192+
latitude = ptr_f%latitude
193+
194+
end subroutine
195+
196+
subroutine f_env_state_set_latitude(ptr_c, latitude) bind(C)
197+
type(env_state_t), pointer :: ptr_f => null()
198+
type(c_ptr), intent(inout) :: ptr_c
199+
real(c_double), intent(in) :: latitude
200+
201+
call c_f_pointer(ptr_c, ptr_f)
202+
203+
ptr_f%latitude = latitude
204+
205+
end subroutine
206+
207+
subroutine f_env_state_get_longitude(ptr_c, longitude) bind(C)
208+
type(env_state_t), pointer :: ptr_f => null()
209+
type(c_ptr), intent(in) :: ptr_c
210+
real(c_double), intent(out) :: longitude
211+
212+
call c_f_pointer(ptr_c, ptr_f)
213+
214+
longitude = ptr_f%longitude
215+
216+
end subroutine
217+
218+
subroutine f_env_state_set_longitude(ptr_c, longitude) bind(C)
219+
type(env_state_t), pointer :: ptr_f => null()
220+
type(c_ptr), intent(inout) :: ptr_c
221+
real(c_double), intent(in) :: longitude
222+
223+
call c_f_pointer(ptr_c, ptr_f)
224+
225+
ptr_f%longitude = longitude
226+
227+
end subroutine
228+
229+
subroutine f_env_state_get_altitude(ptr_c, altitude) bind(C)
230+
type(env_state_t), pointer :: ptr_f => null()
231+
type(c_ptr), intent(in) :: ptr_c
232+
real(c_double), intent(out) :: altitude
233+
234+
call c_f_pointer(ptr_c, ptr_f)
235+
236+
altitude = ptr_f%altitude
237+
238+
end subroutine
239+
240+
subroutine f_env_state_set_altitude(ptr_c, altitude) bind(C)
241+
type(env_state_t), pointer :: ptr_f => null()
242+
type(c_ptr), intent(inout) :: ptr_c
243+
real(c_double), intent(in) :: altitude
244+
245+
call c_f_pointer(ptr_c, ptr_f)
246+
247+
ptr_f%altitude = altitude
248+
249+
end subroutine
250+
251+
subroutine f_env_state_ppb_to_conc(ptr_c, ppb, conc) bind(C)
252+
type(env_state_t), pointer :: ptr_f => null()
253+
type(c_ptr), intent(in) :: ptr_c
254+
real(c_double), intent(in) :: ppb
255+
real(c_double), intent(out) :: conc
256+
257+
call c_f_pointer(ptr_c, ptr_f)
258+
259+
conc = env_state_ppb_to_conc(ptr_f, ppb)
260+
261+
end subroutine
262+
263+
subroutine f_env_state_conc_to_ppb(ptr_c, conc, ppb) bind(C)
264+
type(env_state_t), pointer :: ptr_f => null()
265+
type(c_ptr), intent(in) :: ptr_c
266+
real(c_double), intent(out) :: ppb
267+
real(c_double), intent(in) :: conc
268+
269+
call c_f_pointer(ptr_c, ptr_f)
270+
271+
ppb = env_state_conc_to_ppb(ptr_f, conc)
272+
273+
end subroutine
274+
275+
subroutine f_env_state_sat_vapor_pressure(ptr_c, sat_vapor_pressure) bind(C)
276+
type(env_state_t), pointer :: ptr_f => null()
277+
type(c_ptr), intent(in) :: ptr_c
278+
real(c_double), intent(out) :: sat_vapor_pressure
279+
280+
call c_f_pointer(ptr_c, ptr_f)
281+
282+
sat_vapor_pressure = env_state_sat_vapor_pressure(ptr_f)
283+
284+
end subroutine
285+
174286
end module

src/env_state.hpp

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,16 @@ extern "C" void f_env_state_get_pressure(const void *ptr, double *pressure) noex
2424
extern "C" void f_env_state_get_elapsed_time(const void *ptr, double *elapsed_time) noexcept;
2525
extern "C" void f_env_state_get_start_time(const void *ptr, double *start_time) noexcept;
2626
extern "C" void f_env_state_air_dens(const void *ptr, double *air_density) noexcept;
27-
27+
extern "C" void f_env_state_air_molar_dens(const void *ptr, double *air_molar_density) noexcept;
28+
extern "C" void f_env_state_set_latitude(const void *ptr, const double *latitude) noexcept;
29+
extern "C" void f_env_state_get_latitude(const void *ptr, double *latitude) noexcept;
30+
extern "C" void f_env_state_set_longitude(const void *ptr, const double *longitude) noexcept;
31+
extern "C" void f_env_state_get_longitude(const void *ptr, double *longitude) noexcept;
32+
extern "C" void f_env_state_set_altitude(const void *ptr, const double *altitude) noexcept;
33+
extern "C" void f_env_state_get_altitude(const void *ptr, double *altitude) noexcept;
34+
extern "C" void f_env_state_ppb_to_conc(const void *ptr, const double *ppb, double *conc) noexcept;
35+
extern "C" void f_env_state_conc_to_ppb(const void *ptr, const double *conc, double *ppb) noexcept;
36+
extern "C" void f_env_state_sat_vapor_pressure(const void *ptr, double *sat_vapor_pressure) noexcept;
2837

2938
struct EnvState {
3039
PMCResource ptr;
@@ -148,4 +157,98 @@ struct EnvState {
148157
);
149158
return air_density;
150159
}
160+
161+
static auto air_molar_density(const EnvState &self) {
162+
double air_molar_density;
163+
164+
f_env_state_air_molar_dens(
165+
self.ptr.f_arg(),
166+
&air_molar_density
167+
);
168+
return air_molar_density;
169+
}
170+
171+
static void set_latitude(const EnvState &self, const double latitude) {
172+
f_env_state_set_latitude(
173+
self.ptr.f_arg(),
174+
&latitude
175+
);
176+
}
177+
178+
static auto get_latitude(const EnvState &self) {
179+
double latitude;
180+
181+
f_env_state_get_latitude(
182+
self.ptr.f_arg(),
183+
&latitude
184+
);
185+
return latitude;
186+
}
187+
188+
static void set_longitude(const EnvState &self, const double longitude) {
189+
f_env_state_set_longitude(
190+
self.ptr.f_arg(),
191+
&longitude
192+
);
193+
}
194+
195+
static auto get_longitude(const EnvState &self) {
196+
double longitude;
197+
198+
f_env_state_get_longitude(
199+
self.ptr.f_arg(),
200+
&longitude
201+
);
202+
return longitude;
203+
}
204+
205+
static void set_altitude(const EnvState &self, const double altitude) {
206+
f_env_state_set_altitude(
207+
self.ptr.f_arg(),
208+
&altitude
209+
);
210+
}
211+
212+
static auto get_altitude(const EnvState &self) {
213+
double altitude;
214+
215+
f_env_state_get_altitude(
216+
self.ptr.f_arg(),
217+
&altitude
218+
);
219+
return altitude;
220+
}
221+
222+
static auto ppb_to_conc(const EnvState &self, const double ppb) {
223+
double conc;
224+
225+
f_env_state_ppb_to_conc(
226+
self.ptr.f_arg(),
227+
&ppb,
228+
&conc
229+
);
230+
return conc;
231+
}
232+
233+
static auto conc_to_ppb(const EnvState &self, const double conc) {
234+
double ppb;
235+
236+
f_env_state_conc_to_ppb(
237+
self.ptr.f_arg(),
238+
&conc,
239+
&ppb
240+
);
241+
return ppb;
242+
}
243+
244+
static auto sat_vapor_pressure(const EnvState &self) {
245+
double sat_vapor_pressure;
246+
247+
f_env_state_sat_vapor_pressure(
248+
self.ptr.f_arg(),
249+
&sat_vapor_pressure
250+
);
251+
return sat_vapor_pressure;
252+
}
253+
151254
};

src/pypartmc.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,22 @@ NB_MODULE(_PyPartMC, m) {
424424
"Box height (m).")
425425
.def_prop_rw("pressure", &EnvState::get_pressure, &EnvState::set_pressure,
426426
"Ambient pressure (Pa).")
427+
.def_prop_rw("latitude", &EnvState::get_latitude, &EnvState::set_latitude,
428+
"Latitude (degrees).")
429+
.def_prop_rw("longitude", &EnvState::get_longitude, &EnvState::set_longitude,
430+
"Longitude (degrees).")
431+
.def_prop_rw("altitude", &EnvState::get_altitude, &EnvState::set_altitude,
432+
"Altitude (m).")
427433
.def_prop_ro("air_density", &EnvState::air_density,
428434
"Air density (kg m^{-3}).")
435+
.def_prop_ro("air_molar_density", &EnvState::air_molar_density,
436+
"Air molar density (mol m^{-3}).")
429437
.def_prop_rw("additive_kernel_coefficient", &EnvState::get_additive_kernel_coefficient, &EnvState::set_additive_kernel_coefficient,
430438
"Scaling coefficient for additive coagulation kernel.")
439+
.def("ppb_to_conc", &EnvState::ppb_to_conc, "Convert (ppb) to (molecules m^{-3}).")
440+
.def("conc_to_ppb", &EnvState::conc_to_ppb, "Convert (molecules m^{-3}) to (ppb).")
441+
.def_prop_ro("sat_vapor_pressure", &EnvState::sat_vapor_pressure,
442+
"Returns the current saturation vapor pressure (Pa).")
431443
;
432444

433445
nb::class_<Photolysis>(m,

tests/test_env_state.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import gc
88

9+
import numpy as np
910
import pytest
1011

1112
import PyPartMC as ppmc
@@ -72,6 +73,42 @@ def test_pressure():
7273
# assert
7374
assert value == sut.pressure
7475

76+
@staticmethod
77+
def test_latitude():
78+
# arrange
79+
sut = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
80+
value = 40.0
81+
82+
# act
83+
sut.latitude = value
84+
85+
# assert
86+
assert value == sut.latitude
87+
88+
@staticmethod
89+
def test_longitude():
90+
# arrange
91+
sut = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
92+
value = 180.0
93+
94+
# act
95+
sut.longitude = value
96+
97+
# assert
98+
assert value == sut.longitude
99+
100+
@staticmethod
101+
def test_altitude():
102+
# arrange
103+
sut = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
104+
value = 200.0
105+
106+
# act
107+
sut.altitude = value
108+
109+
# assert
110+
assert value == sut.altitude
111+
75112
@staticmethod
76113
def test_additive_kernel_coefficient():
77114
# arrange
@@ -119,3 +156,50 @@ def test_air_density():
119156

120157
# assert
121158
assert 1 * si.kg / si.m**3 < env_state.air_density < 1.5 * si.kg / si.m**3
159+
160+
@staticmethod
161+
def test_air_molar_density():
162+
# arrange
163+
gas_data = ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)
164+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
165+
scenario = ppmc.Scenario(gas_data, aero_data, SCENARIO_CTOR_ARG_MINIMAL)
166+
env_state = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
167+
scenario.init_env_state(env_state, 0.0)
168+
169+
# assert
170+
assert (
171+
1 * si.mol / si.m**3 < env_state.air_molar_density < 100 * si.mol / si.m**3
172+
)
173+
174+
@staticmethod
175+
def test_conc_ppb_conversions():
176+
# arrange
177+
gas_data = ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)
178+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
179+
scenario = ppmc.Scenario(gas_data, aero_data, SCENARIO_CTOR_ARG_MINIMAL)
180+
env_state = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
181+
scenario.init_env_state(env_state, 0.0)
182+
183+
# act
184+
conc_orig = 1.0
185+
ppb = env_state.conc_to_ppb(conc_orig)
186+
ppb_orig = 1.0
187+
conc = env_state.ppb_to_conc(ppb_orig)
188+
189+
# assert
190+
assert ppb < conc_orig
191+
assert ppb_orig < conc
192+
np.testing.assert_almost_equal(env_state.ppb_to_conc(ppb), conc_orig)
193+
np.testing.assert_almost_equal(env_state.conc_to_ppb(conc), ppb_orig)
194+
195+
@staticmethod
196+
def test_sat_vapor_pressure():
197+
# arrange
198+
gas_data = ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)
199+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
200+
scenario = ppmc.Scenario(gas_data, aero_data, SCENARIO_CTOR_ARG_MINIMAL)
201+
env_state = ppmc.EnvState(ENV_STATE_CTOR_ARG_MINIMAL)
202+
scenario.init_env_state(env_state, 0.0)
203+
204+
# assert
205+
assert env_state.sat_vapor_pressure > 0.0

0 commit comments

Comments
 (0)