.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples\simulator\mechanics-simulator-leftventricle_pr.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_simulator_mechanics-simulator-leftventricle_pr.py: Run a left ventricle mechanical simulation ------------------------------------------ This example shows you how to perform the following actions: - Generate a left-ventricle model from a labeled surface. - Set up the model for mechanical simulation: - Generate fibers. - Assign material. - Tune boundary conditions. - Compute stress-free configuration. - Run the simulation for one heartbeat. - Postprocess the results: - Plot the stress-free configuration versus the end-diastole configuration. - Plot the Klotz curve. - Animate the simulation results. - Plot the PV loop. .. GENERATED FROM PYTHON SOURCE LINES 47-56 .. warning:: When using a standalone version of the DPF Server, you must accept the `license terms `_. To accept these terms, you can set this environment variable: .. code-block:: python import os os.environ["ANSYS_DPF_ACCEPT_LA"] = "Y" .. GENERATED FROM PYTHON SOURCE LINES 58-62 Perform the required imports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Import the required modules and set relevant paths, including that of the working directory, heart model, and LS-DYNA executable file. .. GENERATED FROM PYTHON SOURCE LINES 62-81 .. code-block:: Python import copy import glob import json import os from pathlib import Path import time import matplotlib.pyplot as plt from pint import Quantity import pyvista as pv from ansys.health.heart.examples import get_input_leftventricle import ansys.health.heart.models as models from ansys.health.heart.post.auto_process import zerop_post from ansys.health.heart.post.dpf_utils import ICVoutReader from ansys.health.heart.settings.material.material import ACTIVE, ANISO, ISO, Mat295 from ansys.health.heart.simulator import DynaSettings, MechanicsSimulator .. GENERATED FROM PYTHON SOURCE LINES 82-84 Get the model input surface and part definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 84-97 .. code-block:: Python path_to_surface, path_to_part_definitions = get_input_leftventricle() # Plot the input surface. surface = pv.read(path_to_surface) surface.plot() # Load and print the parts defined in the JSON file. with open(path_to_part_definitions, "r") as f: part_definitions = json.load(f) # Print the part definitions using indentation for better readability. print(json.dumps(part_definitions, indent=4)) .. tab-set:: .. tab-item:: Static Scene .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_001.png :alt: mechanics simulator leftventricle pr :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_001.png :class: sphx-glr-single-img .. tab-item:: Interactive Scene .. offlineviewer:: C:\Users\ansys\actions-runner\_work\pyansys-heart\pyansys-heart\doc\source\examples\simulator\images\sphx_glr_mechanics-simulator-leftventricle_pr_001.vtksz .. rst-class:: sphx-glr-script-out .. code-block:: none { "Left ventricle": { "id": 1, "enclosed_by_boundaries": { "left-ventricle-endocardium": 1, "left-ventricle-epicardium": 2, "interface_left-ventricle-myocardium_mitral-valve-plane": 3, "interface_left-ventricle-myocardium_aortic-valve-plane": 4 } } } .. GENERATED FROM PYTHON SOURCE LINES 98-101 Load the input surface and mesh the model. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Set the working directory. .. GENERATED FROM PYTHON SOURCE LINES 101-120 .. code-block:: Python workdir = ( Path.home() / "pyansys-heart" / "downloads" / "Rodero2021" / "01" / "LeftVentricle-simulation" ) # Initialize a left ventricle model. model: models.LeftVentricle = models.LeftVentricle(working_directory=workdir) # Load the input surface. model.load_input(surface, part_definitions, scalar="surface-id") # Mesh the volume. model.mesh_volume(use_wrapper=True, global_mesh_size=4.0, _global_wrap_size=4.0) # Update the model. model.update() # Plot the mesh. model.plot_mesh() .. tab-set:: .. tab-item:: Static Scene .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_002.png :alt: mechanics simulator leftventricle pr :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_002.png :class: sphx-glr-single-img .. tab-item:: Interactive Scene .. offlineviewer:: C:\Users\ansys\actions-runner\_work\pyansys-heart\pyansys-heart\doc\source\examples\simulator\images\sphx_glr_mechanics-simulator-leftventricle_pr_002.vtksz .. GENERATED FROM PYTHON SOURCE LINES 121-124 .. note:: This mesh is very coarse for and for demonstration purposes. In practice, the mesh size should be smaller. .. GENERATED FROM PYTHON SOURCE LINES 126-129 Instantiate the simulator ~~~~~~~~~~~~~~~~~~~~~~~~~ Instantiate the simulator and define settings. .. GENERATED FROM PYTHON SOURCE LINES 129-145 .. code-block:: Python # Specify the LS-DYNA path. lsdyna_path = r"ls-dyna_mpp" # Instantiate LS-DYNA settings. dyna_settings = DynaSettings( lsdyna_path=lsdyna_path, dynatype="intelmpi", num_cpus=2, platform="windows" ) # Instantiate the simulator, modifying options as necessary. simulator = MechanicsSimulator( model=model, dyna_settings=dyna_settings, simulation_directory=os.path.join(workdir, "simulation-mechanics"), ) .. GENERATED FROM PYTHON SOURCE LINES 146-149 Load simulation settings ~~~~~~~~~~~~~~~~~~~~~~~~ Load the default settings. .. GENERATED FROM PYTHON SOURCE LINES 149-151 .. code-block:: Python simulator.settings.load_defaults() .. GENERATED FROM PYTHON SOURCE LINES 152-155 Compute fiber orientation ~~~~~~~~~~~~~~~~~~~~~~~~~ Compute fiber orientation and plot the fibers. .. GENERATED FROM PYTHON SOURCE LINES 155-161 .. code-block:: Python simulator.compute_fibers(method="D-RBM") # Plot the fiber orientation by streamlines. simulator.model.plot_fibers(n_seed_points=2000) .. tab-set:: .. tab-item:: Static Scene .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_003.png :alt: mechanics simulator leftventricle pr :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_003.png :class: sphx-glr-single-img .. tab-item:: Interactive Scene .. offlineviewer:: C:\Users\ansys\actions-runner\_work\pyansys-heart\pyansys-heart\doc\source\examples\simulator\images\sphx_glr_mechanics-simulator-leftventricle_pr_003.vtksz .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 162-164 Assign a material to the left ventricle. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 164-181 .. code-block:: Python # Define a material for the myocardium. myocardium = Mat295( rho=0.001, iso=ISO(itype=-3, beta=2, kappa=1.0, k1=0.20e-3, k2=6.55), aniso=ANISO( atype=-1, fibers=[ANISO.HGOFiber(k1=0.00305, k2=29.05), ANISO.HGOFiber(k1=1.25e-3, k2=36.65)], k1fs=0.15e-3, k2fs=6.28, ), active=ACTIVE(), # This uses the default active model ) # Assign the material to the left ventricle. simulator.model.left_ventricle.meca_material = myocardium .. GENERATED FROM PYTHON SOURCE LINES 182-184 Compute the stress-free configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 184-207 .. code-block:: Python # Compute the stress-free configuration and estimate initial stress. simulator.compute_stress_free_configuration() # Plot stress-free geometry. report, stress_free_coord, guess_ed_coord = zerop_post( os.path.join(workdir, "simulation-mechanics", "zeropressure"), model ) zerop = copy.deepcopy(model.mesh) # Update the points of the mesh with the stress-free coordinates. zerop.points = stress_free_coord # Plot the original and stress-free meshes. plotter = pv.Plotter() plotter.add_mesh(zerop, color="red", opacity=0.3, label="stress-free shape") plotter.add_mesh(simulator.model.mesh, color="grey", opacity=0.2, label="end-of-diastole") plotter.add_legend() plotter.show() # Print the stress free report in readable format. print(json.dumps(report, indent=4)) .. tab-set:: .. tab-item:: Static Scene .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_004.png :alt: mechanics simulator leftventricle pr :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_004.png :class: sphx-glr-single-img .. tab-item:: Interactive Scene .. offlineviewer:: C:\Users\ansys\actions-runner\_work\pyansys-heart\pyansys-heart\doc\source\examples\simulator\images\sphx_glr_mechanics-simulator-leftventricle_pr_004.vtksz .. rst-class:: sphx-glr-horizontal * .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_005.png :alt: EDVPR :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_005.png :class: sphx-glr-multi-img * .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_006.png :alt: EDVPR :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_006.png :class: sphx-glr-multi-img .. rst-class:: sphx-glr-script-out .. code-block:: none { "Simulation output time (ms)": [ 0.0, 100.0, 200.23744201660156, 329.7889709472656, 409.2218017578125, 509.2218017578125, 609.2218017578125, 709.2218017578125, 809.2218017578125, 909.2218017578125, 1000.0 ], "Convergence": { "max_error (mm)": 0.0, "mean_error (mm)": 0.0 }, "Left ventricle EOD pressure (mmHg)": 15.0, "True left ventricle volume (mm3)": 117537.10032219399, "Simulation left ventricle volume (mm3)": [ 67873.59161815229, 85416.36313267954, 94974.29402146801, 101931.24791258169, 104797.30955416568, 107955.9519721437, 110458.76540857709, 112828.7940870969, 114479.32023918148, 116263.38131122515, 117537.10032219399 ] } .. GENERATED FROM PYTHON SOURCE LINES 208-211 .. note:: The input geometry is assumed to be at the end-of-diastole with a ventricular pressure of 15 mmHg. You can modify this pressure in the settings. .. GENERATED FROM PYTHON SOURCE LINES 213-215 Run the main simulation ~~~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 215-223 .. code-block:: Python # Tune the boundary conditions at the valve regions: in this model there are # springs in radial and normal direction of the valve region which constrain the model. simulator.settings.mechanics.boundary_conditions.valve["stiffness"] = Quantity(0.02, "MPa/mm") # Start the mechanical simulation. simulator.simulate() .. GENERATED FROM PYTHON SOURCE LINES 224-228 .. note:: By default, the simulation is coupled to an open-loop circulation model with a constant preload and a Windkessel-type afterload. Moreover, the simulation is set to run for a single heartbeat. .. GENERATED FROM PYTHON SOURCE LINES 230-232 Postprocessing ~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 232-281 .. code-block:: Python # Plot pressure-volume loop # ~~~~~~~~~~~~~~~~~~~~~~~~~ # Read the LS-DYNA binout file that contains cavity volumes and pressure. icvout = ICVoutReader(os.path.join(workdir, "simulation-mechanics", "main-mechanics", "binout0000")) pressure = icvout.get_pressure(1) volume = icvout.get_volume(1) # Convert to mL and mmHg and plot the pressure and volume curves. plt.plot(volume / 1000, pressure * 7500, label="Left ventricle") plt.xlabel("Volume (mL)") plt.ylabel("Pressure (mmHg)") plt.title("Pressure-volume loop") plt.show() # Plot the displacement field # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ mesh_folder = os.path.join(workdir, "simulation-mechanics", "main-mechanics", "post", "vtks") mesh_files = sorted(glob.glob(f"{mesh_folder}/*.vtu")) mesh_list = [] for mesh_file in mesh_files: mesh = pv.read(mesh_file) mesh.set_active_vectors("displacement") mesh_list.append(mesh) # Create a PyVista plotter plotter = pv.Plotter() if mesh_files: actor = plotter.add_mesh(mesh_list[0]) plotter.show(interactive_update=True) # Animate the meshes over time # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Use a function for animation. def animate(): for m in mesh_list: plotter.clear() plotter.add_mesh(m, show_edges=True, opacity=0.5, scalars=None) plotter.update() plotter.render() time.sleep(0.1) # Control animation speed # Animate the model. animate() .. tab-set:: .. tab-item:: Static Scene .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_007.png :alt: mechanics simulator leftventricle pr :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_007.png :class: sphx-glr-single-img .. tab-item:: Interactive Scene .. offlineviewer:: C:\Users\ansys\actions-runner\_work\pyansys-heart\pyansys-heart\doc\source\examples\simulator\images\sphx_glr_mechanics-simulator-leftventricle_pr_007.vtksz .. image-sg:: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_008.png :alt: Pressure-volume loop :srcset: /examples/simulator/images/sphx_glr_mechanics-simulator-leftventricle_pr_008.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (8 minutes 33.007 seconds) .. _sphx_glr_download_examples_simulator_mechanics-simulator-leftventricle_pr.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: mechanics-simulator-leftventricle_pr.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: mechanics-simulator-leftventricle_pr.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: mechanics-simulator-leftventricle_pr.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_