Skip to content

Commit 28f783e

Browse files
slayoojcurtis2
andauthored
remove hardcoded AeroState init parameters, add AeroState::dist_sample. closes #116 (#197)
Co-authored-by: Jeff Curtis <[email protected]>
1 parent 6ece6d0 commit 28f783e

File tree

6 files changed

+111
-61
lines changed

6 files changed

+111
-61
lines changed

src/aero_state.F90

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -33,65 +33,13 @@ subroutine f_aero_state_init(ptr_c, n_part, aero_data_ptr_c) bind(C)
3333
type(c_ptr) :: ptr_c, aero_data_ptr_c
3434
real(c_double), intent(in) :: n_part
3535

36-
! local testing ! TODO #141
37-
type(aero_dist_t) :: aero_dist_init
38-
real(kind=dp), parameter, dimension(2) :: num_conc = &
39-
[3.2d9, 2.9d9] ! TODO #141
40-
real(kind=dp), parameter, dimension(2) :: diams = [2d-8, 1.16d-7] ! TODO #141
41-
real(kind=dp), parameter, dimension(2) :: std = [1.45,1.65] ! TODO #141
42-
character(len=10), parameter, dimension(2) :: mode_names = ["init_small","init_large"]
43-
integer :: n_spec, n_modes, i_mode, i_spec
44-
integer :: n_part_added, source
45-
logical, parameter :: hardcoded_init = .true.
46-
4736
call c_f_pointer(ptr_c, ptr_f)
4837
call c_f_pointer(aero_data_ptr_c, aero_data_ptr_f)
4938

5039
call aero_state_zero(ptr_f)
5140
call fractal_set_spherical(aero_data_ptr_f%fractal)
52-
53-
if (hardcoded_init) then
54-
n_modes = 2 ! TODO #141
55-
n_spec = aero_data_n_spec(aero_data_ptr_f)
56-
if (n_spec > 1) then
57-
allocate(aero_dist_init%mode(n_modes))
58-
do i_mode = 1,n_modes
59-
aero_dist_init%mode(i_mode)%name = mode_names(i_mode)
60-
aero_dist_init%mode(i_mode)%type = AERO_MODE_TYPE_LOG_NORMAL
61-
aero_dist_init%mode(i_mode)%char_radius = diams(i_mode) / 2
62-
aero_dist_init%mode(i_mode)%log10_std_dev_radius = &
63-
log10(std(i_mode))
64-
aero_dist_init%mode(i_mode)%num_conc = num_conc(i_mode)
65-
allocate(aero_dist_init%mode(i_mode)%vol_frac(n_spec))
66-
aero_dist_init%mode(i_mode)%vol_frac = 0.0
67-
if (i_mode == 1) then
68-
i_spec = aero_data_spec_by_name(aero_data_ptr_f, "SO4")
69-
aero_dist_init%mode(i_mode)%vol_frac(i_spec) = 1.0
70-
else
71-
i_spec = aero_data_spec_by_name(aero_data_ptr_f, "OC")
72-
aero_dist_init%mode(i_mode)%vol_frac(i_spec) = .8
73-
i_spec = aero_data_spec_by_name(aero_data_ptr_f, "BC")
74-
aero_dist_init%mode(i_mode)%vol_frac(i_spec) = .2
75-
end if
76-
allocate(aero_dist_init%mode(i_mode)%vol_frac_std(n_spec))
77-
aero_dist_init%mode(i_mode)%vol_frac_std = 0.0
78-
source = aero_data_source_by_name(aero_data_ptr_f, mode_names(i_mode))
79-
aero_dist_init%mode(i_mode)%source = source
80-
end do
81-
end if
82-
end if
83-
8441
call aero_state_set_weight(ptr_f, aero_data_ptr_f, AERO_STATE_WEIGHT_NUMMASS_SOURCE)
8542
call aero_state_set_n_part_ideal(ptr_f, n_part)
86-
87-
if (hardcoded_init) then
88-
call aero_state_add_aero_dist_sample(ptr_f, aero_data_ptr_f, &
89-
aero_dist_init, 1d0, 0d0, &
90-
.true., & ! TODO #121 run_part_opt%allow_doubling, &
91-
.true., & ! TODO #121 run_part_opt%allow_halving)
92-
n_part_added)
93-
end if
94-
9543
end subroutine
9644

9745
subroutine f_aero_state_len(ptr_c, len) bind(C)
@@ -238,7 +186,7 @@ subroutine f_aero_state_crit_rel_humids(ptr_c, aero_data_ptr_c, &
238186

239187
! TODO #130: Add include, exclude, group and groups
240188
subroutine f_aero_state_mixing_state_metrics(ptr_c, aero_data_ptr_c, &
241-
d_alpha, d_gamma, chi) bind(C) !, include, exclude, group, groups)&
189+
d_alpha, d_gamma, chi) bind(C)
242190

