|
| 1 | +import logging |
1 | 2 | import os |
2 | 3 | from datetime import datetime |
3 | 4 |
|
@@ -1022,3 +1023,125 @@ def neg_stoich_cutoff(variables): |
1022 | 1023 |
|
1023 | 1024 | neg_stoich = sol["Negative electrode stoichiometry"].data |
1024 | 1025 | assert neg_stoich[-1] == pytest.approx(0.5, abs=0.0001) |
| 1026 | + |
| 1027 | + def test_simulation_changing_capacity_crate_steps(self): |
| 1028 | + """Test that C-rate steps are correctly updated when capacity changes""" |
| 1029 | + model = pybamm.lithium_ion.SPM() |
| 1030 | + experiment = pybamm.Experiment( |
| 1031 | + [ |
| 1032 | + ( |
| 1033 | + "Discharge at C/5 for 20 minutes", |
| 1034 | + "Discharge at C/2 for 20 minutes", |
| 1035 | + "Discharge at 1C for 20 minutes", |
| 1036 | + ) |
| 1037 | + ] |
| 1038 | + ) |
| 1039 | + param = pybamm.ParameterValues("Chen2020") |
| 1040 | + sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param) |
| 1041 | + |
| 1042 | + # First solve |
| 1043 | + sol1 = sim.solve(calc_esoh=False) |
| 1044 | + original_capacity = param["Nominal cell capacity [A.h]"] |
| 1045 | + |
| 1046 | + # Check that C-rates correspond to expected currents |
| 1047 | + I_C5_1 = np.abs(sol1.cycles[0].steps[0]["Current [A]"].data).mean() |
| 1048 | + I_C2_1 = np.abs(sol1.cycles[0].steps[1]["Current [A]"].data).mean() |
| 1049 | + I_1C_1 = np.abs(sol1.cycles[0].steps[2]["Current [A]"].data).mean() |
| 1050 | + |
| 1051 | + np.testing.assert_allclose(I_C5_1, original_capacity / 5, rtol=1e-2) |
| 1052 | + np.testing.assert_allclose(I_C2_1, original_capacity / 2, rtol=1e-2) |
| 1053 | + np.testing.assert_allclose(I_1C_1, original_capacity, rtol=1e-2) |
| 1054 | + |
| 1055 | + # Update capacity |
| 1056 | + new_capacity = 0.9 * original_capacity |
| 1057 | + sim._parameter_values.update({"Nominal cell capacity [A.h]": new_capacity}) |
| 1058 | + |
| 1059 | + # Second solve with updated capacity |
| 1060 | + sol2 = sim.solve(calc_esoh=False) |
| 1061 | + |
| 1062 | + # Check that C-rates now correspond to updated currents |
| 1063 | + I_C5_2 = np.abs(sol2.cycles[0].steps[0]["Current [A]"].data).mean() |
| 1064 | + I_C2_2 = np.abs(sol2.cycles[0].steps[1]["Current [A]"].data).mean() |
| 1065 | + I_1C_2 = np.abs(sol2.cycles[0].steps[2]["Current [A]"].data).mean() |
| 1066 | + |
| 1067 | + np.testing.assert_allclose(I_C5_2, new_capacity / 5, rtol=1e-2) |
| 1068 | + np.testing.assert_allclose(I_C2_2, new_capacity / 2, rtol=1e-2) |
| 1069 | + np.testing.assert_allclose(I_1C_2, new_capacity, rtol=1e-2) |
| 1070 | + |
| 1071 | + # Verify all currents scaled proportionally |
| 1072 | + np.testing.assert_allclose(I_C5_2 / I_C5_1, 0.9, rtol=1e-2) |
| 1073 | + np.testing.assert_allclose(I_C2_2 / I_C2_1, 0.9, rtol=1e-2) |
| 1074 | + np.testing.assert_allclose(I_1C_2 / I_1C_1, 0.9, rtol=1e-2) |
| 1075 | + |
| 1076 | + def test_simulation_multiple_cycles_with_capacity_change(self): |
| 1077 | + """Test capacity changes across multiple experiment cycles""" |
| 1078 | + model = pybamm.lithium_ion.SPM() |
| 1079 | + experiment = pybamm.Experiment( |
| 1080 | + [("Discharge at 1C for 5 minutes", "Charge at 1C for 5 minutes")] * 2 |
| 1081 | + ) |
| 1082 | + param = pybamm.ParameterValues("Chen2020") |
| 1083 | + sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param) |
| 1084 | + |
| 1085 | + # First solve |
| 1086 | + sol1 = sim.solve(calc_esoh=False) |
| 1087 | + original_capacity = param["Nominal cell capacity [A.h]"] |
| 1088 | + |
| 1089 | + # Get discharge currents for both cycles |
| 1090 | + I_discharge_cycle1 = np.abs(sol1.cycles[0].steps[0]["Current [A]"].data).mean() |
| 1091 | + I_discharge_cycle2 = np.abs(sol1.cycles[1].steps[0]["Current [A]"].data).mean() |
| 1092 | + |
| 1093 | + # Both cycles should use the same capacity initially |
| 1094 | + np.testing.assert_allclose(I_discharge_cycle1, original_capacity, rtol=1e-2) |
| 1095 | + np.testing.assert_allclose(I_discharge_cycle2, original_capacity, rtol=1e-2) |
| 1096 | + |
| 1097 | + # Update capacity between cycles |
| 1098 | + new_capacity = 0.85 * original_capacity |
| 1099 | + sim._parameter_values.update({"Nominal cell capacity [A.h]": new_capacity}) |
| 1100 | + |
| 1101 | + # Solve again |
| 1102 | + sol2 = sim.solve(calc_esoh=False) |
| 1103 | + |
| 1104 | + # All cycles in the new solution should use updated capacity |
| 1105 | + I_discharge_cycle1_new = np.abs( |
| 1106 | + sol2.cycles[0].steps[0]["Current [A]"].data |
| 1107 | + ).mean() |
| 1108 | + I_discharge_cycle2_new = np.abs( |
| 1109 | + sol2.cycles[1].steps[0]["Current [A]"].data |
| 1110 | + ).mean() |
| 1111 | + |
| 1112 | + np.testing.assert_allclose(I_discharge_cycle1_new, new_capacity, rtol=1e-2) |
| 1113 | + np.testing.assert_allclose(I_discharge_cycle2_new, new_capacity, rtol=1e-2) |
| 1114 | + |
| 1115 | + def test_simulation_logging_with_capacity_change(self, caplog): |
| 1116 | + """Test that capacity changes are logged appropriately""" |
| 1117 | + model = pybamm.lithium_ion.SPM() |
| 1118 | + experiment = pybamm.Experiment([("Discharge at 1C for 10 minutes",)]) |
| 1119 | + param = pybamm.ParameterValues("Chen2020") |
| 1120 | + sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param) |
| 1121 | + |
| 1122 | + # First solve |
| 1123 | + sim.solve(calc_esoh=False) |
| 1124 | + original_capacity = param["Nominal cell capacity [A.h]"] |
| 1125 | + |
| 1126 | + # Update capacity |
| 1127 | + new_capacity = 0.75 * original_capacity |
| 1128 | + sim._parameter_values.update({"Nominal cell capacity [A.h]": new_capacity}) |
| 1129 | + |
| 1130 | + # Set logging level to capture INFO messages |
| 1131 | + original_log_level = pybamm.logger.level |
| 1132 | + pybamm.set_logging_level("INFO") |
| 1133 | + |
| 1134 | + try: |
| 1135 | + # Second solve should log capacity change |
| 1136 | + with caplog.at_level(logging.INFO, logger="pybamm.logger"): |
| 1137 | + sim.solve(calc_esoh=False) |
| 1138 | + |
| 1139 | + # Check that a log message about capacity change was recorded |
| 1140 | + log_messages = [record.message for record in caplog.records] |
| 1141 | + capacity_change_logged = any( |
| 1142 | + "Nominal capacity changed" in msg for msg in log_messages |
| 1143 | + ) |
| 1144 | + assert capacity_change_logged |
| 1145 | + finally: |
| 1146 | + # Restore original logging level |
| 1147 | + pybamm.logger.setLevel(original_log_level) |
0 commit comments