Write a net configuration file

In this section, we will learn how to write configuration files describing Nets.

We will first describe the net description syntax, then provide example nets description. The first example concerns how to create Blocks, Nodes and link them in a Net. The second will introduce Model Components.

Net description syntax

The Net Descriptions are done in JSON files and have four main components:

  1. Type: for now, it should always be net. We will detail the use of this field later in the alias section.

  2. Flux DOF couples Definitions: a dictionary of all the flux types names in the net matching their DOF type names

  3. Nodes: a list of the Nodes names in the net.

  4. Blocks: a dictionary of all the blocks in the net with their names. The blocks are defined by their:

    1. Type: underlying model defining the Flux and Internal Equations of the block.

    2. Flux Type: flux type exchanged by the block. Nodes can receive any flux type from blocks. They sum Flux by type thus providing one equation per type of flux they receive.

    3. Global Ids: global names in the net of the block parameters and variable local names.

    4. Connections: for every local node sharing a flux in the block, their matching global node in the net.

    5. Sub-models: The model components enhancing the Block.

Note

An other composant of the Nets are the Boundary Conditions, we will cover them in the next section.

As a first example, we will create a simple circulation net configuration file consisting in a two state windkessel model.

Simple circulation net example

This simple example will focus on :

  • creating nodes, blocks, link them in the net

  • change the blocks parameters name in the global system.

Simple circulation net model

The model we are going to describe with a Net is the following:

Figure made with TikZ

Simple circulation model scheme

From a block-node perspective, it contains two unit RCBlock and three nodes named A, B and C.

Note

Notice that the fluxes are expressed towards the output of the blocks to match the block flux definition in the RCBlock documentation.

From the RCBlock documentation, we get the fluxes described for the block, and can draw the matching block-node diagram.

Figure made with TikZ

Simple circulation system block-node diagram

We will now create a net configuration file step by step to represent this diagram.

Declare the net and its nodes

In an empty JSON file, we have to declare the fields:

  • type: Set the configuration object type we are writing to define a net

  • flux_dof_definitions: Set all the flux types and their matching DOF type

  • nodes: Set the list of node names to “A”, “B” and “C”.

{
    "type": "net",
    "flux_dof_definitions": {"flow": "pressure"},
    "nodes": ["A", "B", "C"]
}

Declare blocks and add them to the Net

Like the net, the block itself is represented with a dictionary. To declare it as a RC block, we set its type field. (you should be able to find the correct value to set to type for each block in the blocks alias documentation).

We also set the block’s flux type to flow, the only available flux type in our net.

{
    "type": "rc_block",
    "flux_type": "flow"
}

The block is then added into the blocks dictionary and named RC_1. Declare a second block named RC_2 and the configuration file should now look like this:

{
    "type": "net",
    "flux_dof_definitions": {"flow": "pressure"},
    "nodes": ["A", "B", "C"],
    "blocks": {
        "RC_1": {
            "type": "rc_block",
            "flux_type": "flow"
        },
        "RC_2": {
            "type": "rc_block",
            "flux_type": "flow"
        }
    }
}

Update blocks parameters names

Default names for the block parameters are $BLOCK_NAME$.$LOCAL_PARAMETER_NAME$. In the example, the \(R_A\) resistance is named RC_1.resistance.

You can rename them in the Block Description:

{
    "type": "rc_block",
    "flux_type": "flow",
    "resistance": "Ra", // Default RC_1.resistance is renamed Ra
    "capacitance": "Ca", // Default RC_1.capacitance is renamed Ca
    "nodes": {
        1: "B",
        2: "A"
    }
}

If you also rename RC_2 block parameters to match the model name, you get the following configuration file:

{
    "type": "net",
    "flux_dof_definitions": {"flow": "pressure"},
    "nodes": ["A", "B", "C"],
    "blocks": {
        "RC_1": {
            "type": "rc_block",
            "flux_type": "flow",
            "resistance": "Ra",
            "capacitance": "Ca",
            "nodes":
            {
                1: "B",
                2: "A"
            }
        },
        "RC_2": {
            "type": "rc_block",
            "flux_type": "flow",
            "resistance": "Rb",
            "capacitance": "Cb",
            "nodes":
            {
                1: "C",
                2: "B"
            }
        }
    }
}

You may notice that we did not rename the pressures quantities to Pa, Pb and Pc. Those quantities are DOFs created by Global Nodes. Their default names are $NODE_NAME$.$DOF_TYPE$ with the DOF type matching the flux type shared at the node. For example here, the DOF has a pressure type, so it is named A.pressure.

Note

Notice that the A and B nodes only have one flux going in.

This is inconsistent with our definition for the nodes where fluxes have to verify Kirchhoff’s law. In the next section we will learn to add Boundary Conditions at nodes to complete the system.

You can now define simples nets. If you want to skip to the next section, you should already be able to follow the guide using this net JSON configuration.

The next part will provide a more complete example of a net description using model components.

Cardiovascular system net example

