9from numpy.testing
import assert_array_almost_equal
10from numpy.testing
import assert_almost_equal
11from cyclus.lib
import Env
12from cyclus.system
import CY_NEAR_ZERO
14from pytest
import skip
17from helper
import run_cyclus
20ALLOW_MILPS = Env().allow_milps
24 """A don't run certain tests if MILPs are disabled."""
26 raise skip(
"Cyclus was compiled without MILPS support or the "
27 "ALLOW_MILPS env var was not set to true.")
31 """A base class for all regression tests. A derived class is required for
32 each new input file to be tested. Each derived class *must* declare an `inf`
33 member in their `__init__` function that points to the input file to be
34 tested, e.g., `self.inf_ = ./path/to/my/input_file.xml. See below for
43 raise TypeError((
"cls.inf must be set in derived classes "
44 "to run regression tests."))
45 run_cyclus(
"cyclus", os.getcwd(), cls.
inf, cls.
outf)
49 with tables.open_file(cls.
outf, mode=
"r")
as f:
53 if "/AgentExit" in f \
56 if "/Enrichments" in f \
61 cls.
info = f.get_node(
"/Info")[:]
63 x[
"ResourceId"]: x[
"Quantity"]
for x
in cls.
resources}
66 cls.
conn.row_factory = sqlite3.Row
69 cls.
agent_entry = exc(
'SELECT * FROM AgentEntry').fetchall()
70 cls.
agent_exit = exc(
'SELECT * FROM AgentExit').fetchall() \
72 (
"SELECT * FROM sqlite_master WHERE "
73 "type='table' AND name='AgentExit'")).fetchall()) > 0 \
75 cls.
enrichments = exc(
'SELECT * FROM Enrichments').fetchall() \
77 (
"SELECT * FROM sqlite_master WHERE "
78 "type='table' AND name='Enrichments'")).fetchall()) > 0 \
80 cls.
resources = exc(
'SELECT * FROM Resources').fetchall()
81 cls.
transactions = exc(
'SELECT * FROM Transactions').fetchall()
82 cls.
compositions = exc(
'SELECT * FROM Compositions').fetchall()
83 cls.
info = exc(
'SELECT * FROM Info').fetchall()
85 x[
"ResourceId"]: x[
"Quantity"]
for x
in cls.
resources}
88 def find_ids(cls, spec, a, spec_col="Spec", id_col="AgentId"):
92 return [x[id_col]
for x
in a
if x[spec_col] == spec]
96 if cls.
ext ==
'.sqlite':
97 return np.array([x[k]
for x
in a])
103 if cls.
ext ==
'.sqlite':
105 if os.path.isfile(cls.
outf):
106 print(
"removing {0}".format(cls.
outf))
110 """This class tests the 1_Enrichment_2_Reactor.xml file related to the
111 Cyclus Physor 2014 publication. The number of key facilities, the enrichment
112 values, and the transactions to each reactor are tested.
122 assert len(self.
rx_id) == 2
123 assert len(self.
enr_id) == 1
130 exp = [6.85, 9.94, 4.11, 6.85]
131 obs = [np.sum(self.
to_ary(enr,
"SWU")[
132 self.
to_ary(enr,
"Time") == t])
for t
in range(4)]
133 assert_array_almost_equal(exp, obs, decimal=2)
141 exp = [13.14, 16.69, 7.88, 13.14]
142 obs = [np.sum(self.
to_ary(enr,
"Natural_Uranium")[
143 self.
to_ary(enr,
"Time") == t])
for t
in range(4)]
144 assert_array_almost_equal(exp, obs, decimal=2)
151 if tx[
'ReceiverId'] == self.
rx_id[0]:
152 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
154 msg =
"Testing that first reactor gets less than it wants."
155 assert_array_almost_equal(exp, txs, decimal=2, err_msg=msg)
159 exp = [1, 0.8, 0.2, 1]
162 if tx[
'ReceiverId'] == self.
rx_id[1]:
163 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
165 msg =
"Testing that second reactor gets what it wants."
166 assert_array_almost_equal(exp, txs, decimal=2, err_msg=msg)
172 super(TestCBCPhysorEnrichment, cls).
setup_class(
"../input/physor/1_Enrichment_2_Reactor.xml")
177 super(TestGreedyPhysorEnrichment, cls).
setup_class(
"../input/physor/greedy_1_Enrichment_2_Reactor.xml")
180 """This class tests the 2_Sources_3_Reactor.xml file related to the Cyclus
181 Physor 2014 publication. Reactor deployment and transactions between
182 suppliers and reactors are tested.
189 rx_id = cls.
find_ids(
":cycamore:Reactor", tbl)
191 s_id = cls.
find_ids(
":cycamore:Source", tbl)
193 s_id.remove(cls.
smox)
197 depl_time = {x[
"AgentId"]: x[
"EnterTime"]
for x
in self.
agent_entry}
199 assert depl_time[self.
r1] == 1
200 assert depl_time[self.
r2] == 2
201 assert depl_time[self.
r3] == 3
204 mox_exp = [0, 1, 1, 1, 0]
205 txs = [0, 0, 0, 0, 0]
207 if tx[
'ReceiverId'] == self.
r1 and tx[
'SenderId'] == self.
smox:
208 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
209 assert_array_almost_equal(mox_exp, txs)
211 uox_exp = [0, 0, 0, 0, 1]
212 txs = [0, 0, 0, 0, 0]
214 if tx[
'ReceiverId'] == self.
r1 and tx[
'SenderId'] == self.
suox:
215 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
216 assert_array_almost_equal(uox_exp, txs)
219 mox_exp = [0, 0, 1, 1, 1]
220 txs = [0, 0, 0, 0, 0]
222 if tx[
'ReceiverId'] == self.
r2 and tx[
'SenderId'] == self.
smox:
223 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
224 assert_array_almost_equal(mox_exp, txs)
226 uox_exp = [0, 0, 0, 0, 0]
227 txs = [0, 0, 0, 0, 0]
229 if tx[
'ReceiverId'] == self.
r2 and tx[
'SenderId'] == self.
suox:
230 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
231 assert_array_almost_equal(uox_exp, txs)
234 mox_exp = [0, 0, 0, 0.5, 1]
235 txs = [0, 0, 0, 0, 0]
237 if tx[
'ReceiverId'] == self.
r3 and tx[
'SenderId'] == self.
smox:
238 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
239 assert_array_almost_equal(mox_exp, txs)
241 uox_exp = [0, 0, 0, 0.5, 0]
242 txs = [0, 0, 0, 0, 0]
244 if tx[
'ReceiverId'] == self.
r3 and tx[
'SenderId'] == self.
suox:
245 txs[tx[
'Time']] += self.
rsrc_qtys[tx[
'ResourceId']]
246 assert_array_almost_equal(uox_exp, txs)
252 super(TestCBCPhysorSources, cls).
setup_class(
"../input/physor/2_Sources_3_Reactors.xml")
257 return super(TestGreedyPhysorSources, cls).
setup_class(
"../input/physor/greedy_2_Sources_3_Reactors.xml")
260 """Tests dynamic capacity restraints involving changes in the number of
261 source and sink facilities.
263 A source facility is expected to offer a commodity of amount 1,
264 and a sink facility is expected to request for a commodity of amount 1.
265 Therefore, number of facilities correspond to the amounts of offers
268 At time step 1, 3 source facilities and 2 sink facilities are deployed, and
269 at time step 2, additional 2 sink facilities are deployed. After time
270 step 2, the older 2 sink facilities are decommissioned.
271 According to this deployment schedule, at time step 1, only 2 transactions
272 are expected, the number of sink facilities being the constraint; whereas,
273 at time step 2, only 3 transactions are expected, the number of source
274 facilities being the constraint. At time step 3, after decommissioning 2
275 older sink facilities, the remaining number of sink facilities becomes
276 the constraint, resulting in the same transaction amount as in time step 1.
281 super(TestDynamicCapacitated, cls).
setup_class(
"./input/dynamic_capacitated.xml")
330 assert len(np.where(self.
source_id == s)[0]) == 1
332 assert len(np.where(self.
sink_id == r)[0]) == 1
336 assert len(np.where(self.
trans_time == 1)[0]) == 2
338 assert len(np.where(self.
trans_time == 2)[0]) == 3
340 assert len(np.where(self.
trans_time == 3)[0]) == 2
368 """This class tests the growth.xml
370 Tests GrowthRegion, ManagerInst, and Source over a 4-time step
373 A linear growth demand (y = x + 2) is provided to the growth region. Two
374 Sources are allowed in the ManagerInst, with capacities of 2 and 1.1,
375 respectively. At t=1, a 2-capacity Source is expected to be built, and at
376 t=2 and t=3, 1-capacity Sources are expected to be built.
378 A linear growth demand (y = 0x + 3) for a second commodity is provided at t=2
379 to test the demand for multiple commodities.
384 super(TestGrowth1, cls).
setup_class(
"./input/growth.xml")
397 spec_col=
"Prototype")
399 spec_col=
"Prototype")
401 spec_col=
"Prototype")
403 assert len(source2_id) == 1
404 assert len(source1_id) == 2
405 assert len(source3_id) == 3
407 assert enter_time[np.where(agent_ids == source2_id[0])] == 1
408 assert enter_time[np.where(agent_ids == source1_id[0])] == 2
409 assert enter_time[np.where(agent_ids == source1_id[1])] == 3
411 assert enter_time[np.where(agent_ids == x)] == 2
414 """This class tests the ./input/deploy_and_manager_insts.xml
416 Tests GrowthRegion, ManagerInst, DeployInst, and Source over a 10-time step
419 A linear growth demand (y = 5) is provided to the growth region. One
420 Source is allowed in the ManagerInst, with capacity of 1.
421 At t=1, a 1-capacity Source1 is built by the DeployInst, and at
422 t=6, 4 1-capacity Source2s are expected to be built by the ManagerInst.
428 super(TestGrowth2, cls).
setup_class(
"../input/growth/deploy_and_manager_insts.xml")
441 spec_col=
"Prototype")
443 spec_col=
"Prototype")
445 assert len(source1_id) == 1
446 assert len(source2_id) == 4
448 assert enter_time[np.where(agent_ids == source1_id[0])] == 1
449 assert enter_time[np.where(agent_ids == source2_id[0])] == 6
452 """This class tests the ../input/deploy_inst.xml
454 Tests DeployInst, and NullRegion over a 10-time step
457 A DeployInst is used to define that a Source agent is to be deployed at
458 time t=1 within a Null Region. A Sink agent is also deployed as
459 an initial facility. This input is used to test that the Source and
460 Sink agents are deployed at their respecitve times and that the correct
461 number of these agents are deployed.
467 super(TestDeployInst, cls).
setup_class(
"../input/deploy_inst.xml")
480 spec_col=
"Prototype")
483 assert len(source_id) == 1
484 assert len(sink_id) == 1
486 assert enter_time[np.where(agent_ids == source_id[0])] == 1
487 assert enter_time[np.where(agent_ids == sink_id[0])] == 0
490 """This class tests the input/recycle.xml file.
495 base, _ = os.path.splitext(cls.
outfoutf)
499 SELECT t.time as time,SUM(c.massfrac*r.quantity) as qty FROM transactions as t
500 JOIN resources as r ON t.resourceid=r.resourceid AND r.simid=t.simid
501 JOIN agententry as send ON t.senderid=send.agentid AND send.simid=t.simid
502 JOIN agententry as recv ON t.receiverid=recv.agentid AND recv.simid=t.simid
503 JOIN compositions as c ON c.qualid=r.qualid AND c.simid=r.simid
504 WHERE send.prototype=? AND recv.prototype=? AND c.nucid=?
508 conn = sqlite3.connect(self.
outfoutf)
511 simdur = len(exp_invs)
513 invs = [0.0] * simdur
514 for i, row
in enumerate(c.execute(self.
sql, (fromfac, tofac, nuclide))):
518 expfname =
'exp_recycle_{0}-{1}-{2}.dat'.format(fromfac, tofac, nuclide)
519 with open(expfname,
'w')
as f:
520 for t, val
in enumerate(exp_invs):
521 f.write(
'{0} {1}\n'.format(t, val))
522 obsfname =
'obs_recycle_{0}-{1}-{2}.dat'.format(fromfac, tofac, nuclide)
523 with open(obsfname,
'w')
as f:
524 for t, val
in enumerate(invs):
525 f.write(
'{0} {1}\n'.format(t, val))
528 for exp, obs
in zip(invs, exp_invs):
530 exp, obs, err_msg=
'mismatch at t={}, {} != {}'.format(i, exp, obs))
544 exp[113] = 1.70022267
545 exp[132] = 1.70022267
546 exp[151] = 1.70022267
547 exp[170] = 1.70022267
548 exp[189] = 1.70022267
549 exp[208] = 1.70022267
550 exp[246] = 1.70022267
551 exp[265] = 1.70022267
552 exp[284] = 1.70022267
553 exp[303] = 1.70022267
554 exp[322] = 1.70022267
555 exp[341] = 1.70022267
556 exp[360] = 1.70022267
557 exp[379] = 1.70022267
558 exp[417] = 1.70022267
559 exp[436] = 1.70022267
560 exp[455] = 1.70022267
561 exp[474] = 1.70022267
562 exp[493] = 1.70022267
563 exp[512] = 1.70022267
564 exp[531] = 1.70022267
565 exp[569] = 1.70022267
566 exp[588] = 1.70022267
568 self.
do_compare(
'separations',
'repo', 942390000, exp)
573 exp[226] = 420.42772559790944
574 exp[397] = 420.42772559790944
575 exp[549] = 420.42772559790944
576 self.
do_compare(
'reactor',
'repo', 942390000, exp)
579 """This class tests the input/recycle.xml file.
583 super(TestGreedyRecycle, cls).
setup_class(
"../input/greedy_recycle.xml")
586 """This class tests the input/recycle.xml file.
591 super(TestCBCRecycle, cls).
setup_class(
"../input/recycle.xml")
test_source_deployment(self)
test_xaction_general(self)
test_xaction_specific(self)
test_sink_deployment(self)
find_ids(cls, spec, a, spec_col="Spec", id_col="AgentId")
test_rxtr2_xactions(self)
test_rxtr_deployment(self)
test_rxtr1_xactions(self)
test_rxtr3_xactions(self)
do_compare(self, fromfac, tofac, nuclide, exp_invs)
test_pu239_reactor_repo(self)
test_pu239_sep_repo(self)
find_ids(data, data_table, id_table)
skip_if_dont_allow_milps()