243191
type(aero_state_t), pointer :: ptr_f => null()
244192
type(aero_data_t), pointer :: aero_data_ptr_f => null()
@@ -310,4 +258,26 @@ subroutine f_aero_state_rand_particle(ptr_c, ptr_particle_c) bind(C)
310258

311259
end subroutine
312260

261+
subroutine f_aero_state_add_aero_dist_sample(ptr_c, ptr_aero_data_c, &
262+
ptr_aero_dist_c, sample_prop, create_time, allow_doubling, &
263+
allow_halving, n_part_add) bind(C)
264+
265+
type(c_ptr) :: ptr_c, ptr_aero_data_c, ptr_aero_dist_c
266+
type(aero_state_t), pointer :: ptr_f => null()
267+
type(aero_data_t), pointer :: ptr_aero_data_f => null()
268+
type(aero_dist_t), pointer :: ptr_aero_dist_f => null()
269+
real(c_double) :: sample_prop, create_time
270+
logical(c_bool) :: allow_doubling, allow_halving
271+
integer(c_int) :: n_part_add
272+
273+
call c_f_pointer(ptr_c, ptr_f)
274+
call c_f_pointer(ptr_aero_data_c,ptr_aero_data_f)
275+
call c_f_pointer(ptr_aero_dist_c,ptr_aero_dist_f)
276+
277+
call aero_state_add_aero_dist_sample(ptr_f, ptr_aero_data_f, &
278+
ptr_aero_dist_f, sample_prop, create_time, LOGICAL(allow_doubling), &
279+
logical(allow_halving), n_part_add)
280+
281+
end subroutine
282+
313283
end module

src/aero_state.hpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "pmc_resource.hpp"
1010
#include "aero_data.hpp"
11+
#include "aero_dist.hpp"
1112
#include "aero_particle.hpp"
1213
#include "env_state.hpp"
1314
#include "bin_grid.hpp"
@@ -116,6 +117,17 @@ extern "C" void f_aero_state_rand_particle(
116117
const void *ptr_particle_c
117118
) noexcept;
118119

120+
extern "C" void f_aero_state_add_aero_dist_sample(
121+
const void *ptr_c,
122+
const void *ptr_aero_data_c,
123+
const void *ptr_aero_dist_c,
124+
const double *sample_prop,
125+
const double *create_time,
126+
const bool *allow_doubling,
127+
const bool *allow_halving,
128+
int *n_part_add
129+
) noexcept;
130+
119131
struct AeroState {
120132
PMCResource ptr;
121133
std::shared_ptr<AeroData> aero_data;
@@ -355,4 +367,28 @@ struct AeroState {
355367

356368
return ptr;
357369
}
370+
371+
static int dist_sample(
372+
const AeroState &self,
373+
const AeroDist &aero_dist,
374+
const double &sample_prop,
375+
const double &create_time,
376+
const bool &allow_doubling,
377+
const bool &allow_halving
378+
) {
379+
int n_part_add = 0;
380+
381+
f_aero_state_add_aero_dist_sample(
382+
self.ptr.f_arg(),
383+
self.aero_data->ptr.f_arg(),
384+
aero_dist.ptr.f_arg(),
385+
&sample_prop,
386+
&create_time,
387+
&allow_doubling,
388+
&allow_halving,
389+
&n_part_add
390+
);
391+
return n_part_add;
392+
393+
}
358394
};

src/pypartmc.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ PYBIND11_MODULE(_PyPartMC, m) {
167167
"returns the particle of a given index")
168168
.def("rand_particle", AeroState::get_random_particle,
169169
"returns a random particle from the population")
170+
.def("dist_sample", AeroState::dist_sample,
171+
"sample particles for AeroState from an AeroDist")
170172
;
171173

172174
py::class_<GasData, std::shared_ptr<GasData>>(m, "GasData",

tests/test_aero_dist.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@
1313
import PyPartMC as ppmc
1414

1515
from .test_aero_data import AERO_DATA_CTOR_ARG_MINIMAL
16-
from .test_aero_mode import AERO_MODE_CTOR_LOG_NORMAL
16+
from .test_aero_mode import AERO_MODE_CTOR_LOG_NORMAL, AERO_MODE_CTOR_LOG_NORMAL_FULL
1717

1818
AERO_DIST_CTOR_ARG_MINIMAL = [
1919
AERO_MODE_CTOR_LOG_NORMAL,
2020
]
2121

22+
AERO_DIST_CTOR_ARG_FULL = [
23+
AERO_MODE_CTOR_LOG_NORMAL_FULL,
24+
]
25+
2226

2327
@pytest.fixture
2428
def sut_minimal():

tests/test_aero_mode.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@
2323
}
2424
}
2525

26+
AERO_MODE_CTOR_LOG_NORMAL_FULL = {
27+
"test_mode": {
28+
"mass_frac": [{"SO4": [1]}],
29+
"diam_type": "geometric",
30+
"mode_type": "log_normal",
31+
"num_conc": 100 / si.m**3,
32+
"geom_mean_diam": 2 * si.um,
33+
"log10_geom_std_dev": np.log10(1.6),
34+
}
35+
}
36+
2637

