@@ -22,13 +22,16 @@ def _make_plant_config(
2222 curtailable = None ,
2323 dispatchable = None ,
2424 storage = None ,
25+ feedstock = None ,
2526 sell_price = 0.06 ,
2627 cost_per_tech = None ,
2728 technology_interconnections = None ,
2829):
2930 """Build a minimal plant_config dict for controller tests."""
30- all_techs = (curtailable or []) + (dispatchable or []) + (storage or [])
31+ all_techs = (curtailable or []) + (dispatchable or []) + (storage or []) + (feedstock or [])
32+
3133 tech_to_commodity = {(t , "electricity" ) for t in all_techs }
34+
3235 config = {
3336 "plant" : {"simulation" : {"n_timesteps" : n_timesteps , "dt" : 3600 }, "plant_life" : 30 },
3437 "system_level_control" : {
@@ -39,6 +42,7 @@ def _make_plant_config(
3942 "curtailable_techs" : curtailable or [],
4043 "dispatchable_techs" : dispatchable or [],
4144 "storage_techs" : storage or [],
45+ "feedstock_techs" : feedstock or [],
4246 "tech_to_commodity" : tech_to_commodity ,
4347 "commodity_sell_price" : sell_price ,
4448 "cost_per_tech" : cost_per_tech or {},
@@ -56,7 +60,8 @@ def _make_slc_config(plant_config):
5660 curtailable = slc .get ("curtailable_techs" , [])
5761 dispatchable = slc .get ("dispatchable_techs" , [])
5862 storage = slc .get ("storage_techs" , [])
59- all_techs = curtailable + dispatchable + storage
63+ feedstock = slc .get ("feedstock_techs" , [])
64+ all_techs = curtailable + dispatchable + storage + feedstock
6065
6166 # Build technology graph
6267 tech_graph = nx .DiGraph ()
@@ -79,6 +84,8 @@ def _make_slc_config(plant_config):
7984 classifiers [t ] = "dispatchable"
8085 for t in storage :
8186 classifiers [t ] = "storage"
87+ for t in feedstock :
88+ classifiers [t ] = "feedstock"
8289
8390 return {
8491 "demand_commodity" : slc ["demand_commodity" ],
@@ -91,7 +98,7 @@ def _make_slc_config(plant_config):
9198 }
9299
93100
94- def _build_problem (slc_cls , plant_config , tech_config = None ):
101+ def _build_problem (slc_cls , plant_config ):
95102 """Create and setup an OpenMDAO Problem with the given controller."""
96103 slc_config = _make_slc_config (plant_config )
97104 prob = om .Problem ()
@@ -100,7 +107,7 @@ def _build_problem(slc_cls, plant_config, tech_config=None):
100107 slc_cls (
101108 driver_config = {},
102109 plant_config = plant_config ,
103- tech_config = tech_config or {},
110+ tech_config = {},
104111 slc_config = slc_config ,
105112 ),
106113 )
@@ -482,22 +489,16 @@ def test_feedstock_single(self):
482489 """feedstock mode: single upstream feedstock drives marginal cost."""
483490 pc = _make_plant_config (
484491 dispatchable = ["ng_plant" ],
492+ feedstock = ["ng_feed" ],
485493 demand = 50000 ,
486494 sell_price = 0.10 ,
487495 cost_per_tech = {"ng_plant" : "feedstock" },
488496 technology_interconnections = [
489497 ["ng_feed" , "ng_plant" , "natural_gas" , "pipe" ],
490498 ],
491499 )
492- tech_config = {
493- "technologies" : {
494- "ng_feed" : {
495- "performance_model" : {"model" : "FeedstockPerformanceModel" },
496- "cost_model" : {"model" : "FeedstockCostModel" },
497- },
498- }
499- }
500- prob = _build_problem (CostMinimizationControl , pc , tech_config = tech_config )
500+
501+ prob = _build_problem (CostMinimizationControl , pc )
501502 prob .set_val ("slc.ng_plant_rated_electricity_production" , 100000 )
502503 # Feedstock VarOpEx: $1M/yr; production: 100 MW * 4 h = 400 MWh
503504 prob .set_val ("slc.ng_feed_VarOpEx" , np .full (30 , 1_000_000.0 ))
@@ -513,6 +514,7 @@ def test_feedstock_multiple(self):
513514 """feedstock mode: multiple upstream feedstocks are summed."""
514515 pc = _make_plant_config (
515516 dispatchable = ["plant" ],
517+ feedstock = ["feed_a" , "feed_b" ],
516518 demand = 50000 ,
517519 sell_price = 0.10 ,
518520 cost_per_tech = {"plant" : "feedstock" },
@@ -522,22 +524,8 @@ def test_feedstock_multiple(self):
522524 ["other_tech" , "plant" , "something" , "cable" ],
523525 ],
524526 )
525- tech_config = {
526- "technologies" : {
527- "feed_a" : {
528- "performance_model" : {"model" : "FeedstockPerformanceModel" },
529- "cost_model" : {"model" : "FeedstockCostModel" },
530- },
531- "feed_b" : {
532- "performance_model" : {"model" : "FeedstockPerformanceModel" },
533- "cost_model" : {"model" : "FeedstockCostModel" },
534- },
535- "other_tech" : {
536- "performance_model" : {"model" : "SomePerformanceModel" },
537- },
538- }
539- }
540- prob = _build_problem (CostMinimizationControl , pc , tech_config = tech_config )
527+
528+ prob = _build_problem (CostMinimizationControl , pc )
541529 prob .set_val ("slc.plant_rated_electricity_production" , 100000 )
542530 # Two feedstocks: $500k and $300k → total $800k/yr
543531 prob .set_val ("slc.feed_a_VarOpEx" , np .full (30 , 500_000.0 ))
@@ -554,22 +542,16 @@ def test_feedstock_profit_max_unprofitable(self):
554542 """feedstock mode in profit max: unprofitable when feedstock costs exceed sell price."""
555543 pc = _make_plant_config (
556544 dispatchable = ["ng_plant" ],
545+ feedstock = ["ng_feed" ],
557546 demand = 50000 ,
558547 sell_price = 0.01 , # very low sell price
559548 cost_per_tech = {"ng_plant" : "feedstock" },
560549 technology_interconnections = [
561550 ["ng_feed" , "ng_plant" , "natural_gas" , "pipe" ],
562551 ],
563552 )
564- tech_config = {
565- "technologies" : {
566- "ng_feed" : {
567- "performance_model" : {"model" : "FeedstockPerformanceModel" },
568- "cost_model" : {"model" : "FeedstockCostModel" },
569- },
570- }
571- }
572- prob = _build_problem (ProfitMaximizationControl , pc , tech_config = tech_config )
553+
554+ prob = _build_problem (ProfitMaximizationControl , pc )
573555 prob .set_val ("slc.ng_plant_rated_electricity_production" , 100000 )
574556 prob .set_val ("slc.commodity_sell_price" , 0.01 )
575557 # Very expensive feedstock: $100M/yr → high marginal cost
@@ -591,12 +573,6 @@ def test_feedstock_no_feedstock_raises(self):
591573 ["some_tech" , "ng_plant" , "electricity" , "cable" ],
592574 ],
593575 )
594- tech_config = {
595- "technologies" : {
596- "some_tech" : {
597- "performance_model" : {"model" : "SomePerformanceModel" },
598- },
599- }
600- }
576+
601577 with pytest .raises (ValueError , match = "at least one feedstock" ):
602- _build_problem (CostMinimizationControl , pc , tech_config = tech_config )
578+ _build_problem (CostMinimizationControl , pc )
0 commit comments