Skip to content

Commit 2f594b2

Browse files
Merge pull request #1206 from pybamm-team/issue-1203-save-to-matlab
Issue 1203 save to matlab
2 parents 34fa6d7 + 45bfae3 commit 2f594b2

File tree

7 files changed

+212
-107
lines changed

7 files changed

+212
-107
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Features
44

5+
- Added variables related to equivalent circuit models ([#1204](https://github.com/pybamm-team/PyBaMM/pull/1204))
56
- Added an example script to check conservation of lithium ([#1186](https://github.com/pybamm-team/PyBaMM/pull/1186))
67
- Added `erf` and `erfc` functions ([#1184](https://github.com/pybamm-team/PyBaMM/pull/1184))
78

@@ -10,6 +11,7 @@
1011

1112
## Bug fixes
1213

14+
- Raise error if saving to matlab with variable names that matlab can't read, and give option of providing alternative variable names ([#1206](https://github.com/pybamm-team/PyBaMM/pull/1206))
1315
- Raise error if the boundary condition at the origin in a spherical domain is other than no-flux ([#1175](https://github.com/pybamm-team/PyBaMM/pull/1175))
1416
- Fix boundary conditions at r = 0 for Creating Models notebooks ([#1173](https://github.com/pybamm-team/PyBaMM/pull/1173))
1517

examples/notebooks/Getting Started/Tutorial 6 - Managing simulation outputs.ipynb

+32-32
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,23 @@
2222
"metadata": {},
2323
"outputs": [
2424
{
25-
"name": "stdout",
2625
"output_type": "stream",
26+
"name": "stdout",
2727
"text": [
28+
"\u001b[33mWARNING: You are using pip version 20.2.1; however, version 20.2.4 is available.\n",
29+
"You should consider upgrading via the '/Users/vsulzer/Documents/Energy_storage/PyBaMM/.tox/dev/bin/python -m pip install --upgrade pip' command.\u001b[0m\n",
2830
"Note: you may need to restart the kernel to use updated packages.\n"
2931
]
3032
},
3133
{
34+
"output_type": "execute_result",
3235
"data": {
3336
"text/plain": [
34-
"<pybamm.solvers.solution.Solution at 0x7f39e107d1d0>"
37+
"<pybamm.solvers.solution.Solution at 0x1467c6820>"
3538
]
3639
},
37-
"execution_count": 1,
3840
"metadata": {},
39-
"output_type": "execute_result"
41+
"execution_count": 1
4042
}
4143
],
4244
"source": [
@@ -100,6 +102,7 @@
100102
"metadata": {},
101103
"outputs": [
102104
{
105+
"output_type": "execute_result",
103106
"data": {
104107
"text/plain": [
105108
"array([3.77047806, 3.75305163, 3.74567013, 3.74038819, 3.73581198,\n",
@@ -124,9 +127,8 @@
124127
" 3.45439366, 3.41299183, 3.35578872, 3.27680073, 3.16842637])"
125128
]
126129
},
127-
"execution_count": 4,
128130
"metadata": {},
129-
"output_type": "execute_result"
131+
"execution_count": 4
130132
}
131133
],
132134
"source": [
@@ -146,6 +148,7 @@
146148
"metadata": {},
147149
"outputs": [
148150
{
151+
"output_type": "execute_result",
149152
"data": {
150153
"text/plain": [
151154
"array([ 0. , 36.36363636, 72.72727273, 109.09090909,\n",
@@ -175,9 +178,8 @@
175178
" 3490.90909091, 3527.27272727, 3563.63636364, 3600. ])"
176179
]
177180
},
178-
"execution_count": 5,
179181
"metadata": {},
180-
"output_type": "execute_result"
182+
"execution_count": 5
181183
}
182184
],
183185
"source": [
@@ -197,14 +199,14 @@
197199
"metadata": {},
198200
"outputs": [
199201
{
202+
"output_type": "execute_result",
200203
"data": {
201204
"text/plain": [
202205
"array([3.72947891, 3.70860034, 3.67810702, 3.65400558])"
203206
]
204207
},
205-
"execution_count": 6,
206208
"metadata": {},
207-
"output_type": "execute_result"
209+
"execution_count": 6
208210
}
209211
],
210212
"source": [
@@ -263,18 +265,16 @@
263265
"metadata": {},
264266
"outputs": [
265267
{
268+
"output_type": "display_data",
266269
"data": {
270+
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…",
267271
"application/vnd.jupyter.widget-view+json": {
268-
"model_id": "7e116fdff90e40b28b3f13b79f3e7347",
269272
"version_major": 2,
270-
"version_minor": 0
271-
},
272-
"text/plain": [
273-
"interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…"
274-
]
273+
"version_minor": 0,
274+
"model_id": "0b4ebac3fdd947218f9444b2b381cf04"
275+
}
275276
},
276-
"metadata": {},
277-
"output_type": "display_data"
277+
"metadata": {}
278278
}
279279
],
280280
"source": [
@@ -311,28 +311,26 @@
311311
"metadata": {},
312312
"outputs": [
313313
{
314+
"output_type": "display_data",
314315
"data": {
316+
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…",
315317
"application/vnd.jupyter.widget-view+json": {
316-
"model_id": "cb9640519af3475b9b921b8523c01020",
317318
"version_major": 2,
318-
"version_minor": 0
319-
},
320-
"text/plain": [
321-
"interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…"
322-
]
319+
"version_minor": 0,
320+
"model_id": "f4a1b65b2bf945099197135c5598084b"
321+
}
323322
},
324-
"metadata": {},
325-
"output_type": "display_data"
323+
"metadata": {}
326324
},
327325
{
326+
"output_type": "execute_result",
328327
"data": {
329328
"text/plain": [
330-
"<pybamm.plotting.quick_plot.QuickPlot at 0x7f39dc81a0b8>"
329+
"<pybamm.plotting.quick_plot.QuickPlot at 0x14be13b80>"
331330
]
332331
},
333-
"execution_count": 11,
334332
"metadata": {},
335-
"output_type": "execute_result"
333+
"execution_count": 11
336334
}
337335
],
338336
"source": [
@@ -370,7 +368,9 @@
370368
"outputs": [],
371369
"source": [
372370
"sol.save_data(\"sol_data.csv\", [\"Current [A]\", \"Terminal voltage [V]\"], to_format=\"csv\")\n",
373-
"sol.save_data(\"sol_data.mat\", [\"Current [A]\", \"Terminal voltage [V]\"], to_format=\"matlab\")"
371+
"# matlab needs names without spaces\n",
372+
"sol.save_data(\"sol_data.mat\", [\"Current [A]\", \"Terminal voltage [V]\"], to_format=\"matlab\",\n",
373+
" short_names={\"Current [A]\": \"I\", \"Terminal voltage [V]\": \"V\"})"
374374
]
375375
},
376376
{
@@ -425,9 +425,9 @@
425425
"name": "python",
426426
"nbconvert_exporter": "python",
427427
"pygments_lexer": "ipython3",
428-
"version": "3.6.9"
428+
"version": "3.8.5-final"
429429
}
430430
},
431431
"nbformat": 4,
432432
"nbformat_minor": 2
433-
}
433+
}

examples/notebooks/solution-data-and-processed-variables.ipynb

+66-62
Large diffs are not rendered by default.

examples/scripts/experimental_protocols/cccv.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
ax.set_xlim([0, 13])
3535
ax.legend()
3636

37-
# Save time, voltage, current, discharge capacity and temperature to csv and matlab
38-
# formats
37+
# Save time, voltage, current, discharge capacity, temperature, and electrolyte
38+
# concentration to csv and matlab formats
3939
sim.solution.save_data(
4040
"output.mat",
4141
[
@@ -44,9 +44,19 @@
4444
"Terminal voltage [V]",
4545
"Discharge capacity [A.h]",
4646
"X-averaged cell temperature [K]",
47+
"Electrolyte concentration [mol.m-3]",
4748
],
4849
to_format="matlab",
50+
short_names={
51+
"Time [h]": "t",
52+
"Current [A]": "I",
53+
"Terminal voltage [V]": "V",
54+
"Discharge capacity [A.h]": "Q",
55+
"X-averaged cell temperature [K]": "T",
56+
"Electrolyte concentration [mol.m-3]": "c_e",
57+
},
4958
)
59+
# We can only save 0D variables to csv
5060
sim.solution.save_data(
5161
"output.csv",
5262
[

pybamm/simulation.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,10 @@ def solve(
350350
"list [t0, tf] where t0 is the initial time and tf is the "
351351
"final time. "
352352
"For a constant current (dis)charge the suggested 't_eval' "
353-
"is [0, 3700/C] where C is the C-rate."
353+
"is [0, 3700/C] where C is the C-rate. "
354+
"For example, run\n\n"
355+
"\tsim.solve([0, 3700])\n\n"
356+
"for a 1C discharge."
354357
)
355358

356359
elif self.operating_mode == "drive cycle":

pybamm/solvers/solution.py

+63-6
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,31 @@ def __getitem__(self, key):
201201
self.update(key)
202202
return self._variables[key]
203203

204+
def plot(self, output_variables=None, **kwargs):
205+
"""
206+
A method to quickly plot the outputs of the solution. Creates a
207+
:class:`pybamm.QuickPlot` object (with keyword arguments 'kwargs') and
208+
then calls :meth:`pybamm.QuickPlot.dynamic_plot`.
209+
210+
Parameters
211+
----------
212+
output_variables: list, optional
213+
A list of the variables to plot.
214+
**kwargs
215+
Additional keyword arguments passed to
216+
:meth:`pybamm.QuickPlot.dynamic_plot`.
217+
For a list of all possible keyword arguments see :class:`pybamm.QuickPlot`.
218+
"""
219+
return pybamm.dynamic_plot(self, output_variables=output_variables, **kwargs)
220+
204221
def save(self, filename):
205222
"""Save the whole solution using pickle"""
206223
# No warning here if len(self.data)==0 as solution can be loaded
207224
# and used to process new variables
208225
with open(filename, "wb") as f:
209226
pickle.dump(self, f, pickle.HIGHEST_PROTOCOL)
210227

211-
def save_data(self, filename, variables=None, to_format="pickle"):
228+
def save_data(self, filename, variables=None, to_format="pickle", short_names=None):
212229
"""
213230
Save solution data only (raw arrays)
214231
@@ -224,7 +241,12 @@ def save_data(self, filename, variables=None, to_format="pickle"):
224241
225242
- 'pickle' (default): creates a pickle file with the data dictionary
226243
- 'matlab': creates a .mat file, for loading in matlab
227-
- 'csv': creates a csv file (1D variables only)
244+
- 'csv': creates a csv file (0D variables only)
245+
short_names : dict, optional
246+
Dictionary of shortened names to use when saving. This may be necessary when
247+
saving to MATLAB, since no spaces or special characters are allowed in
248+
MATLAB variable names. Note that not all the variables need to be given
249+
a short name.
228250
229251
"""
230252
if variables is None:
@@ -243,20 +265,55 @@ def save_data(self, filename, variables=None, to_format="pickle"):
243265
to save.
244266
"""
245267
)
268+
269+
# Use any short names if provided
270+
data_short_names = {}
271+
short_names = short_names or {}
272+
for name, var in data.items():
273+
# change to short name if it exists
274+
if name in short_names:
275+
data_short_names[short_names[name]] = var
276+
else:
277+
data_short_names[name] = var
278+
246279
if to_format == "pickle":
247280
with open(filename, "wb") as f:
248-
pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
281+
pickle.dump(data_short_names, f, pickle.HIGHEST_PROTOCOL)
249282
elif to_format == "matlab":
250-
savemat(filename, data)
283+
# Check all the variable names only contain a-z, A-Z or _ or numbers
284+
for name in data_short_names.keys():
285+
# Check the string only contains the following ASCII:
286+
# a-z (97-122)
287+
# A-Z (65-90)
288+
# _ (95)
289+
# 0-9 (48-57) but not in the first position
290+
for i, s in enumerate(name):
291+
if not (
292+
97 <= ord(s) <= 122
293+
or 65 <= ord(s) <= 90
294+
or ord(s) == 95
295+
or (i > 0 and 48 <= ord(s) <= 57)
296+
):
297+
raise ValueError(
298+
"Invalid character '{}' found in '{}'. ".format(s, name)
299+
+ "MATLAB variable names must only contain a-z, A-Z, _, "
300+
"or 0-9 (except the first position). "
301+
"Use the 'short_names' argument to pass an alternative "
302+
"variable name, e.g. \n\n"
303+
"\tsolution.save_data(filename, "
304+
"['Electrolyte concentration'], to_format='matlab, "
305+
"short_names={'Electrolyte concentration': 'c_e'})"
306+
)
307+
savemat(filename, data_short_names)
251308
elif to_format == "csv":
252-
for name, var in data.items():
309+
for name, var in data_short_names.items():
253310
if var.ndim >= 2:
254311
raise ValueError(
255312
"only 0D variables can be saved to csv, but '{}' is {}D".format(
256313
name, var.ndim - 1
257314
)
258315
)
259-
df = pd.DataFrame(data)
316+
df = pd.DataFrame(data_short_names)
260317
df.to_csv(filename, index=False)
261318
else:
262319
raise ValueError("format '{}' not recognised".format(to_format))

0 commit comments

Comments
 (0)