We are now going to see a more complete Net example to learn how to:

  • Enhance Blocks Definition with Model Components

  • Define Blocks parameters and variables that share the same quantity.

Cardiovascular system model

Given the following cardiovascular model, we can schematize a Block-Node layout of the Net.

Figure made with TikZ

Simple cardiovascular system model

Figure made with TikZ

Simple cardiovascular system Block-Node diagram

Note

If you want to launch a simulation of the model, a simulation configuration using the model is in the reference folder of the PhysioBlocks package.

Every block here has an implementation in the PhysioBlocks library. See the library section of the API Reference for descriptions of the fluxes and internal equations shared for each block. The type names to declare the blocks in configurations are described in the alias section of the library.

Note

Notice again that nodes in the net match pressures in the model : the pressures are the DOFs of the net.

Applying the assembling process described in the previous section, we get one equation per node in the Net. They provide a dynamics on the DOFs.

The other equations are the Blocks and Model Components Internal Equations that are concatenated to the system.

Especially, the cavity only defines a flux based on its deformation. The model components attached to the cavity block are concatenating equations to the global system to provide a dynamics on the pressure shared at the ventricle node.

Note

Notice again that the atrial and the venous nodes only have one Flux going in. Net definition should be completed with Boundary Conditions when creating a simulation configuration.

Create net, nodes and blocks

First, let’s write the Net JSON description of the Block-Node diagram without the model components. Following the process in the last example, we declare:

  • the net type.

  • the fluxes-DOFs couples (for the cardiovascular system, we declare a "blood_flow": "blood_pressure" couple)

  • the nodes names.

  • We refer to the documentation in the Llbrary to:

    • Declare the needed block types.

    • Link the local node indexes in the blocks to the global nodes names in the net.

The JSON file should look like this:

{
    "type": "net",
    "flux_dof_definitions": {"blood_flow": "blood_pressure"},
    "nodes": [
        "cavity",
        "atrial",
        "proximal",
        "distal",
        "venous"
    ],
    "blocks": {
        "cavity": {
            "type": "spherical_cavity_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "cavity"
            }
        },
        "valve_atrium": {
            "type": "valve_rl_block",
            "flux_type": "blood_flow",
            "backward_conductance": "conductance_iso",
            "nodes": {
                "1": "atrial",
                "2": "cavity"
            }
        },
        "valve_arterial": {
            "type": "valve_rl_block",
            "flux_type": "blood_flow",
            "backward_conductance": "conductance_iso",
            "nodes": {
                "1": "cavity",
                "2": "proximal"
            }
        },
        "capacitance_valve": {
            "type": "c_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "cavity"
            }
        },
        "circulation_aorta_proximal": {
            "type": "rc_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "distal",
                "2": "proximal"
            }
        },
        "circulation_aorta_distal": {
            "type": "rc_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "venous",
                "2": "distal"
            }
        }
    }
}

Here we kept default block names for parameters except for the backward_conductance of both valves.

Notice that we give them the same id in both valve blocks. This will result in both backward_conductance sharing the same quantity (\(K_{iso}\) in the model).

Add model components to blocks

Based on the SphericalCavityBlock object documentation, notice the cavity contributes a flux that only depends on the cavity volume variation based on disp (\(y\) in the model). We could consider disp as a parameter and give it a value that varies over time.

But here, we will add model components to the cavity to enhance the block with a dynamics on \(y\) related to the pressure in the Ventricle (ie. the DOF at node ventricle or \(P_V\) in the model).

To add a model component to a block, we update the submodels dictionary of the block. Every model component is defined with a dictionary where the type field is set to the wanted model component type.

You will find the description of the model component internal equations in the library and their type names in the alias section.

For our cardiovascular system net, the cavity with sub-models gives:

{
    "type": "spherical_cavity_block",
    "flux_type": "blood_flow",
    "submodels": {
        "dynamics": {
            "type": "spherical_dynamics_hht_model",
        },
        "velocity_law": {
            "type": "velocity_law_hht_model",
        },
        "rheology": {
            "type": "rheology_fiber_additive_model",
            "submodels": {
                "active_law": {
                    "type": "active_law_macro_huxley_two_moments_model",
                }
            }
        }
    },
    "nodes": {
        "1": "cavity"
    }
}

Notice that the active law is itself a submodel of the rheology model component. You can add model components to any block or other model components updating its submodels entry.

In fact, since it only concatenates internal equations to the global system, you could perfectly add the same model components to any block sub-models field and obtain the same results.

Still, the goal here is to have a clear layout for the net while also having consistent default parameters names. It will also allow us to simplify the net using aliases as we will see later.

Shared quantities for parameters and variables

At this point, the cavity will still not work as expected. Here every model component defines its own parameters and variables.

We have to make the model component use the same quantities for the variables and parameters that are shared. This is done using common names for the parameters and variables across blocks and model components.

For example here, disp the cavity deformation (\(y\) in the cavity model) has to be the same quantity in both the cavity, the spherical dynamics, the velocity law and the rheology.

