@@ -190,6 +190,64 @@ def test_pathsim_state_advances(self):
190190 self .sim .run (2 )
191191 self .assertFalse (np .allclose (self .cell .engine .state , state_before ))
192192
193+ def test_q_heat_nonzero_during_discharge (self ):
194+ """Q_heat must be strictly positive when a discharge current flows.
195+
196+ With thermal='isothermal' PyBaMM does not compute heat source terms,
197+ so Q_heat would be identically zero — this test guards against that.
198+ """
199+ cell = CellElectrical (initial_soc = 1.0 )
200+ I_src = Constant (5.0 ) # 1C-ish discharge
201+ T_src = Constant (298.15 )
202+ sim = Simulation (
203+ blocks = [I_src , T_src , cell ],
204+ connections = [
205+ Connection (I_src , cell ["I" ]),
206+ Connection (T_src , cell ["T_cell" ]),
207+ ],
208+ dt = 10.0 ,
209+ Solver = ESDIRK43 ,
210+ )
211+ sim .run (60 )
212+ self .assertGreater (
213+ cell .outputs [1 ],
214+ 0.0 ,
215+ "Q_heat is zero — thermal model may not compute heat sources" ,
216+ )
217+
218+ def test_temperature_input_affects_voltage (self ):
219+ """T_cell must actually influence the electrochemistry.
220+
221+ Butler-Volmer kinetics are temperature-dependent, so discharging at
222+ a significantly higher temperature must yield a measurably different
223+ terminal voltage after the same duration.
224+ """
225+
226+ def _run_and_get_voltage (T_cell ):
227+ cell = CellElectrical (initial_soc = 1.0 )
228+ I_src = Constant (5.0 )
229+ T_src = Constant (T_cell )
230+ sim = Simulation (
231+ blocks = [I_src , T_src , cell ],
232+ connections = [
233+ Connection (I_src , cell ["I" ]),
234+ Connection (T_src , cell ["T_cell" ]),
235+ ],
236+ dt = 10.0 ,
237+ Solver = ESDIRK43 ,
238+ )
239+ sim .run (300 )
240+ return cell .outputs [0 ] # terminal voltage [V]
241+
242+ V_cold = _run_and_get_voltage (278.15 ) # 5 °C
243+ V_hot = _run_and_get_voltage (318.15 ) # 45 °C
244+ self .assertNotAlmostEqual (
245+ V_cold ,
246+ V_hot ,
247+ places = 3 ,
248+ msg = "T_cell input has no effect on terminal voltage" ,
249+ )
250+
193251
194252class TestElectrothermal (unittest .TestCase ):
195253 """Integration tests for CellElectrothermal — PathSim integrates the PyBaMM ODE."""
@@ -240,6 +298,58 @@ def test_pathsim_state_advances(self):
240298 self .sim .run (2 )
241299 self .assertFalse (np .allclose (self .cell .engine .state , state_before ))
242300
301+ def test_q_heat_nonzero_during_discharge (self ):
302+ """Q_heat must be strictly positive when a discharge current flows."""
303+ cell = CellElectrothermal (initial_soc = 1.0 )
304+ I_src = Constant (5.0 )
305+ T_src = Constant (298.15 )
306+ sim = Simulation (
307+ blocks = [I_src , T_src , cell ],
308+ connections = [
309+ Connection (I_src , cell ["I" ]),
310+ Connection (T_src , cell ["T_amb" ]),
311+ ],
312+ dt = 10.0 ,
313+ Solver = ESDIRK43 ,
314+ )
315+ sim .run (60 )
316+ self .assertGreater (
317+ cell .outputs [2 ],
318+ 0.0 ,
319+ "Q_heat is zero — thermal model may not compute heat sources" ,
320+ )
321+
322+ def test_tamb_input_affects_cell_temperature (self ):
323+ """T_amb must influence the output cell temperature.
324+
325+ With a lower ambient temperature the cell should run cooler after
326+ the same discharge duration.
327+ """
328+
329+ def _run_and_get_T_cell (T_amb ):
330+ cell = CellElectrothermal (initial_soc = 1.0 )
331+ I_src = Constant (5.0 )
332+ T_src = Constant (T_amb )
333+ sim = Simulation (
334+ blocks = [I_src , T_src , cell ],
335+ connections = [
336+ Connection (I_src , cell ["I" ]),
337+ Connection (T_src , cell ["T_amb" ]),
338+ ],
339+ dt = 10.0 ,
340+ Solver = ESDIRK43 ,
341+ )
342+ sim .run (300 )
343+ return cell .outputs [1 ] # cell temperature [K]
344+
345+ T_cell_cold_amb = _run_and_get_T_cell (278.15 ) # 5 °C ambient
346+ T_cell_hot_amb = _run_and_get_T_cell (318.15 ) # 45 °C ambient
347+ self .assertLess (
348+ T_cell_cold_amb ,
349+ T_cell_hot_amb ,
350+ msg = "T_amb input has no effect on output cell temperature" ,
351+ )
352+
243353
244354class TestCoSimulationElectrical (unittest .TestCase ):
245355 """Integration tests for CellCoSimElectrical — PyBaMM performs the stepping."""
@@ -293,6 +403,55 @@ def test_dfn_step_outputs_physical(self):
293403 self .assertGreater (cell .outputs [2 ], 0.0 ) # SOC
294404 self .assertLessEqual (cell .outputs [2 ], 1.0 )
295405
406+ def test_q_heat_nonzero_during_discharge (self ):
407+ """Q_heat must be strictly positive when a discharge current flows."""
408+ cell = CellCoSimElectrical (initial_soc = 1.0 , dt = 10.0 )
409+ I_src = Constant (5.0 )
410+ T_src = Constant (298.15 )
411+ sim = Simulation (
412+ blocks = [I_src , T_src , cell ],
413+ connections = [
414+ Connection (I_src , cell ["I" ]),
415+ Connection (T_src , cell ["T_cell" ]),
416+ ],
417+ dt = 5.0 ,
418+ Solver = ESDIRK43 ,
419+ )
420+ sim .run (60 )
421+ self .assertGreater (
422+ cell .outputs [1 ],
423+ 0.0 ,
424+ "Q_heat is zero — thermal model may not compute heat sources" ,
425+ )
426+
427+ def test_temperature_input_affects_voltage (self ):
428+ """T_cell must actually influence the electrochemistry."""
429+
430+ def _run_and_get_voltage (T_cell ):
431+ cell = CellCoSimElectrical (initial_soc = 1.0 , dt = 10.0 )
432+ I_src = Constant (5.0 )
433+ T_src = Constant (T_cell )
434+ sim = Simulation (
435+ blocks = [I_src , T_src , cell ],
436+ connections = [
437+ Connection (I_src , cell ["I" ]),
438+ Connection (T_src , cell ["T_cell" ]),
439+ ],
440+ dt = 5.0 ,
441+ Solver = ESDIRK43 ,
442+ )
443+ sim .run (300 )
444+ return cell .outputs [0 ] # terminal voltage [V]
445+
446+ V_cold = _run_and_get_voltage (278.15 ) # 5 °C
447+ V_hot = _run_and_get_voltage (318.15 ) # 45 °C
448+ self .assertNotAlmostEqual (
449+ float (V_cold ),
450+ float (V_hot ),
451+ places = 3 ,
452+ msg = "T_cell input has no effect on terminal voltage" ,
453+ )
454+
296455
297456class TestCoSimulationElectrothermal (unittest .TestCase ):
298457 """Integration tests for CellCoSimElectrothermal — PyBaMM performs the stepping."""
@@ -349,6 +508,52 @@ def test_dfn_step_outputs_physical(self):
349508 self .assertGreater (cell .outputs [3 ], 0.0 ) # SOC
350509 self .assertLessEqual (cell .outputs [3 ], 1.0 )
351510
511+ def test_q_heat_nonzero_during_discharge (self ):
512+ """Q_heat must be strictly positive when a discharge current flows."""
513+ cell = CellCoSimElectrothermal (initial_soc = 1.0 , dt = 10.0 )
514+ I_src = Constant (5.0 )
515+ T_src = Constant (298.15 )
516+ sim = Simulation (
517+ blocks = [I_src , T_src , cell ],
518+ connections = [
519+ Connection (I_src , cell ["I" ]),
520+ Connection (T_src , cell ["T_amb" ]),
521+ ],
522+ dt = 5.0 ,
523+ Solver = ESDIRK43 ,
524+ )
525+ sim .run (60 )
526+ self .assertGreater (
527+ cell .outputs [2 ],
528+ 0.0 ,
529+ "Q_heat is zero — thermal model may not compute heat sources" ,
530+ )
531+
532+ def test_tamb_input_affects_cell_temperature (self ):
533+ """T_amb must influence the output cell temperature."""
534+
535+ def _run_and_get_T_cell (T_amb ):
536+ cell = CellCoSimElectrothermal (initial_soc = 1.0 , dt = 10.0 )
537+ I_src = Constant (5.0 )
538+ T_src = Constant (T_amb )
539+ sim = Simulation (
540+ blocks = [I_src , T_src , cell ],
541+ connections = [
542+ Connection (I_src , cell ["I" ]),
543+ Connection (T_src , cell ["T_amb" ]),
544+ ],
545+ dt = 5.0 ,
546+ Solver = ESDIRK43 ,
547+ )
548+ sim .run (300 )
549+ return cell .outputs [1 ] # cell temperature [K]
550+
551+ T_cold = _run_and_get_T_cell (278.15 )
552+ T_hot = _run_and_get_T_cell (318.15 )
553+ self .assertLess (
554+ T_cold , T_hot , msg = "T_amb input has no effect on output cell temperature"
555+ )
556+
352557
353558if __name__ == "__main__" :
354559 unittest .main ()
0 commit comments