See code in GitLab.
Author: Tobias Gerach tobias.gerach@kit.edu
EMI basics.
The EMI model (Extracellular–Membrane–Intracellular) resolves each cardiomyocyte as an independent intracellular subdomain coupled to a shared extracellular domain and, if present, to neighbouring myocytes through explicit membrane faces. This is fundamentally different from bidomain or monodomain, where all intracellular space is treated as a continuous medium.
This example introduces the building blocks of an EMI simulation on a minimal geometry: two 50 × 18 × 18 µm3 cardiomyocytes lying end to end in an extracellular domain, coupled by a gap junction at their shared face. It covers the EMI mesh anatomy, the EMI-specific carputils functions, gap-junction and per-cell heterogeneity, and how to visualise the extracellular potential \(\phi_e\) in meshalyzer.
A standard openCARP mesh (.pts/.elem) describes a uniform volume.
EMI additionally requires two tag-list files that declare which element tags
form intracellular domains and which form the extracellular domain:
<mesh>.intraOne intracellular region per cardiomyocyte. Format: first line is the count, then one tag per line.
<mesh>.extraTags of the extracellular domain. Same format.
openCARP auto-detects the membrane interface as any face shared between an intracellular and an extracellular element. Gap junctions are faces shared between two intracellular elements.
The mesh is generated on the fly with mesh.Block and two
mesh.BoxRegion tags, one per cell. BoxRegion has an asymmetric
convention: lowerleft is the absolute lower corner, but the mesher adds
the block centre to upperright, so the upper corner must be supplied
relative to the centre. A small helper hides this and tags a cell by its
absolute x-range:
centre = (90.5, 65, 13) # µm
geom = mesh.Block(size=(0.181, 0.130, 0.026), # mm: 181 × 130 × 26 µm
resolution=0.002, etype='tetra',
centre=tuple(c/1000 for c in centre))
def cell_box(xmin, xmax, tag):
lo = (xmin, 56, 4)
hi = (xmax - centre[0], 74 - centre[1], 22 - centre[2])
return mesh.BoxRegion(lowerleft=tuple(v/1000 for v in lo),
upperright=tuple(v/1000 for v in hi),
tag=tag, bath=0)
geom.add_region(cell_box(40, 90, tag=2)) # left cell
geom.add_region(cell_box(90, 140, tag=4)) # right cellThe two boxes abut at the midplane; the face they share becomes the gap junction.
After generation the script writes the two EMI tag files alongside the mesh:
# .extra: one region, tag 1 (the extracellular domain — default mesher tag)
with open(meshname + '.extra', 'w') as f:
f.write('1\n1')
# .intra: two regions, tags 2 and 4 (the two cells)
with open(meshname + '.intra', 'w') as f:
f.write('2\n2\n4')Note
EMI uses isotropic conductivity per region (g_bath in S/m) and does
not use fibre orientation, which is implicitly represented by the geometry
and connectivity of the myocyte network. A .lon file will be present in the mesh
directory because the mesher always generates one, but openCARP ignores
it for EMI physics.
EMI partitions the mesh one tag at a time: every element sharing an
intra- or extracellular tag is assigned to the same MPI rank, so a cell or
the surrounding extracellular domain is never split across ranks. The number of MPI ranks
is therefore bounded by the total number of unique tags — the intracellular
tags listed in <mesh>.intra plus the extracellular tags in
<mesh>.extra:
n_ranks <= (unique intracellular tags) + (unique extracellular tags)
Tags are distributed to ranks in ascending order by default; an optional
<mesh>.part file (one tag / rank pair per line) overrides this
mapping when a specific assignment is desired. Requesting more ranks than
there are tags aborts the run with an explicit error rather than silently
degrading the partition.
During setup openCARP decouples the mesh into two sub-meshes written to the simulation output directory:
<basename>_e.*Volumetric mesh of the decoupled domain — the extracellular region and
both intracellular cells. phie.igb is stored here as nodal data:
the extracellular potential \(\phi_e\) on extracellular nodes and the
intracellular potential on the cell nodes. Being nodal, meshalyzer can
plot time traces at individual nodes.
<basename>_m.*Surface mesh of the membrane interface. vm.igb is stored here as
cell data — one value per membrane face, not per node. Meshalyzer
renders it as a colour map; it cannot plot per-element time traces.
tools.gen_physics_opts registers the EMI physics type with openCARP:
tools.gen_physics_opts(EMI=True)generates
-num_phys_regions 1
-phys_region[0].name "EMI domain"
-phys_region[0].ptype 6ptype 6 is the EMI physics identifier. For bidomain/monodomain simulations
ptype 0 (intracellular) and ptype 1 (extracellular) are used instead.
EMI uses model.ConductivityRegionEMI in place of the bidomain
model.ConductivityRegion. The two factory methods
extra_default and intra_default create catch-all regions that apply
to all extracellular and intracellular elements respectively, without
requiring an explicit tag list. openCARP determines which elements belong to
each category from the .extra and .intra tag files.
model.ConductivityRegionEMI.extra_default(g_bath=2.0)
model.ConductivityRegionEMI.intra_default(g_bath=0.4)These two calls, passed via opts_formatted(i), generate:
-num_gregions 2
-gregion[0].name "extra_regions_default"
-gregion[0].g_bath 2.0
-gregion[0].g_mult 1.0
-gregion[1].name "intra_regions_default"
-gregion[1].g_bath 0.4
-gregion[1].g_mult 1.0g_bath is the isotropic conductivity in S/m. No longitudinal/transverse
split is needed because EMI resolves individual cells and their geometry
explicitly rather than relying on fibre-direction homogenisation.
Individual region conductivities can still be modified by tag ID to override the defaults for specific element groups. For example, to raise the intracellular conductivity of the right-hand cell (tag 4) relative to the default:
model.ConductivityRegionEMI([4], 'region 4', g_bath=1.5)which generates:
-gregion[2].name "region 4"
-gregion[2].num_IDs 1
-gregion[2].ID[0] 4
-gregion[2].g_bath 1.5
-gregion[2].g_mult 1.0The two default regions already cover both cells and the extracellular domain; an explicit entry like the one above is only needed to make an individual cell heterogeneous.
The cell pair is excited by a transmembrane current stimulus applied at the
left end. Dirichlet grounds on the outer faces of the extracellular domain
pin its potential here, but they are not required: with no ground or
Dirichlet boundary the solver handles the floating extracellular potential
through null-space removal. Stimulus modes and electrode geometry are covered
in the 01_stimulation example.
EMI requires two ionic model regions, one for membrane faces (between an
intracellular and an extracellular element) and one for gap-junction faces
(between two intracellular elements). The emi=True keyword switches the
carputils array from imp_region to imp_region_emi:
model.ionic.AlievPanfilovIonicModel(None, 'default_ionic', emi=True)
model.ionic.PlonseyIonicModel(None, 'default_gap_junction', Rm=0.0045, emi=True)generates:
-num_imp_regions 2
-imp_region_emi[0].name "default_ionic"
-imp_region_emi[0].im AlievPanfilov
-imp_region_emi[1].name "default_gap_junction"
-imp_region_emi[1].im Plonsey
-imp_region_emi[1].im_param Rm=0.0045openCARP assigns imp_region_emi[0] to membrane faces and
imp_region_emi[1] to gap-junction faces based on the mesh topology.
IDs=None (first positional argument) means the model applies to all faces
of that type; no explicit face-tag list is needed.
The Plonsey model represents a gap junction as a purely resistive membrane
with resistance \(R_m\) [kΩ cm²]. Here the two cells share a single
internal face, so imp_region_emi[1] is active on that one gap junction;
with the low default resistance the pair conducts almost like a continuous
cell.
Heterogeneity can be introduced by adding extra imp_region_emi entries
with explicit face IDs. In the EMI model, the gap-junction face between two
cells with element tags a and b is identified by the compound face ID
a:b. The junction between cells 2 and 4 is therefore 2:4; to raise
its resistance and slow conduction across it:
model.ionic.PlonseyIonicModel(['2:4'], 'blocking_gj', Rm=0.5, emi=True)This becomes imp_region_emi[2] — a third entry that overrides the
default gap-junction region for that face group. Membrane faces are
identified the same way, by the pair of the intracellular tag and the
extracellular tag: cell 4's membrane is 4:1. Giving it its own
imp_region_emi entry assigns that cell a distinct ionic model — the basis
for representing different cell types (atrial, ventricular, nodal):
model.ionic.tenTusscherPanfilovIonicModel(['4:1'], 'tt_cell_4', emi=True)With --visualize, meshalyzer opens phie.igb on the volumetric
sub-mesh <basename>_e with a pre-configured view (clipping plane through
the block midpoint, potential range ±0.0125 mV at time slice 10, isolines over
the same range). This view is tuned for the default homogeneous mode; the
other modes produce different ranges and need re-scaling. To inspect the
transmembrane voltage open vm.igb on <basename>_m in a second window.
cd examples/07_EMI/00_basics
./run.py --visualize--mode selects a heterogeneity demonstration on the right cell (tag 4):
conductivity overrides its intracellular conductivity, block raises the
gap-junction resistance to block conduction across the 2:4 interface, and
ionic switches it to the tenTusscher-Panfilov model. The default
homogeneous leaves both cells identical.
./run.py --mode block --visualizeThere are tagged with EMI, carputils.
Here we display the 5 most recent questions. You can click on each tag to show all questions for this tag.
You can also ask a new question.
© Copyright 2020 openCARP project Supported by DFG and EuroHPC Contact Imprint and data protection