2738
class TestAeroMode:
2839
@staticmethod

tests/test_aero_state.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,29 @@
1313
import PyPartMC as ppmc
1414

1515
from .test_aero_data import AERO_DATA_CTOR_ARG_FULL, AERO_DATA_CTOR_ARG_MINIMAL
16+
from .test_aero_dist import AERO_DIST_CTOR_ARG_FULL, AERO_DIST_CTOR_ARG_MINIMAL
1617
from .test_env_state import ENV_STATE_CTOR_ARG_MINIMAL
1718

1819
AERO_STATE_CTOR_ARG_MINIMAL = 44
1920

2021

2122
@pytest.fixture
2223
def sut_minimal():
24+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
25+
aero_dist = ppmc.AeroDist(aero_data, AERO_DIST_CTOR_ARG_MINIMAL)
26+
sut = ppmc.AeroState(AERO_STATE_CTOR_ARG_MINIMAL, aero_data)
27+
_ = sut.dist_sample(aero_dist, 1.0, 0.0, True, True)
28+
aero_data = None
29+
gc.collect()
30+
return sut
31+
32+
33+
@pytest.fixture
34+
def sut_full():
2335
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_FULL)
36+
aero_dist = ppmc.AeroDist(aero_data, AERO_DIST_CTOR_ARG_FULL)
2437
sut = ppmc.AeroState(AERO_STATE_CTOR_ARG_MINIMAL, aero_data)
38+
_ = sut.dist_sample(aero_dist, 1.0, 0.0, True, True)
2539
aero_data = None
2640
gc.collect()
2741
return sut
@@ -40,18 +54,20 @@ def test_ctor():
4054
assert sut is not None
4155

4256
@staticmethod
43-
@pytest.mark.xfail(strict=True) # TODO #116
44-
@pytest.mark.parametrize("n_part", (1, 44, 666))
57+
@pytest.mark.parametrize("n_part", (44, 666))
4558
def test_len(n_part):
4659
# arrange
4760
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
61+
aero_dist = ppmc.AeroDist(aero_data, AERO_DIST_CTOR_ARG_MINIMAL)
4862
sut = ppmc.AeroState(n_part, aero_data)
63+
_ = sut.dist_sample(aero_dist, 1.0, 0.0, True, True)
4964

5065
# act
5166
size = len(sut)
5267

5368
# assert
54-
assert size == n_part
69+
assert int(size) > n_part * 0.5
70+
assert int(size) < n_part * 2
5571

5672
@staticmethod
5773
def test_copy(sut_minimal): # pylint: disable=redefined-outer-name
@@ -128,18 +144,18 @@ def test_diameters(sut_minimal): # pylint: disable=redefined-outer-name
128144
assert len(diameters) == len(sut_minimal)
129145

130146
@staticmethod
131-
def test_crit_rel_humids(sut_minimal): # pylint: disable=redefined-outer-name
147+
def test_crit_rel_humids(sut_full): # pylint: disable=redefined-outer-name
132148
# arrange
133149
args = {"rel_humidity": 0.8, **ENV_STATE_CTOR_ARG_MINIMAL}
134150
env_state = ppmc.EnvState(args)
135151
env_state.set_temperature(300)
136152

137153
# act
138-
crit_rel_humids = sut_minimal.crit_rel_humids(env_state)
154+
crit_rel_humids = sut_full.crit_rel_humids(env_state)
139155

140156
# assert
141157
assert isinstance(crit_rel_humids, list)
142-
assert len(crit_rel_humids) == len(sut_minimal)
158+
assert len(crit_rel_humids) == len(sut_full)
143159
assert (np.asarray(crit_rel_humids) > 1).all()
144160
assert (np.asarray(crit_rel_humids) < 1.2).all()
145161

@@ -155,7 +171,7 @@ def test_mixing_state(sut_minimal): # pylint: disable=redefined-outer-name
155171
@staticmethod
156172
def test_bin_average_comp(sut_minimal): # pylint: disable=redefined-outer-name
157173
# arrange
158-
bin_grid = ppmc.BinGrid(123, "log", 1, 100)
174+
bin_grid = ppmc.BinGrid(123, "log", 1e-9, 1e-4)
159175

160176
# act
161177
sut_minimal.bin_average_comp(bin_grid)
@@ -214,3 +230,14 @@ def test_get_particle_out_of_range(
214230

215231
# assert
216232
assert False
233+
234+
@staticmethod
235+
def test_dist_sample():
236+
n_part = 44
237+
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
238+
aero_dist = ppmc.AeroDist(aero_data, AERO_DIST_CTOR_ARG_MINIMAL)
239+
sut = ppmc.AeroState(n_part, aero_data)
240+
n_added = sut.dist_sample(aero_dist, 1.0, 0.0, True, True)
241+
242+
assert n_added > n_part * 0.5
243+
assert n_added < n_part * 2

0 commit comments

Comments
 (0)