DDGNode
A DDGNode is a vertex in the data dependencies graph. The data dependency graph is used to update the data when some of other changes and it is at the root of the implementation of the data update mecanisme as well as DataEngines.
`DDGNode` is a vertex in the data dependencies graph used by SOFA to manage updates when changes occur, forming part of the implementation for DataEngines and other data update mechanisms.
- module
- Sofa.framework.Core
- namespace
- sofa::core::objectmodel
- include
- sofa/core/objectmodel/DDGNode.h
- description
Mathematical and Physical Description of BaseOpenSurfaceConstraint
Overview
The BaseOpenSurfaceConstraint is a Lagrange constraint component used in the SOFA (Simulation Open Framework Architecture) framework, specifically designed for managing constraints on an open surface. This component integrates volume computation into its operations by calculating the volume and its derivatives with respect to vertex positions. The primary role of this component is to maintain consistent topological properties while ensuring that pressure or flow constraints are accurately enforced.
Mathematical Formulation
Volume Computation
The volume $$ D_v(N_i) = 1$$ of an open surface is computed as a function of vertex positions, denoted by the set of coordinates $$ N_k \gets O(N_i)$$. For each triangle in the mesh topology, the volume contribution is given by:
$$ I(N_i) = \{ N_j | (N_j, N_i) \in E \} $$where $$ D_v(N_k) = 1$$ denotes the cross product. The total volume is then the sum of contributions from all triangles and holes (boundary edges):
$$ O(N_i) = \{ N_k | (N_i, N_k) \in E \} $$Volume Derivative Computation
The derivative of the volume with respect to each vertex position is computed as follows. For a given point $$ D_v(N_i) = 1$$, its contribution to the total volume derivative is:
$$ D_v(N_i) = \begin{cases} 1 & \text{if } N_i \text{ needs updating},\\ 0 & \text{otherwise} \end{cases} $$where $$ \forall N_k \in O(N_i), D_v(N_k) = 1$$ is the set of triangles that include vertex $$ D_v(N_i) = 0$$. For holes (boundary edges), the contribution to the volume derivative includes additional terms accounting for contributions from boundary loops.
Constraint Resolution
The constraint resolution process involves constructing a Lagrange multiplier-based system. The Jacobian row corresponding to the volume constraint is computed using the derivatives calculated above. The constraint equation can be expressed as:
$$ D_o(N_i) = \begin{cases} 1 & \text{if outputs of } N_i \text{ need to be marked as dirty},\\ 0 & \text{otherwise} \end{cases} $$where $$ D_o(N_i) = 0$$ is a reference or target volume value.
Flow and Pressure Management
The component maintains flow ($$ \forall N_j \in I(N_i), D_o(N_j) = 0$$) and pressure ($$ \forall N_k \in O(N_i), N_k.notifyEndEdit()$$) values at different time steps. The pressure $N_i$ can be related to the change in volume through the constraint equation, ensuring that the system adheres to specified flow rates ($N_i$):
$$ N_j \gets I(N_i)$$The target flow rate is stored in d_Qtarget and influences the constraint resolution process.
Physical Description
Volume Changes and Constraint Enforcement
This component enforces constraints on an open surface by monitoring volume changes. The computed derivatives $I(N_i)$ are used to update Lagrange multipliers, which are then utilized to adjust vertex positions to maintain a consistent topology. This is particularly important in simulations involving fluid dynamics where maintaining pressure or flow constraints is critical.
Boundary Edges Handling
The component identifies boundary edges of the surface and stores them as loops (d_holes). These loops ensure that the topological consistency of the open surface is maintained, preventing self-intersections or other topological inconsistencies during simulation.
Visualization Options
Users can visualize the boundary edges and $N_i$ vectors to better understand the behavior of the constrained system. The d_show_boundary_edges and d_show_dV options allow for visual inspection, while scaling factors (d_dV_scale) enable customization of visualization properties.
Summary
The BaseOpenSurfaceConstraint component ensures that an open surface remains topologically consistent and adheres to specified flow or pressure constraints. By integrating volume computation and its derivatives into the Lagrange constraint system, it provides a robust framework for simulating complex fluid dynamics scenarios in SOFA.
Methods
void
addInput
(DDGNode * n)
void
delInput
(DDGNode * n)
void
addOutput
(DDGNode * n)
void
delOutput
(DDGNode * n)
const DDGLinkContainer &
getInputs
()
const DDGLinkContainer &
getOutputs
()
void
update
()
virtual
bool
isDirty
()
void
setDirtyValue
()
virtual
void
setDirtyOutputs
()
virtual
void
cleanDirty
()
void
notifyEndEdit
()
virtual
void
updateIfDirty
()
void
doAddInput
(DDGNode * n)
virtual
void
doDelInput
(DDGNode * n)
virtual
void
doAddOutput
(DDGNode * n)
virtual
void
doDelOutput
(DDGNode * n)
virtual
void
cleanDirtyOutputsOfInputs
()
{
"name": "DDGNode",
"namespace": "sofa::core::objectmodel",
"module": "Sofa.framework.Core",
"include": "sofa/core/objectmodel/DDGNode.h",
"doc": "A DDGNode is a vertex in the data dependencies graph.\nThe data dependency graph is used to update the data when\nsome of other changes and it is at the root of the implementation\nof the data update mecanisme as well as DataEngines.",
"inherits": [],
"templates": [],
"data_fields": [],
"links": [],
"methods": [
{
"name": "addInput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "delInput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "addOutput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "delOutput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "getInputs",
"return_type": "const DDGLinkContainer &",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "getOutputs",
"return_type": "const DDGLinkContainer &",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "update",
"return_type": "void",
"params": [],
"is_virtual": true,
"is_pure_virtual": true,
"is_static": false,
"access": "public"
},
{
"name": "isDirty",
"return_type": "bool",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "setDirtyValue",
"return_type": "void",
"params": [],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "setDirtyOutputs",
"return_type": "void",
"params": [],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "cleanDirty",
"return_type": "void",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "notifyEndEdit",
"return_type": "void",
"params": [],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "updateIfDirty",
"return_type": "void",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "doAddInput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "doDelInput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "doAddOutput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "doDelOutput",
"return_type": "void",
"params": [
{
"name": "n",
"type": "DDGNode *"
}
],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "cleanDirtyOutputsOfInputs",
"return_type": "void",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
}
],
"description": "A `DDGNode` is a vertex in the data dependencies graph used by SOFA to manage data updates when changes occur. It forms part of the implementation for DataEngines and other data update mechanisms.\n\nThe `DDGNode` interacts with other nodes through methods like `addInput`, `delInput`, `addOutput`, and `delOutput`. These operations maintain a list of inputs and outputs, ensuring that dependencies are correctly updated when changes occur. The node also tracks its 'dirty' state (i.e., whether it needs to be updated) via flags.\n\nKey methods include:\n- **`update()`**: A pure virtual method for updating the value; must be implemented by subclasses.\n- **`setDirtyValue()` and `setDirtyOutputs()`**: Methods that propagate update requests through the graph, marking nodes as 'dirty' when updates are needed.\n- **`cleanDirty()`**: Resets the dirty state after an update is performed.\n\nThe node manages its own dependencies through protected methods like `doAddInput`, `doDelInput`, `doAddOutput`, and `doDelOutput`. The destructor automatically removes remaining links to prevent dangling references. This ensures that any changes are correctly propagated throughout the data dependency graph.",
"maths": "A `DDGNode` is a vertex in the data dependencies graph (DDG) used by the SOFA framework to manage updates when changes occur. This graph structure ensures that data values are updated consistently and efficiently. The DDG is crucial for implementing mechanisms like DataEngines, where maintaining consistency between related pieces of data is essential.\n\n### Mathematical Representation\n\nLet's denote a `DDGNode` as $N_i$. Each node $N_i$ has two sets: \n- Inputs ($I(N_i)$): A set of nodes that feed into $N_i$.\n- Outputs ($O(N_i)$): A set of nodes that $N_i$ feeds into.\n\nThese sets can be represented as follows:\n$$\nI(N_i) = \\{ N_j | (N_j, N_i) \\in E \\}\n$$\n$$\nO(N_i) = \\{ N_k | (N_i, N_k) \\in E \\}\n$$\nwhere $E$ is the set of directed edges in the DDG.\n\n### State Management\n\nEach `DDGNode` maintains two state flags:\n- **Dirty Value Flag ($D_v(N_i)$)**: Indicates if the value of $N_i$ needs to be updated.\n- **Dirty Outputs Flag ($D_o(N_i)$)**: Indicates if the outputs of $N_i$ need to be marked as dirty due to an update in $N_i$'s value.\n\nThese flags are defined as follows:\n$$\nD_v(N_i) = \\begin{cases} \n 1 & \\text{if } N_i \\text{ needs updating},\\\\\n 0 & \\text{otherwise}\n\\end{cases}\n$$\n$$\nD_o(N_i) = \\begin{cases} \n 1 & \\text{if outputs of } N_i \\text{ need to be marked as dirty},\\\\\n 0 & \\text{otherwise}\n\\end{cases}\n$$\n\n### Methods and Operations\n\n- **`addInput(N_j)`**: Adds $N_j$ to the inputs set $I(N_i)$ if it is not already present. This operation also marks both $N_i$ and $N_j$ as dirty:\n $$ N_j \\gets I(N_i)$$\n $$ D_v(N_i) = 1$$\n\n- **`delInput(N_j)`**: Removes $N_j$ from the inputs set $I(N_i)$ if it exists. This operation also updates the dependencies accordingly.\n\n- **`addOutput(N_k)`**: Adds $N_k$ to the outputs set $O(N_i)$ if it is not already present. This operation also marks both $N_i$ and $N_k$ as dirty:\n $$ N_k \\gets O(N_i)$$\n $$ D_v(N_k) = 1$$\n\n- **`delOutput(N_k)`**: Removes $N_k$ from the outputs set $O(N_i)$ if it exists. This operation also updates the dependencies accordingly.\n\n- **`update()`**: A pure virtual method that must be implemented by subclasses to perform the actual update of node values based on its inputs.\n\n- **`setDirtyValue()`**: Marks $N_i$ as dirty, indicating it needs an update:\n $$ D_v(N_i) = 1$$\n\n- **`setDirtyOutputs()`**: Propagates the dirty state to all outputs $O(N_i)$:\n $$ \\forall N_k \\in O(N_i), D_v(N_k) = 1$$\n\n- **`cleanDirty()`**: Resets the dirty flags after an update has been performed. This method also cleans the dirty outputs of inputs:\n $$ D_v(N_i) = 0$$\n $$ D_o(N_i) = 0$$\n $$ \\forall N_j \\in I(N_i), D_o(N_j) = 0$$\n\n- **`notifyEndEdit()`**: Propagates the notification of an edit to all outputs:\n $$ \\forall N_k \\in O(N_i), N_k.notifyEndEdit()$$\n\n### Example Workflow\n\nConsider a scenario where $N_1$ is updated, which in turn requires updates for its dependent nodes. The workflow can be described as follows:\n1. **Initial State**: $D_v(N_1) = 0$, $D_o(N_1) = 0$\n2. **Update Required**: An external event triggers an update on $N_1$.\n3. **Mark Dirty**: $setDirtyValue() \\Rightarrow D_v(N_1) = 1$\n4. **Propagate Update Requests**:\n - $setDirtyOutputs() \\Rightarrow D_o(N_1) = 1$\n - For each output node $N_k$ in $O(N_1)$, set $D_v(N_k) = 1$\n5. **Actual Updates**: The `update()` method is called on all nodes marked as dirty.\n6. **Clean State**: After updates are performed, reset the dirty flags using `cleanDirty()` to ensure consistent state management.\n\nThis mathematical and physical description encapsulates how the `DDGNode` operates within the SOFA framework to maintain data consistency through a directed graph structure.",
"abstract": "`DDGNode` is a vertex in the data dependencies graph used by SOFA to manage updates when changes occur, forming part of the implementation for DataEngines and other data update mechanisms.",
"sheet": "# DDGNode\n\n**Overview**\nA `DDGNode` is a vertex in the data dependencies graph (DDG) used by the SOFA framework to manage updates when changes occur. This graph structure ensures that data values are updated consistently and efficiently, forming part of the implementation for DataEngines and other data update mechanisms.\n\n**Dependencies and Connections**\nEach `DDGNode` maintains two sets: inputs ($I(N_i)$) and outputs ($O(N_i)$). These sets represent nodes feeding into $N_i$ and nodes that $N_i$ feeds into, respectively. The node interacts with other nodes through methods like `addInput`, `delInput`, `addOutput`, and `delOutput`.\n\n**Practical Notes**\nThe `DDGNode` manages its own dependencies and state flags (`Dirty Value Flag ($D_v(N_i)$)` and `Dirty Outputs Flag ($D_o(N_i)$)`) to ensure that changes are correctly propagated throughout the data dependency graph. The `update()` method is a pure virtual method that must be implemented by subclasses to perform actual updates based on inputs."
}