Skip to content

Commit 6b027c5

Browse files
authored
Merge pull request #131 from jcurtis2/gas_improvements
make gas state more functional
2 parents 159f630 + 7ac7a94 commit 6b027c5

File tree

8 files changed

+152
-71
lines changed

8 files changed

+152
-71
lines changed

src/gas_data.F90

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,20 @@ subroutine f_gas_data_from_json(ptr_c) bind(C)
4646
call spec_file_read_gas_data(nofile, ptr_f)
4747
end subroutine
4848

49+
subroutine f_gas_data_spec_by_name(ptr_c, value, name_data, name_size) &
50+
bind(C)
51+
type(gas_data_t), pointer :: ptr_f => null()
52+
type(c_ptr), intent(in) :: ptr_c
53+
character(kind=c_char), intent(in) :: name_data
54+
integer(c_int), intent(in) :: name_size
55+
integer(c_int) :: value
56+
57+
character(len=name_size) :: name
58+
59+
call c_f_pointer(ptr_c, ptr_f)
60+
name = name_data(1:name_size)
61+
value = gas_data_spec_by_name(ptr_f, name)
62+
63+
end subroutine
64+
4965
end module

src/gas_data.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ extern "C" void f_gas_data_dtor(void *ptr) noexcept;
1414
extern "C" void f_gas_data_len(const void *ptr, int *len) noexcept;
1515
extern "C" void f_gas_data_from_json(const void *ptr) noexcept;
1616
extern "C" void f_gas_data_to_json(const void *ptr) noexcept;
17+
extern "C" void f_gas_data_spec_by_name(const void *ptr, int *value, const char *name_data,
18+
const int *name_size) noexcept;
1719

1820
struct GasData {
1921
PMCResource ptr;
@@ -43,6 +45,14 @@ struct GasData {
4345
int len;
4446
f_gas_data_len(&self.ptr, &len);
4547
return len;
46-
}
48+
}
49+
50+
static int spec_by_name(const GasData &self, const std::string &name) {
51+
int value;
52+
const int name_size = name.size();
53+
f_gas_data_spec_by_name(&self.ptr, &value, name.c_str(), &name_size);
54+
if (value==0) throw std::runtime_error("Element not found.");
55+
return value-1;
56+
}
4757
};
4858

src/gas_state.F90

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,17 @@ subroutine f_gas_state_get_item(ptr_c, idx, val) bind(C)
5757
val = ptr_f%mix_rat(idx+1)
5858
end subroutine
5959

60-
subroutine f_gas_state_from_json(ptr_c) bind(C)
60+
subroutine f_gas_state_from_json(ptr_c, gas_data_ptr_c) bind(C)
6161
type(gas_state_t), pointer :: ptr_f => null()
6262
type(c_ptr), intent(in) :: ptr_c
63+
type(c_ptr), intent(in) :: gas_data_ptr_c
6364

64-
type(gas_data_t), pointer :: gas_data => null()
65+
type(gas_data_t), pointer :: gas_data_ptr_f => null()
6566
integer :: ncid
6667

6768
call c_f_pointer(ptr_c, ptr_f)
68-
call gas_state_input_netcdf(ptr_f, ncid, gas_data)
69+
call c_f_pointer(gas_data_ptr_c, gas_data_ptr_f)
70+
call gas_state_input_netcdf(ptr_f, ncid, gas_data_ptr_f)
6971
end subroutine
7072

7173
subroutine f_gas_state_to_json(ptr_c) bind(C)
@@ -80,4 +82,16 @@ subroutine f_gas_state_to_json(ptr_c) bind(C)
8082
call gas_state_output_netcdf(ptr_f, ncid, gas_data)
8183
deallocate(gas_data) ! TODO #122
8284
end subroutine
85+
86+
subroutine f_gas_state_set_size(ptr_c, gas_data_ptr_c) bind(C)
87+
type(c_ptr), intent(inout) :: ptr_c
88+
type(c_ptr), intent(in) :: gas_data_ptr_c
89+
type(gas_state_t), pointer :: ptr_f => null()
90+
type(gas_data_t), pointer :: gas_data_ptr_f => null()
91+
92+
call c_f_pointer(ptr_c, ptr_f)
93+
call c_f_pointer(gas_data_ptr_c, gas_data_ptr_f)
94+
call gas_state_set_size(ptr_f, gas_data_n_spec(gas_data_ptr_f))
95+
96+
end subroutine
8397
end module

