.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/00-fluent/single_battery_cell_workflow.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_00-fluent_single_battery_cell_workflow.py: .. _single_battery_cell_simulation: Single Battery Cell Using MSMD Battery Model Simulation ---------------------------------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 30-41 Problem Description: ===================================================================================== Simulate a 14.6 Ah lithium-ion battery with a LiMn₂O₄ cathode and graphite anode using the Multi-Scale Multi-Domain (MSMD) battery model in Ansys Fluent. Evaluate the battery's electrochemical and thermal performance under various discharge rates (e.g., 0.5C, 1C, 5C) and operating conditions, including normal operation, pulse discharge, and short-circuit scenarios. Key outputs include voltage, temperature, and state of charge. .. image:: ../../_static/Single_Battery_cell_model.png :align: center :alt: Single Battery Cell Model .. GENERATED FROM PYTHON SOURCE LINES 43-45 Import modules ===================================================================================== .. GENERATED FROM PYTHON SOURCE LINES 45-50 .. code-block:: Python import os import ansys.fluent.core as pyfluent from ansys.fluent.core import FluentMode, Precision, examples .. GENERATED FROM PYTHON SOURCE LINES 51-54 Launch Fluent session ===================================================================================== Launch a Fluent solver session with required parameters .. GENERATED FROM PYTHON SOURCE LINES 54-58 .. code-block:: Python solver = pyfluent.launch_fluent( precision=Precision.DOUBLE, processor_count=4, mode=FluentMode.SOLVER ) .. GENERATED FROM PYTHON SOURCE LINES 59-62 Download the mesh file ===================================================================================== Download the battery mesh file and save it to the current working directory. .. GENERATED FROM PYTHON SOURCE LINES 62-68 .. code-block:: Python unit_battery_mesh = examples.download_file( "unit_battery.msh.h5", "pyfluent/battery_thermal_simulation", save_path=os.getcwd(), ) .. GENERATED FROM PYTHON SOURCE LINES 69-74 Read and display mesh ===================================================================================== .. note:: Graphics commands like restore_view and save_picture require GUI mode. .. GENERATED FROM PYTHON SOURCE LINES 74-89 .. code-block:: Python solver.settings.file.read_case(file_name=unit_battery_mesh) # Get all the available wall boundary surfaces all_walls = solver.settings.setup.boundary_conditions.wall.get_object_names() mesh_object = solver.settings.results.graphics.mesh.create("mesh-1") mesh_object.surfaces_list = all_walls mesh_object.options.edges = True mesh_object.display() graphics_object = solver.settings.results.graphics graphics_object.picture.x_resolution = 650 graphics_object.picture.y_resolution = 450 graphics_object.views.restore_view(view_name="isometric") graphics_object.picture.save_picture(file_name="Single_Battery_Cell_Mesh.png") .. GENERATED FROM PYTHON SOURCE LINES 90-93 .. image:: ../../_static/Single_Battery_Cell_Mesh.png :align: center :alt: Single Battery Cell Mesh .. GENERATED FROM PYTHON SOURCE LINES 95-98 Configure solver settings for battery model ===================================================================================== Use an unsteady first-order time solver for transient behavior. .. GENERATED FROM PYTHON SOURCE LINES 98-100 .. code-block:: Python solver.settings.setup.general.solver.time = "unsteady-1st-order" .. GENERATED FROM PYTHON SOURCE LINES 101-106 Enable the battery model ===================================================================================== Activate the NTGK/DCIR model with a nominal cell capacity of 14.6 Ah. Enable Joule heat in passive zones and define zones and terminals. For a detailed guide on setting up a single battery cell,refer to the Reference_ [3]. .. GENERATED FROM PYTHON SOURCE LINES 106-115 .. code-block:: Python battery = solver.settings.setup.models.battery battery.enabled = True battery.echem_model = "ntgk/dcir" battery.zone_assignment.active_zone = ["e_zone"] battery.zone_assignment.passive_zone = ["tab_nzone", "tab_pzone"] battery.zone_assignment.negative_tab = ["tab_n"] battery.zone_assignment.positive_tab = ["tab_p"] .. GENERATED FROM PYTHON SOURCE LINES 116-126 Define materials for cell and tabs ===================================================================================== .. note:: Chemical formula values are arbitrary identifiers for demonstration. Material definition for battery cell, positive tab and negative tab. User define scalars are defined for e-material and positive material to specify the electric conductivity with ``defined-per-uds`` and ``constant`` option respectively. .. GENERATED FROM PYTHON SOURCE LINES 126-177 .. code-block:: Python materials = [ { "name": "e_material", "chemical_formula": "e", "density": 2092, "specific_heat": 678, "thermal_conductivity": 18.2, "uds_diffusivity": { "option": "defined-per-uds", "uds-0": 1190000, "uds-1": 983000, }, }, { "name": "p_material", "chemical_formula": "pmat", "density": 8978, "specific_heat": 381, "thermal_conductivity": 387.6, "uds_diffusivity": {"option": "constant", "value": 10000000}, }, { "name": "n_material", "chemical_formula": "nmat", "density": 8978, "specific_heat": 381, "thermal_conductivity": 387.6, }, ] solids = solver.settings.setup.materials.solid for mat in materials: solids.create(mat["name"]) solids[mat["name"]].chemical_formula = mat["chemical_formula"] solids[mat["name"]].density.value = mat["density"] solids[mat["name"]].specific_heat.value = mat["specific_heat"] solids[mat["name"]].thermal_conductivity.value = mat["thermal_conductivity"] if "uds_diffusivity" in mat: solids[mat["name"]].uds_diffusivity = { "option": mat["uds_diffusivity"]["option"] } if mat["uds_diffusivity"]["option"] == "defined-per-uds": solids[mat["name"]].uds_diffusivity.uds_diffusivities["uds-0"].value = mat[ "uds_diffusivity" ]["uds-0"] solids[mat["name"]].uds_diffusivity.uds_diffusivities["uds-1"].value = mat[ "uds_diffusivity" ]["uds-1"] else: solids[mat["name"]].uds_diffusivity.value = mat["uds_diffusivity"]["value"] .. GENERATED FROM PYTHON SOURCE LINES 178-181 Assign materials to cell zones ===================================================================================== Map materials to respective zones. .. GENERATED FROM PYTHON SOURCE LINES 181-191 .. code-block:: Python cell_zones = [ ("e_zone", "e_material"), ("tab_nzone", "n_material"), ("tab_pzone", "p_material"), ] for zone, material in cell_zones: solver.settings.setup.cell_zone_conditions.solid[zone].general.material = material .. GENERATED FROM PYTHON SOURCE LINES 192-195 Define boundary conditions ===================================================================================== Set convective heat transfer on external surfaces. .. GENERATED FROM PYTHON SOURCE LINES 195-205 .. code-block:: Python wall = solver.settings.setup.boundary_conditions.wall wall["wall_active"].thermal.thermal_condition = "Convection" wall["wall_active"].thermal.heat_transfer_coeff.value = 5 # API to copy similar boundary condition solver.settings.setup.boundary_conditions.copy( from_="wall_active", to=["wall_n", "wall_p"] ) .. GENERATED FROM PYTHON SOURCE LINES 206-209 Configure solution settings ===================================================================================== Disable flow and turbulence equations, since residual criteria are set to ``none`` .. GENERATED FROM PYTHON SOURCE LINES 209-215 .. code-block:: Python solver.settings.solution.controls.equations["flow"] = False solver.settings.solution.controls.equations["kw"] = False solver.settings.solution.monitor.residual.options.criterion_type = "none" .. GENERATED FROM PYTHON SOURCE LINES 216-219 Create report definitions ===================================================================================== Monitor average voltage and maximum temperature. .. GENERATED FROM PYTHON SOURCE LINES 219-262 .. code-block:: Python avg_surface_voltage_report_def = ( solver.settings.solution.report_definitions.surface.create("surface_voltage") ) avg_surface_voltage_report_def.report_type = "surface-areaavg" avg_surface_voltage_report_def.field = "passive-zone-potential" avg_surface_voltage_report_def.surface_names = ["tab_p"] max_temp_report_def = solver.settings.solution.report_definitions.volume.create( "max_temperature" ) max_temp_report_def.report_type = "volume-max" max_temp_report_def.field = "temperature" max_temp_report_def.cell_zones = ["e_zone", "tab_nzone", "tab_pzone"] surf_voltage_report_files = solver.settings.solution.monitor.report_files.create( "surface_voltage_file" ) surf_voltage_report_files.report_defs = ["flow-time", "surface_voltage"] surf_voltage_report_files.file_name = "ntgk-1c.out" surf_voltage_report_files.print = True max_temp_report_file = solver.settings.solution.monitor.report_files.create( "max_temperature_file" ) max_temp_report_file.report_defs = ["max_temperature"] max_temp_report_file.file_name = "max-temp-1c.out" max_temp_report_file.print = True report_plots = solver.settings.solution.monitor.report_plots voltage_plot = report_plots.create("surface_voltage_plot") voltage_plot.report_defs = ["surface_voltage"] voltage_plot.print = True voltage_plot.axes.x.number_format.precision = 0 voltage_plot.axes.y.number_format.precision = 2 temp_plot = report_plots.create("max_temperature_plot") temp_plot.report_defs = ["max_temperature"] temp_plot.print = True temp_plot.axes.x.number_format.precision = 0 temp_plot.axes.y.number_format.precision = 2 .. GENERATED FROM PYTHON SOURCE LINES 263-265 Run the simulation ===================================================================================== .. GENERATED FROM PYTHON SOURCE LINES 265-272 .. code-block:: Python solver.settings.solution.initialization.standard_initialize() transient_controls = solver.settings.solution.run_calculation.transient_controls transient_controls.time_step_size = 30 transient_controls.time_step_count = 100 solver.settings.solution.run_calculation.calculate() .. GENERATED FROM PYTHON SOURCE LINES 273-276 Post-process results ===================================================================================== Generate contour and vector plots. .. GENERATED FROM PYTHON SOURCE LINES 276-337 .. code-block:: Python contours = solver.settings.results.graphics.contour contour_list = [ { "name": "contour-phi+", "field": "cathode-potential", "surfaces": ["wall_active"], "file_name": "Single_Battery_Cell_1.png", }, { "name": "contour-phi-", "field": "anode-potential", "surfaces": ["wall_active"], "file_name": "Single_Battery_Cell_2.png", }, { "name": "contour-phi-passive", "field": "passive-zone-potential", "surfaces": ["tab_n", "tab_p", "wall_n", "wall_p"], "file_name": "Single_Battery_Cell_3.png", }, { "name": "contour-temp", "field": "temperature", "surfaces": ["wall_p", "wall_active", "tab_p", "tab_n", "wall_n"], "file_name": "Single_Battery_Cell_4.png", }, ] # Create, display, and save contour plots for contour in contour_list: # Create the contour contours.create(contour["name"]) current = contours[contour["name"]] current.field = contour["field"] current.surfaces_list = contour["surfaces"] current.range_options.compute() # Set the view graphics_object.views.restore_view(view_name="front") # display the current contour current.display() # Save the contour plot as an image graphics_object.picture.save_picture(file_name=contour["file_name"]) # Create and configure vector plot vector_plot = solver.settings.results.graphics.vector.create("vector-current_density") vector_plot.vector_field = "current-density-j" vector_plot.field = "current-magnitude" vector_plot.surfaces_list = ["wall_n", "wall_p", "wall_active", "tab_n", "tab_p"] vector_plot.options.vector_style = "arrow" vector_plot.range_options.compute() # Set view, display, and save the vector plot image graphics_object.views.restore_view(view_name="front") vector_plot.display() graphics_object.picture.save_picture(file_name="Single_Battery_Cell_5.png") # Save case file for ROM simulation solver.settings.file.write_case(file_name="unit_battery.cas.h5") # Save case and data for short circuit simulation solver.settings.file.write_case_data(file_name=" ntgk") # Save case data .. GENERATED FROM PYTHON SOURCE LINES 338-361 .. image:: ../../_static/Single_Battery_Cell_1.png :align: center :alt: Anode Potential Contour(1C) .. image:: ../../_static/Single_Battery_Cell_2.png :align: center :alt: Cathode Potential Contour(1C) .. image:: ../../_static/Single_Battery_Cell_3.png :align: center :alt: Passive Zone Potential Contour(1C) .. image:: ../../_static/Single_Battery_Cell_4.png :align: center :alt: Static Temperature Contour(1C) .. image:: ../../_static/Single_Battery_Cell_5.png :align: center :alt: Current Density Vector(1C) .. GENERATED FROM PYTHON SOURCE LINES 364-367 Run simulations at different C-rates ===================================================================================== Simulate at 0.5C and 5C discharge rates with adjusted time steps. .. GENERATED FROM PYTHON SOURCE LINES 367-389 .. code-block:: Python solver.settings.setup.models.battery.eload_condition.eload_settings.crate_value = 0.5 # Get report files report_files = solver.settings.solution.monitor.report_files # Update report file names for 0.5 c rate simulation for existing report files report_files["surface_voltage_file"].file_name = "ntgk-0.5c.out" report_files["max_temperature_file"].file_name = "max-temp-0.5c.out" solver.settings.solution.initialization.standard_initialize() solver.settings.solution.run_calculation.transient_controls.time_step_count = 230 solver.settings.solution.run_calculation.calculate() solver.settings.setup.models.battery.eload_condition.eload_settings.crate_value = 5 # Update report file names for 5 c rate simulation for existing report files report_files["surface_voltage_file"].file_name = "ntgk-5c.out" report_files["max_temperature_file"].file_name = "max-temp-5c.out" solver.settings.solution.initialization.standard_initialize() solver.settings.solution.run_calculation.transient_controls.time_step_count = 23 solver.settings.solution.run_calculation.calculate() .. GENERATED FROM PYTHON SOURCE LINES 390-393 Reduced Order Method (ROM) setup ===================================================================================== Apply ROM for computational efficiency. .. GENERATED FROM PYTHON SOURCE LINES 393-457 .. code-block:: Python solver.settings.file.read_case(file_name="unit_battery.cas.h5") solver.settings.solution.initialization.standard_initialize() solver.settings.solution.run_calculation.transient_controls.time_step_size = 30 solver.settings.solution.run_calculation.transient_controls.time_step_count = 3 solver.settings.solution.run_calculation.calculate() solver.settings.setup.models.battery.solution_method = "msmd-rom" solver.settings.setup.models.battery.solution_option.option_settings.number_substeps = ( 10 ) solver.settings.solution.run_calculation.transient_controls.time_step_size = 30 solver.settings.solution.run_calculation.transient_controls.time_step_count = 100 solver.settings.solution.run_calculation.calculate() # Generate contour and vector plots for ROM results. contours = solver.settings.results.graphics.contour contour_list = [ { "name": "contour_cathode_potential", "field": "cathode-potential", "surfaces": ["wall_active"], }, { "name": "contour_anode_potential", "field": "anode-potential", "surfaces": ["wall_active"], }, { "name": "contour_passive_potential", "field": "passive-zone-potential", "surfaces": ["tab_n", "tab_p", "wall_n", "wall_p"], }, { "name": "contour_temperature", "field": "temperature", "surfaces": ["wall_p", "wall_active", "tab_p", "tab_n", "wall_n"], }, ] for contour in contour_list: contours.create(contour["name"]) contours[contour["name"]].field = contour["field"] contours[contour["name"]].surfaces_list = contour["surfaces"] contours[contour["name"]].range_options.compute() vectors = solver.settings.results.graphics.vector.create("vector-current_density") vectors.vector_field = "current-density-j" vectors.field = "current-magnitude" vectors.surfaces_list = [ "wall_n", "wall_p", "wall_active", "tab_n", "tab_p", ] vectors.options.vector_style = "arrow" vectors.range_options.compute() # Set view, display, and save the vector plot image graphics_object.views.restore_view(view_name="front") vectors.display() graphics_object.picture.save_picture(file_name="Single_Battery_Cell_6.png") .. GENERATED FROM PYTHON SOURCE LINES 458-462 .. image:: ../../_static/Single_Battery_Cell_6.png :align: center :alt: Current Magnitude (1C) Vector current density for ROM model (faster with identical results). .. GENERATED FROM PYTHON SOURCE LINES 464-467 Simulate short-circuit ===================================================================================== Apply low external resistance and define a short-circuit region. .. GENERATED FROM PYTHON SOURCE LINES 467-529 .. code-block:: Python solver.settings.file.read_case(file_name="ntgk.cas.h5") solver.settings.setup.models.battery.eload_condition.eload_settings.eload_type = ( "specified-resistance" ) solver.settings.setup.models.battery.eload_condition.eload_settings.external_resistance = ( 0.5 ) # Create a new cell register named "register_patch" patch = solver.settings.solution.cell_registers.create(name="register_patch") patch.type.option = "hexahedron" # Configure the hexahedron box patch.type.hexahedron.inside = True patch.type.hexahedron.min_point = [-0.01, -0.01, -1.0] patch.type.hexahedron.max_point = [0.01, 0.02, 1.0] solver.settings.solution.initialization.standard_initialize() # Patch initialization solver.settings.solution.initialization.patch.calculate_patch( domain="", cell_zones=[], registers=["register_patch"], variable="battery-short-resistance", reference_frame="Relative to Cell Zone", use_custom_field_function=False, custom_field_function_name="", value=5e-07, ) solver.settings.solution.run_calculation.transient_controls.time_step_size = 1 solver.settings.solution.run_calculation.transient_controls.time_step_count = 5 solver.settings.solution.run_calculation.calculate() solver.settings.file.write_case_data(file_name="ntgk_short_circuit.cas.h5") solver.settings.results.report.surface_integrals.area_weighted_avg( report_of="passive-zone-potential", surface_names=["tab_p"], write_to_file=False ) solver.settings.results.report.volume_integrals.volume_integral( cell_function="total-current-source", cell_zones=["e_zone"], write_to_file=False ) vector = solver.settings.results.graphics.vector vector_negative = vector.create("vector_negative_current") vector_negative.vector_field = "current-density-jn" vector_negative.field = "current-magnitude" vector_negative.surfaces_list = [ "wall_n", "wall_p", "wall_active", ] vector_negative.options.vector_style = "arrow" vector_negative.range_options.compute() graphics_object.views.restore_view(view_name="front") vector_negative.display() graphics_object.picture.save_picture(file_name="Single_Battery_Cell_9.png") .. GENERATED FROM PYTHON SOURCE LINES 530-534 .. image:: ../../_static/Single_Battery_Cell_9.png :align: center :alt: Negative Current Vector Plot Negative current vector plot after short circuit. .. GENERATED FROM PYTHON SOURCE LINES 534-550 .. code-block:: Python vector_positive = vectors.create("vector_positive_current") vector_positive.vector_field = "current-density-jp" vector_positive.field = "current-magnitude" vector_positive.surfaces_list = [ "wall_n", "wall_p", "wall_active", ] vector_positive.options.vector_style = "arrow" vector_positive.range_options.compute() graphics_object.views.restore_view(view_name="front") vector_positive.display() graphics_object.picture.save_picture(file_name="Single_Battery_Cell_10.png") .. GENERATED FROM PYTHON SOURCE LINES 551-555 .. image:: ../../_static/Single_Battery_Cell_10.png :align: center :alt: Positive Current Vector Plot Positive current vector plot after short circuit. .. GENERATED FROM PYTHON SOURCE LINES 555-565 .. code-block:: Python temp_contour = solver.settings.results.graphics.contour.create("temperature-contour") temp_contour.field = "temperature" temp_contour.surfaces_list = all_walls temp_contour.range_options.compute() graphics_object.views.restore_view(view_name="front") temp_contour.display() graphics_object.picture.save_picture(file_name="Single_Battery_Cell_11.png") .. GENERATED FROM PYTHON SOURCE LINES 566-570 .. image:: ../../_static/Single_Battery_Cell_11.png :align: center :alt: Temperature Contour Temperature contour plot after short circuit. .. GENERATED FROM PYTHON SOURCE LINES 572-574 Close the solver ===================================================================================== .. GENERATED FROM PYTHON SOURCE LINES 574-576 .. code-block:: Python solver.exit() .. GENERATED FROM PYTHON SOURCE LINES 577-587 References: ===================================================================================== [1] U. S. Kim et al, "Effect of electrode configuration on the thermal behavior of a lithium-polymer battery", Journal of Power Sources, Volume 180 (2), pages 909-916, 2008. [2] U. S. Kim, et al., "Modeling the Dependence of the Discharge Behavior of a Lithium-Ion Battery on the Environmental Temperature", J. of Electrochemical Soc., Volume 158 (5), pages A611-A618, 2011. .. _Reference: [3] Simulating a Single Battery Cell Using the MSMD Battery Model, `Ansys Fluent documentation​ `_. .. _sphx_glr_download_examples_00-fluent_single_battery_cell_workflow.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: single_battery_cell_workflow.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: single_battery_cell_workflow.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: single_battery_cell_workflow.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_