Coverage for physioblocks / configuration / description / nets.py: 98%
45 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-09 16:40 +0100
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-09 16:40 +0100
1# SPDX-FileCopyrightText: Copyright INRIA
2#
3# SPDX-License-Identifier: LGPL-3.0-only
4#
5# Copyright INRIA
6#
7# This file is part of PhysioBlocks, a library mostly developed by the
8# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9#
10# Authors:
11# - Colin Drieu
12# - Dominique Chapelle
13# - François Kimmig
14# - Philippe Moireau
15#
16# PhysioBlocks is free software: you can redistribute it and/or modify it under the
17# terms of the GNU Lesser General Public License as published by the Free Software
18# Foundation, version 3 of the License.
19#
20# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23#
24# You should have received a copy of the GNU Lesser General Public License along with
25# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
27from typing import Any
29from physioblocks.configuration.base import Configuration, ConfigurationError
30from physioblocks.configuration.constants import (
31 BLOCKS_ITEM_ID,
32 BOUNDARIES_ID,
33 FLUX_DOF_DEFINITION_ID,
34 NET_ID,
35 NODES_ITEM_ID,
36)
37from physioblocks.configuration.functions import load, save
38from physioblocks.description.blocks import BlockDescription
39from physioblocks.description.flux import get_flux_dof_register
40from physioblocks.description.nets import BoundaryCondition, Net
41from physioblocks.registers.load_function_register import loads
42from physioblocks.registers.save_function_register import saves
45@saves(Net)
46def save_net_config(net: Net, *args: Any, **kwargs: Any) -> Configuration:
47 """
48 Create a Configuration for a net
50 :param net: the net
51 :type net: Net
53 :return: the configuration
54 :rtype: Configuration
55 """
56 # save blocks
57 blocks_config = save(net.blocks, *args, **kwargs)
58 if isinstance(blocks_config, dict) is False:
59 raise ConfigurationError(
60 str.format(
61 "Expected a dict for {0} configuration, got {1}.",
62 BLOCKS_ITEM_ID,
63 type(net.blocks).__name__,
64 )
65 )
67 # add node informations
68 for block_id, block in net.blocks.items():
69 block_connections = {
70 str(node_index): net.local_to_global_node_id(block_id, node_index)
71 for node_index in block.described_type.nodes
72 }
74 blocks_config[block_id][NODES_ITEM_ID] = block_connections
76 node_ids = list(net.nodes.keys())
77 flux_dof_register = get_flux_dof_register()
79 net_config = Configuration(NET_ID)
80 net_config[FLUX_DOF_DEFINITION_ID] = save(flux_dof_register.flux_dof_couples)
81 net_config[NODES_ITEM_ID] = node_ids
82 net_config[BLOCKS_ITEM_ID] = blocks_config
83 net_config[BOUNDARIES_ID] = save(net.boundary_conditions, *args, **kwargs)
85 return net_config
88@loads(Net)
89def load_net_config(
90 configuration: Configuration,
91 configuration_type: type[Net],
92 configurable_object: Net | None = None,
93 *args: Any,
94 **kwargs: Any,
95) -> Net:
96 """
97 Load a net from a configuration.
99 :param configuration: the configuration
100 :type configuration: Configuration
102 :param boundaries: the boundaries of the net at each node
103 :type boundaries: dict[str, list[BoundaryCondition]]
105 :return: the net
106 :rtype: Net
107 """
109 configurable_net = (
110 configuration_type() if configurable_object is None else configurable_object
111 )
112 nodes_ids = configuration[NODES_ITEM_ID]
114 # Fill the flux type singleton from the configured value
115 if FLUX_DOF_DEFINITION_ID in configuration:
116 load(
117 configuration[FLUX_DOF_DEFINITION_ID],
118 configuration_object=get_flux_dof_register(),
119 )
121 for node_id in nodes_ids:
122 configurable_net.add_node(node_id)
124 blocks_config: dict[str, Configuration] = configuration[BLOCKS_ITEM_ID].copy()
125 connections_config: dict[str, dict[str, str]] = {
126 block_key: block_config.configuration_items.pop(NODES_ITEM_ID)
127 for block_key, block_config in blocks_config.items()
128 }
130 connections: dict[str, dict[int, str]] = {
131 block_id: {
132 int(node_index): global_node
133 for node_index, global_node in connection_config.items()
134 }
135 for block_id, connection_config in connections_config.items()
136 }
137 blocks: dict[str, BlockDescription] = load(blocks_config)
139 for block_id, block in blocks.items():
140 # remove the node key (on a block configuration copy) before loading the block
141 configurable_net.add_block(block_id, block, connections[block_id])
143 boundaries: dict[str, list[BoundaryCondition]] | None = (
144 load(configuration[BOUNDARIES_ID]) if BOUNDARIES_ID in configuration else None
145 )
147 # Add boundaries conditions
148 if boundaries is not None:
149 for node_id, conditions in boundaries.items():
150 for bc in conditions:
151 configurable_net.set_boundary(
152 node_id, bc.condition_type, bc.condition_id
153 )
155 return configurable_net