{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Tutorial 6 \\- Simulate Thermal Performance\n", "\n", "## Introduction\n", "\n", "In this tutorial, we will use a P4D model to simulate the thermal performance. We'll use the same model from Tutorial 1\n", "\n", "## Setup material properties" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "source": [ "jsonstruct_material = parseBattmoJson('Examples/jsondatafiles/sample_input.json');\n", "jsonstruct_material.include_current_collectors = true;" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the geometry\n", "\n", "We use a 3D geometry where it is easier to visualize the thermal effects.\n", "" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "source": [ "jsonstruct_geometry = parseBattmoJson('Examples/JsonDataFiles/geometry3d.json');\n", "disp(jsonstruct_geometry)" ], "outputs": [ { "data": { "text/plain": [ " include_current_collectors: 1\n", " Geometry: [1x1 struct]\n", " NegativeElectrode: [1x1 struct]\n", " PositiveElectrode: [1x1 struct]\n", " Separator: [1x1 struct]\n", " ThermalModel: [1x1 struct]" ] }, "metadata": {}, "execution_count": 2, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We merge the json structure. We get a warning for each field that gets different values from the given inputs. The rule is that the first input takes precedence, the warning can be switched off be setting the 'warn' option to false in the call to mergeJsonStructs.\n", "" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "source": [ "jsonstruct = mergeJsonStructs({jsonstruct_geometry , ...\n", " jsonstruct_material});" ], "outputs": [ { "data": { "text/plain": [ "mergeJsonStructs: Parameter Geometry.case is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter NegativeElectrode.Coating.thickness is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter NegativeElectrode.Coating.N is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter NegativeElectrode.CurrentCollector.N is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter PositiveElectrode.Coating.thickness is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter PositiveElectrode.Coating.N is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter PositiveElectrode.CurrentCollector.N is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter Separator.thickness is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter Separator.N is assigned twice with different values. Value from first jsonstruct is used.\n", "mergeJsonStructs: Parameter ThermalModel.externalHeatTransferCoefficient is assigned twice with different values. Value from first jsonstruct is used." ] }, "metadata": {}, "execution_count": 3, "output_type": "execute_result" } ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "source": [ "\n", "jsonstruct.use_thermal = true;" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We setup the model using the json structure.\n", "" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "source": [ "model = setupModelFromJson(jsonstruct);" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run the simulation\n", "\n", "We run the simulation. We have used here a standard discharge control at C\\-Rate=1.\n", "" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "source": [ "output = runBatteryJson(jsonstruct);" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualisation of the results\n", "\n", "We plot the voltage versus time for the simulation.\n", "" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "source": [ "time = output.time;\n", "E = output.E;\n", "\n", "set(0, 'defaulttextfontsize', 15);\n", "set(0, 'defaultaxesfontsize', 15);\n", "set(0, 'defaultlinelinewidth', 3);\n", "\n", "figure\n", "plot(time/hour, E)\n", "title('Voltage / V');\n", "xlabel('time / h');\n", "ylabel('voltage / V');" ], "outputs": [ { "data": { "text/html": [ "
\"figure_0.png\"
" ] }, "metadata": {}, "execution_count": 7, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We plot the minimum and maximum values of the temperature in the model as a function of time. The temperature for each grid cell, is stored in state.ThermalModel.T. For each computed step, we extract the minimum and maximum value of the temperature\n", "" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "source": [ "T0 = PhysicalConstants.absoluteTemperature;\n", "\n", "states = output.states;\n", "Tmin = cellfun(@(state) min(state.ThermalModel.T + T0), states);\n", "Tmax = cellfun(@(state) max(state.ThermalModel.T + T0), states);\n", "\n", "figure\n", "hold on\n", "plot(time / hour, Tmin, 'displayname', 'min T');\n", "plot(time / hour, Tmax, 'displayname', 'max T');\n", "title('Temperature / C')\n", "xlabel('time / h');\n", "ylabel('Temperature / C');\n", "\n", "legend show" ], "outputs": [ { "data": { "text/html": [ "
\"figure_1.png\"
" ] }, "metadata": {}, "execution_count": 8, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Temperature distribution at final time\n", "\n", "We have access to the temperature distribution for all the time steps. Here, we plot the temperature on the 3D model. We find a extensive set of plotting functions in [MRST](https://www.sintef.no/Projectweb/MRST/). You may be interested to have a look at the [Visualization Tutorial](https://www.sintef.no/projectweb/mrst/documentation/tutorials/visualization-tutorial/). We use [plotCellData](https://github.com/SINTEF-AppliedCompSci/MRST/blob/main/core/plotting/plotCellData.m) to plot the temperature. The function [plotToolbar.m](https://github.com/SINTEF-AppliedCompSci/MRST/blob/main/visualization/mrst-gui/plotToolbar.m) is also convenient to visualize values inside the domain in a interactive way.\n", "" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "source": [ "state = states{end}" ], "outputs": [ { "data": { "text/plain": [ "state = struct with fields:\n", " NegativeElectrode: [1x1 struct]\n", " PositiveElectrode: [1x1 struct]\n", " Electrolyte: [1x1 struct]\n", " ThermalModel: [1x1 struct]\n", " Control: [1x1 struct]\n", " time: 3.5517e+03" ] }, "metadata": {}, "execution_count": 9, "output_type": "execute_result" } ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "source": [ "figure\n", "plotCellData(model.ThermalModel.grid, ...\n", " state.ThermalModel.T + T0);\n", "colorbar\n", "title('Temperature / C');\n", "view([50, 50]);" ], "outputs": [ { "data": { "text/html": [ "
\"figure_2.png\"
" ] }, "metadata": {}, "execution_count": 10, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The external heat transfer coefficient\n", "\n", "The external heat transfer coefficient and the external temperature have a strong influence on the value of the temperature inside the model. The value of the external temperature has been given in the json input and passed to the model.\n", "" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "source": [ "disp(model.ThermalModel.externalTemperature);" ], "outputs": [ { "data": { "text/plain": [ " 298.1500" ] }, "metadata": {}, "execution_count": 11, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The values of the heat transfer coefficient have been processed from the json structure. For this 3D geometry, the external heat transfer coefficient is given by a value that is used at the tab\n", "" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "source": [ "disp(jsonstruct.ThermalModel.externalHeatTransferCoefficientTab);" ], "outputs": [ { "data": { "text/plain": [ " 1000" ] }, "metadata": {}, "execution_count": 12, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "and an other that is used for the remaining external faces,\n", "" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "source": [ "disp(jsonstruct.ThermalModel.externalHeatTransferCoefficient);" ], "outputs": [ { "data": { "text/plain": [ " 100" ] }, "metadata": {}, "execution_count": 13, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "From those values, when the model is setup, a value is assigned to all the external faces of the model. This value is stored in model.ThermalModel.externalHeatTransferCoefficient. Let us plot its value the 3D model. In the coupling term of the thermal model (coupling to the exterior model), we get the list of the face indices that are coupled thermally, which are in fact allthe external faces.\n", "" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "source": [ "extfaceind = model.ThermalModel.couplingTerm.couplingfaces;\n", "G = model.ThermalModel.grid;\n", "nf = G.faces.num;" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We create a vector with one value per face and we set this value equal to the external heat transfer coefficient for the corresponding external face.\n", "" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "source": [ "val = NaN(nf, 1);\n", "val(extfaceind) = model.ThermalModel.externalHeatTransferCoefficient;\n", "\n", "figure\n", "plotFaceData(G, val, 'edgecolor', 'black');\n", "axis equal\n", "view([50, 20]);\n", "title('External Heat Transfer Coefficient / W/s/m^2')\n", "colorbar" ], "outputs": [ { "data": { "text/html": [ "
\"figure_3.png\"
" ] }, "metadata": {}, "execution_count": 15, "output_type": "execute_result" } ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Let us modify the heat transfer coefficients and rerun the simulation to observe the effects.\n", "" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "source": [ "jsonstruct.ThermalModel.externalHeatTransferCoefficientTab = 100;\n", "jsonstruct.ThermalModel.externalHeatTransferCoefficient = 0;" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We run the model for the new values\n", "" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "source": [ "output = runBatteryJson(jsonstruct);" ], "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We plot the results\n", "" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "source": [ "states = output.states;\n", "\n", "Tmin = cellfun(@(state) min(state.ThermalModel.T + T0), states);\n", "Tmax = cellfun(@(state) max(state.ThermalModel.T + T0), states);\n", "time = output.time;\n", "\n", "figure\n", "hold on\n", "plot(time / hour, Tmin, 'displayname', 'min T');\n", "plot(time / hour, Tmax, 'displayname', 'max T');\n", "title('Temperature / C')\n", "xlabel('time / h');\n", "ylabel('Temperature / C');\n", "\n", "legend show" ], "outputs": [ { "data": { "text/html": [ "
\"figure_4.png\"
" ] }, "metadata": {}, "execution_count": 18, "output_type": "execute_result" } ] } ], "metadata": { "kernelspec": { "display_name": "MATLAB (matlabkernel)", "language": "matlab", "name": "matlab" }, "language_info": { "file_extension": ".m", "mimetype": "text/matlab", "name": "matlab", "nbconvert_exporter": "matlab", "pygments_lexer": "matlab", "version": "24.1.0.2689473" } }, "nbformat": 4, "nbformat_minor": 4 }