src/gas_state.hpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "nlohmann/json.hpp"
1111
#include "gimmicks.hpp"
1212
#include "pmc_resource.hpp"
13+
#include "gas_data.hpp"
1314

1415
extern "C" void f_gas_state_ctor(void *ptr) noexcept;
1516
extern "C" void f_gas_state_dtor(void *ptr) noexcept;
@@ -18,21 +19,32 @@ extern "C" void f_gas_state_get_item(const void *ptr, const int *idx, double *va
1819
extern "C" void f_gas_state_len(const void *ptr, int *len) noexcept;
1920
extern "C" void f_gas_state_to_json(const void *ptr) noexcept;
2021
extern "C" void f_gas_state_from_json(const void *ptr) noexcept;
22+
extern "C" void f_gas_state_set_size(const void *ptr, const void *gasdata_ptr) noexcept;
23+
extern "C" void f_gas_state_mix_rats(const void *ptr, const double *data, const int *len);
2124

2225
struct GasState {
2326
PMCResource ptr;
2427

25-
GasState(const nlohmann::json &json) :
28+
/* GasState(const GasData &gas_data,
29+
const nlohmann::json &json) :
2630
ptr(f_gas_state_ctor, f_gas_state_dtor)
2731
{
2832
gimmick_ptr() = std::make_unique<InputGimmick>(json);
2933
3034
const int n = json.empty() ? 0 : gimmick_ptr()->find("gas_mixing_ratio")->size();
35+
f_gas_state_set_size(this->ptr.f_arg(), &gas_data.ptr);
3136
//f_gas_state_set_size(this->ptr.f_arg(), &n);
3237
if (n != 0) f_gas_state_from_json(this->ptr.f_arg());
3338
3439
gimmick_ptr().reset(); // TODO #117: guard
3540
}
41+
*/
42+
43+
GasState(const GasData &gas_data) :
44+
ptr(f_gas_state_ctor, f_gas_state_dtor)
45+
{
46+
f_gas_state_set_size(this->ptr.f_arg(), &gas_data.ptr);
47+
}
3648

3749
static void set_item(const GasState &self, const int &idx, const double &val) {
3850
if (idx < 0 || idx >= (int)__len__(self))
@@ -63,4 +75,29 @@ struct GasState {
6375
f_gas_state_len(&self.ptr, &len);
6476
return len;
6577
}
78+
79+
static double mix_rat(const GasState &self, const GasData &gasData,
80+
const std::string &name) {
81+
int value;
82+
const int name_size = name.size();
83+
84+
f_gas_data_spec_by_name(&gasData.ptr, &value, name.c_str(), &name_size);
85+
if (value==0) throw std::runtime_error("Element not found.");
86+
return get_item(self, value-1);
87+
}
88+
89+
static void set_size(GasState &self, const GasData &GasData) {
90+
f_gas_state_set_size(&self.ptr, &GasData.ptr);
91+
}
92+
93+
static std::valarray<double> mix_rats(const GasState &self) {
94+
int len;
95+
f_gas_state_len(&self.ptr, &len);
96+
std::valarray<double> data(len);
97+
98+
for (int idx = 0; idx < len; idx++) {
99+
f_gas_state_get_item(&self.ptr, &idx, &data[idx]);
100+
}
101+
return data;
102+
}
66103
};

src/pypartmc.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,11 @@ PYBIND11_MODULE(_PyPartMC, m) {
170170
)
171171
.def(py::init<const py::tuple&>())
172172
.def("__len__", GasData::__len__)
173+
.def_property_readonly("n_spec", GasData::__len__)
173174
.def("__str__", GasData::__str__,
174175
"returns a string with JSON representation of the object")
176+
.def("spec_by_name", GasData::spec_by_name,
177+
"returns the number of the species in gas with the given name")
175178
;
176179

177180
py::class_<EnvState>(m,
@@ -254,15 +257,22 @@ PYBIND11_MODULE(_PyPartMC, m) {
254257
it. This will be the case for new \c gas_state_t structures.
255258
)pbdoc"
256259
)
257-
.def(py::init<const nlohmann::json&>(),
258-
"instantiates and initializes from a JSON object", py::arg(0) = py::dict())
260+
.def(py::init<const GasData&>(),
261+
"instantiates and initializes based on GasData")
259262
.def("__setitem__", GasState::set_item)
260263
//.def("__setitem__", GasState::set_items)
261264
.def("__getitem__", GasState::get_item)
262265
//.def("__getitem__", GasState::get_items)
263266
.def("__len__", GasState::__len__)
267+
.def_property_readonly("n_spec", GasState::__len__)
264268
.def("__str__", GasState::__str__,
265269
"returns a string with JSON representation of the object")
270+
.def("set_size", GasState::set_size,
271+
"sets the GasState to the size of GasData")
272+
.def("mix_rat", GasState::mix_rat,
273+
"returns the mixing ratio of a gas species")
274+
.def_property_readonly("mix_rats", GasState::mix_rats,
275+
"returns array of mixing ratios")
266276
;
267277

268278
py::class_<RunPartOpt>(m,

tests/test_dtors.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111
import PyPartMC as ppmc
1212

1313
from .test_aero_data import AERO_DATA_CTOR_ARG_MINIMAL
14+
from .test_gas_data import GAS_DATA_CTOR_ARG_MINIMAL
1415

1516

1617
@pytest.mark.parametrize(
1718
"sut",
1819
(
1920
pytest.param(ppmc.GasData(("SO2",)), id="GasData"),
2021
pytest.param(ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL), id="AeroData"),
21-
pytest.param(ppmc.GasState(), id="GasState"),
22+
pytest.param(
23+
ppmc.GasState(ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)), id="GasState"
24+
),
2225
pytest.param(
2326
ppmc.AeroParticle(ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL), [0]),
2427
id="AeroParticle",

tests/test_gas_state.py

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
# import numpy as np
1313
import PyPartMC as ppmc
1414

15+
from .test_gas_data import GAS_DATA_CTOR_ARG_MINIMAL
16+
17+
GAS_DATA_MINIMAL = ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)
18+
1519

1620
class TestGasState:
1721
@staticmethod
@@ -29,104 +33,91 @@ def test_ctor_error():
2933
# assert
3034
# assert False
3135

32-
@staticmethod
33-
def test_ctor_emtpy():
34-
# arrange
35-
pass
36-
37-
# act
38-
sut = ppmc.GasState()
39-
40-
# assert
41-
isinstance(sut, ppmc.GasState)
42-
4336
@staticmethod
4437
def test_ctor_valid():
4538
# arrange
46-
pass
47-
48-
# act
49-
# TODO #123 sut = ppmc.GasState({"gas_mixing_ratio":''})
39+
sut = ppmc.GasState(GAS_DATA_MINIMAL)
5040

5141
# assert
52-
# TODO #123 assert isinstance(sut, ppmc.GasState)
53-
54-
@staticmethod
55-
def test_len_empty():
56-
# arrange
57-
pass
58-
# sut = ppmc.GasState()
59-
60-
# act
61-
# size = len(sut)
62-
63-
# assert
64-
# assert isinstance(size, int)
65-
# assert size == 0 # TODO #123: test non-empty len
42+
assert isinstance(sut, ppmc.GasState)
6643

6744
@staticmethod
6845
@pytest.mark.parametrize("idx", (-1, 100))
6946
def test_get_item_out_of_range(idx):
7047
# arrange
71-
pass
72-
# sut = ppmc.GasState()
48+
sut = ppmc.GasState(GAS_DATA_MINIMAL)
7349

7450
# act
75-
# try:
76-
# value = sut[idx]
77-
# except IndexError:
78-
# return
51+
try:
52+
value = sut[idx]
53+
except IndexError:
54+
return
7955

80-
# assert
81-
# assert False
56+
assert False
8257

8358
@staticmethod
8459
def test_get_item_valid():
85-
pass
8660
# arrange
87-
# sut = ppmc.GasState({'gas_mixing_ratio': (44,)})
88-
61+
sut = ppmc.GasState(GAS_DATA_MINIMAL)
62+
sut[0] = 44
8963
# act
90-
# value = sut[0]
64+
value = sut[0]
9165

9266
# assert
93-
# assert isinstance(value, float)
94-
# assert value == 44 # TODO #123
67+
assert isinstance(value, float)
68+
assert value == 44
9569

9670
@staticmethod
9771
def test_get_items():
9872
# arrange
99-
sut = ppmc.GasState()
73+
gas_data = ppmc.GasData(
74+
(
75+
"SO2",
76+
"NO2",
77+
"NO",
78+
"CO",
79+
)
80+
)
81+
sut = ppmc.GasState(gas_data)
10082

10183
# act
102-
# values = sut[:] TODO #123
84+
values = sut.mix_rats
10385

10486
# assert
105-
# assert isinstance(values, np.ndarray)
106-
# assert len(sut) == len(values)
87+
assert isinstance(values, list)
88+
assert len(sut) == len(values)
10789

10890
@staticmethod
10991
def test_set_item():
11092
# arrange
111-
sut = ppmc.GasState() # TODO #123
112-
idx = 1
93+
sut = ppmc.GasState(GAS_DATA_MINIMAL)
94+
idx = 0
11395
val = 1234
11496

11597
# act
116-
# sut[idx] = val TODO #123
98+
sut[idx] = val
11799

118100
# assert
119-
# assert sut[idx] == value TODO #123
101+
assert sut[idx] == val
120102

121103
@staticmethod
122-
def test_to_json():
123-
# arrange
124-
data_in = {} # TODO #123
125-
sut = ppmc.GasState(data_in)
126-
127-
# act
128-
data_out = str(sut)
129-
print(data_out)
130-
131-
# assert
132-
# assert data_in == data_out TODO #123
104+
def test_get_mix_rats():
105+
106+
gas_data = GAS_DATA_MINIMAL
107+
sut = ppmc.GasState(gas_data)
108+
109+
assert len(sut.mix_rats) == len(sut)
110+
111+
112+
# @staticmethod
113+
# def test_to_json():
114+
# # arrange
115+
# data_in = {} # TODO #123
116+
# sut = ppmc.GasState(data_in)
117+
#
118+
# # act
119+
# data_out = str(sut)
120+
# print(data_out)
121+
#
122+
# # assert
123+
# # assert data_in == data_out TODO #123

tests/test_run_part.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_args():
2323
aero_data = ppmc.AeroData(AERO_DATA_CTOR_ARG_MINIMAL)
2424
aero_state = ppmc.AeroState(AERO_STATE_CTOR_ARG_MINIMAL, aero_data)
2525
gas_data = ppmc.GasData(GAS_DATA_CTOR_ARG_MINIMAL)
26-
gas_state = ppmc.GasState()
26+
gas_state = ppmc.GasState(gas_data)
2727
scenario = ppmc.Scenario(gas_data, aero_data, SCENARIO_CTOR_ARG_MINIMAL)
2828
run_part_opt = ppmc.RunPartOpt(RUN_PART_OPT_CTOR_ARG_MINIMAL)
2929
camp_core = ppmc.CampCore()

0 commit comments

Comments
 (0)