Let’s complete the cavity definition:

{
    "type": "spherical_cavity_block",
    "flux_type": "blood_flow",
    "disp": "cavity.dynamics.disp",
    "radius": "heart_radius",
    "thickness": "heart_thickness",
    "submodels": {
        "dynamics": {
            "type": "spherical_dynamics_hht_model",
            "fib_deform": "cavity.rheology.fib_deform",
            "pressure": "cavity.blood_pressure",
            "pressure_external": "pleural.pressure",
            "vel": "cavity.velocity_law.vel",
            "radius": "heart_radius",
            "thickness": "heart_thickness",
            "series_stiffness": "cavity.rheology.series_stiffness"
        },
        "velocity_law": {
            "type": "velocity_law_hht_model",
            "disp": "cavity.dynamics.disp"
        },
        "rheology": {
            "type": "rheology_fiber_additive_model",
            "disp": "cavity.dynamics.disp",
            "active_tension_discr": "cavity.rheology.active_law.active_tension_discr",
            "radius": "heart_radius",
            "submodels": {
                "active_law": {
                    "type": "active_law_macro_huxley_two_moments_model",
                    "fib_deform": "cavity.rheology.fib_deform",
                    "contractility": "heart_contractility"
                }
            }
        }
    },
    "nodes": {
        "1": "cavity"
    }
}

The next array summarizes every quantity global name matching its local names as defined in the model components and blocks.

Global Name

cavity

dynamics

velocity_law

rheology

active_law

cavity.blood_pressure

pressure

pleural.pressure

pressure_external

heart_radius

radius

radius

radius

heart_thickness

thickness

thickness

cavity.dynamics.disp

disp

disp

disp

disp

cavity.velocity_law.vel

vel

vel

cavity.rheology.fib_deform

fib_deform

fib_deform

cavity.rheology.series_stiffness

series_stiffness

series_stiffness

cavity.rheology.active_law.active_tension_discr

active_tension_discr

active_tension_discr

heart_contractility

contractility

The entries are in bold when the global name is the default name of the parameter, variable or DOFs, the origin of which is indicated as the first part of the quantity name.

Note

cavity.blood_pressure is a DOF defined in the net: the pressure point matching \(P_V\) in the model.

In our net, the pleural pressure is a parameter, but we could increase the net to make it a DOF and provide a dynamics on it.

Full net description

Finally, the full JSON net description for our model gives:

{
    "type": "net",
    "flux_dof_definitions": {"blood_flow": "blood_pressure"},
    "nodes": [
        "cavity",
        "atrial",
        "proximal",
        "distal",
        "venous"
    ],
    "blocks": {
        "cavity": {
            "type": "spherical_cavity_block",
            "flux_type": "blood_flow",
            "disp": "cavity.dynamics.disp",
            "radius": "heart_radius",
            "thickness": "heart_thickness",
            "submodels": {
                "dynamics": {
                    "type": "spherical_dynamics_hht_model",
                    "fib_deform": "cavity.rheology.fib_deform",
                    "pressure": "cavity.blood_pressure",
                    "pressure_external": "pleural.pressure",
                    "vel": "cavity.velocity_law.vel",
                    "radius": "heart_radius",
                    "thickness": "heart_thickness",
                    "series_stiffness": "cavity.rheology.series_stiffness"
                },
                "velocity_law": {
                    "type": "velocity_law_hht_model",
                    "disp": "cavity.dynamics.disp"
                },
                "rheology": {
                    "type": "rheology_fiber_additive_model",
                    "disp": "cavity.dynamics.disp",
                    "active_tension_discr": "cavity.rheology.active_law.active_tension_discr",
                    "radius": "heart_radius",
                    "submodels": {
                        "active_law": {
                            "type": "active_law_macro_huxley_two_moments_model",
                            "fib_deform": "cavity.rheology.fib_deform",
                            "contractility": "heart_contractility"
                        }
                    }
                }
            },
            "nodes": {
                "1": "cavity"
            }
        },
        "valve_atrium": {
            "type": "valve_rl_block",
            "flux_type": "blood_flow",
            "backward_conductance": "conductance_iso",
            "nodes": {
                "1": "atrial",
                "2": "cavity"
            }
        },
        "valve_arterial": {
            "type": "valve_rl_block",
            "flux_type": "blood_flow",
            "backward_conductance": "conductance_iso",
            "nodes": {
                "1": "cavity",
                "2": "proximal"
            }
        },
        "capacitance_valve": {
            "type": "c_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "cavity"
            }
        },
        "circulation_aorta_proximal": {
            "type": "rc_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "proximal"
                "2": "distal",
            }
        },
        "circulation_aorta_distal": {
            "type": "rc_block",
            "flux_type": "blood_flow",
            "nodes": {
                "1": "venous",
                "2": "distal"
            }
        }
    }
}

Now that we know how to define a net with a JSON file, we are going to see how to write a simulation configuration to run a simulation based on a net description.