SurfacePressureForceField
Pressure applied on a generic surface (triangular or quadrangular). SurfacePressureForceField Class Implements a pressure force applied on a triangle or quad surface. Each surfel receives a pressure in the direction of its normal.
The `SurfacePressureForceField` applies pressure forces to surfaces composed of triangular or quadrilateral elements in the direction of their normal vectors, supporting various modes such as pulse mode and volume conservation.
- module
- Sofa.Component.MechanicalLoad
- namespace
- sofa::component::mechanicalload
- include
- sofa/component/mechanicalload/SurfacePressureForceField.h
- inherits
-
- ForceField
- templates
-
- sofa::defaulttype::Rigid3Types
- sofa::defaulttype::Vec3Types
- description
Governing Equations and Operators
The SurfacePressureForceField in the SOFA framework implements a pressure force field that is applied to surfaces composed of triangular or quadrilateral elements. This force field contributes primarily to the internal forces, denoted as $\mathbf{f}_{int}$, which are integrated into the global system equations.
Internal Forces ($oldsymbol{f_{int}}$)
The pressure force is applied in the direction of the normal vector for each surfel (surface element). The pressure force per unit area is defined by the parameter d_pressure and can be cyclically varied if d_pulseMode is enabled.
For a triangle with vertices $oldsymbol{a}$, $oldsymbol{b}$, and $oldsymbol{c}$, the normal vector $oldsymbol{n}_i$ for each vertex $i
eq 0$ (assuming $i = 1, 2$) is given by:
egin{align}
\boldsymbol{n}_i &= \frac{(\boldsymbol{b} - \boldsymbol{a}) \times (\boldsymbol{c} - \boldsymbol{a})}{6}
\end{align}
The pressure force $oldsymbol{p}$ for each vertex is then computed as:
egin{align}
\boldsymbol{p}_i &= p \cdot \boldsymbol{n}_i,
\end{align}
where $p$ is the applied pressure. If d_mainDirection is set, the force $oldsymbol{p}$ is projected onto the main direction vector $oldsymbol{m}$:
egin{align}
\boldsymbol{p}_i &= p \cdot (|\boldsymbol{n}_i \cdot \boldsymbol{m}|) \cdot \boldsymbol{n}_i,
\end{align}
where $|\boldsymbol{n}_i \\cdot \boldsymbol{m}|$ is the absolute value of the dot product between $oldsymbol{n}_i$ and $oldsymbol{m}$.
For a quadrilateral with vertices $oldsymbol{a}, oldsymbol{b}, oldsymbol{c}, oldsymbol{d}$, the forces are similarly computed using two triangles formed by splitting the quad into two parts. The pressure force is then applied to each vertex proportionally:
egin{align}
\boldsymbol{p}_i &= p \cdot (\frac{(\boldsymbol{b} - \boldsymbol{a}) \times (\boldsymbol{c} - \boldsymbol{a})}{6} + \frac{(\boldsymbol{c} - \boldsymbol{a}) \times (\boldsymbol{d} - \boldsymbol{a})}{6}),
\end{align}
where $p$ is the applied pressure.
Constraint and Mapping
The force field does not directly handle constraints or mappings but instead contributes to the internal forces. However, it can interact with other components that impose constraints on the mesh topology, ensuring consistent application of pressure within those constraints.
Numerical Methods and Discretization
- Pressure Application: The pressure is discretely applied at each vertex of affected triangles and quads. Each triangle or quad's vertices receive a portion of the total pressure force based on their contribution to the surface area.
- Pulse Mode: If
d_pulseModeis enabled, the pressure can cyclically vary between two bounds (d_pressureLowerBoundandd_pressure). The variation is controlled byd_pressureSpeed, which specifies the rate of change in Pascal per second. This behavior is implemented within the time integration scheme. - Volume Conservation: If
d_volumeConservationModeis enabled, the pressure varies inversely with the mesh volume to maintain a constant volume, as defined byd_defaultVolume. The mesh volume $V$ is computed using tetrahedral elements formed from the triangles and quads:
egin{align}
V &= \frac{1}{6} \sum_{i=1}^N (\boldsymbol{x}{2i-1} - \boldsymbol{x}_0) \cdot ((\boldsymbol{x}{2i} - \boldsymbol{x}0) \times (\boldsymbol{x}{2i+1} - \boldsymbol{x}0)) + \frac{1}{6} \sum{j=1}^M (\boldsymbol{y}{3j-1} - \boldsymbol{y}_0) \cdot ((\boldsymbol{y}{3j} - \boldsymbol{y}0) \times (\boldsymbol{y}{3j+1} - \boldsymbol{y}_0)),
\end{align}
where $N$ and $M$ are the number of triangles and quads, respectively. The pressure is scaled as:
egin{align}
p &= p_0 \cdot \frac{V_{default}}{V},
\end{align}
where $p_0$ is the initial pressure.
- Tangent Stiffness: If
d_useTangentStiffnessis enabled, a non-symmetric stiffness matrix is used to approximate the derivative of forces with respect to displacements. This matrix is assembled by computing the derivatives of the cross-product terms in the force computation.
Role in the Global FEM Pipeline
- Assembly Phase: The
SurfacePressureForceFieldcontributes to the assembly of internal forces $\mathbf{f}_{int}$, which are then incorporated into the global system equations during the assembly phase. It also provides the tangent stiffness matrix if enabled. - Time Integration: Pressure forces contribute to the dynamic equation in both static and dynamic regimes. The pressure can be time-varying if
d_pulseModeis active, affecting the solution of the nonlinear residual $R(\mathbf{x}_{n+1})$ during time integration steps. - Nonlinear Solve: The internal force contributions are linearized during the Newton-Raphson iteration process to solve for the incremental displacement $\delta \mathbf{x}_k$. If
d_useTangentStiffnessis enabled, the Jacobian includes the tangent stiffness matrix derived from the cross-product derivatives. - Linear Solve: The assembled system of equations with internal forces and constraints (if any) are solved using iterative solvers like Conjugate Gradient or direct sparse factorizations.
Variational / Lagrangian Mechanics Framework
The SurfacePressureForceField adheres to the principles of variational mechanics by providing a force contribution that respects the weak form derived from the Lagrangian. The pressure forces are projected onto the surface normals, ensuring consistency with the underlying continuum mechanics formulation. The use of tangent stiffness matrices and volume conservation mechanisms further enhances the compatibility with the broader framework.
Summary
The SurfacePressureForceField contributes to the internal force $oldsymbol{f_{int}}$ by applying pressure in the direction of normal vectors on triangular or quadrilateral elements. It supports various modes such as pulse mode, volume conservation, and tangent stiffness matrices, making it a versatile component for simulating surface pressures within deformable models.
Data Fields
| Name | Type | Default | Help |
|---|---|---|---|
d_pressure |
Real | |
Pressure force per unit area |
d_min |
Coord | |
Lower bound of the selection box |
d_max |
Coord | |
Upper bound of the selection box |
d_triangleIndices |
VecIndex | |
Indices of affected triangles |
d_quadIndices |
VecIndex | |
Indices of affected quads |
d_pulseMode |
bool | |
Cyclic pressure application |
d_pressureLowerBound |
Real | |
Pressure lower bound force per unit area (active in pulse mode) |
d_pressureSpeed |
Real | |
Continuous pressure application in Pascal per second. Only active in pulse mode |
d_volumeConservationMode |
bool | |
Pressure variation follow the inverse of the volume variation |
d_useTangentStiffness |
bool | |
Whether (non-symmetric) stiffness matrix should be used |
d_defaultVolume |
Real | |
Default Volume |
d_mainDirection |
Deriv | |
Main direction for pressure application |
d_drawForceScale |
Real | |
DEBUG: scale used to render force vectors |
Links
| Name | Type | Help |
|---|---|---|
l_topology |
link to the topology container |
Methods
void
init
()
void
addForce
(const core::MechanicalParams * mparams, DataVecDeriv & d_f, const DataVecCoord & d_x, const DataVecDeriv & d_v)
void
addDForce
(const core::MechanicalParams * mparams, DataVecDeriv & , const DataVecDeriv & )
void
addKToMatrix
(const core::MechanicalParams * mparams, const sofa::core::behavior::MultiMatrixAccessor * matrix)
void
buildStiffnessMatrix
(core::behavior::StiffnessMatrix * matrix)
void
buildDampingMatrix
(core::behavior::DampingMatrix * )
SReal
getPotentialEnergy
(const core::MechanicalParams * , const DataVecCoord & )
void
draw
(const core::visual::VisualParams * vparams)
void
setPressure
(const Real _pressure)
Real
computeMeshVolume
(const VecDeriv & f, const VecCoord & x)
void
addTriangleSurfacePressure
(unsigned int triId, VecDeriv & , const VecCoord & , const VecDeriv & , const Real & , bool computeDerivatives)
virtual
void
addQuadSurfacePressure
(unsigned int quadId, VecDeriv & , const VecCoord & , const VecDeriv & , const Real & )
virtual
bool
isInPressuredBox
(const Coord & )
Real
computePulseModePressure
()
void
verifyDerivative
(VecDeriv & v_plus, VecDeriv & v, VecVec3DerivValues & DVval, VecVec3DerivIndices & DVind, const VecDeriv & Din)
{
"name": "SurfacePressureForceField",
"namespace": "sofa::component::mechanicalload",
"module": "Sofa.Component.MechanicalLoad",
"include": "sofa/component/mechanicalload/SurfacePressureForceField.h",
"doc": "Pressure applied on a generic surface (triangular or quadrangular).\n\nSurfacePressureForceField Class\nImplements a pressure force applied on a triangle or quad surface.\nEach surfel receives a pressure in the direction of its normal.",
"inherits": [
"ForceField"
],
"templates": [
"sofa::defaulttype::Rigid3Types",
"sofa::defaulttype::Vec3Types"
],
"data_fields": [
{
"name": "d_pressure",
"type": "Real",
"xmlname": "pressure",
"help": "Pressure force per unit area"
},
{
"name": "d_min",
"type": "Coord",
"xmlname": "min",
"help": "Lower bound of the selection box"
},
{
"name": "d_max",
"type": "Coord",
"xmlname": "max",
"help": "Upper bound of the selection box"
},
{
"name": "d_triangleIndices",
"type": "VecIndex",
"xmlname": "triangleIndices",
"help": "Indices of affected triangles"
},
{
"name": "d_quadIndices",
"type": "VecIndex",
"xmlname": "quadIndices",
"help": "Indices of affected quads"
},
{
"name": "d_pulseMode",
"type": "bool",
"xmlname": "pulseMode",
"help": "Cyclic pressure application"
},
{
"name": "d_pressureLowerBound",
"type": "Real",
"xmlname": "pressureLowerBound",
"help": "Pressure lower bound force per unit area (active in pulse mode)"
},
{
"name": "d_pressureSpeed",
"type": "Real",
"xmlname": "pressureSpeed",
"help": "Continuous pressure application in Pascal per second. Only active in pulse mode"
},
{
"name": "d_volumeConservationMode",
"type": "bool",
"xmlname": "volumeConservationMode",
"help": "Pressure variation follow the inverse of the volume variation"
},
{
"name": "d_useTangentStiffness",
"type": "bool",
"xmlname": "useTangentStiffness",
"help": "Whether (non-symmetric) stiffness matrix should be used"
},
{
"name": "d_defaultVolume",
"type": "Real",
"xmlname": "defaultVolume",
"help": "Default Volume"
},
{
"name": "d_mainDirection",
"type": "Deriv",
"xmlname": "mainDirection",
"help": "Main direction for pressure application"
},
{
"name": "d_drawForceScale",
"type": "Real",
"xmlname": "drawForceScale",
"help": "DEBUG: scale used to render force vectors"
}
],
"links": [
{
"name": "l_topology",
"target": "BaseMeshTopology",
"kind": "single",
"xmlname": "topology",
"help": "link to the topology container"
}
],
"methods": [
{
"name": "init",
"return_type": "void",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "addForce",
"return_type": "void",
"params": [
{
"name": "mparams",
"type": "const core::MechanicalParams *"
},
{
"name": "d_f",
"type": "DataVecDeriv &"
},
{
"name": "d_x",
"type": "const DataVecCoord &"
},
{
"name": "d_v",
"type": "const DataVecDeriv &"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "addDForce",
"return_type": "void",
"params": [
{
"name": "mparams",
"type": "const core::MechanicalParams *"
},
{
"name": "",
"type": "DataVecDeriv &"
},
{
"name": "",
"type": "const DataVecDeriv &"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "addKToMatrix",
"return_type": "void",
"params": [
{
"name": "mparams",
"type": "const core::MechanicalParams *"
},
{
"name": "matrix",
"type": "const sofa::core::behavior::MultiMatrixAccessor *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "buildStiffnessMatrix",
"return_type": "void",
"params": [
{
"name": "matrix",
"type": "core::behavior::StiffnessMatrix *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "buildDampingMatrix",
"return_type": "void",
"params": [
{
"name": "",
"type": "core::behavior::DampingMatrix *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "getPotentialEnergy",
"return_type": "SReal",
"params": [
{
"name": "",
"type": "const core::MechanicalParams *"
},
{
"name": "",
"type": "const DataVecCoord &"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "draw",
"return_type": "void",
"params": [
{
"name": "vparams",
"type": "const core::visual::VisualParams *"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "setPressure",
"return_type": "void",
"params": [
{
"name": "_pressure",
"type": "const Real"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "public"
},
{
"name": "computeMeshVolume",
"return_type": "Real",
"params": [
{
"name": "f",
"type": "const VecDeriv &"
},
{
"name": "x",
"type": "const VecCoord &"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "addTriangleSurfacePressure",
"return_type": "void",
"params": [
{
"name": "triId",
"type": "unsigned int"
},
{
"name": "",
"type": "VecDeriv &"
},
{
"name": "",
"type": "const VecCoord &"
},
{
"name": "",
"type": "const VecDeriv &"
},
{
"name": "",
"type": "const Real &"
},
{
"name": "computeDerivatives",
"type": "bool"
}
],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "addQuadSurfacePressure",
"return_type": "void",
"params": [
{
"name": "quadId",
"type": "unsigned int"
},
{
"name": "",
"type": "VecDeriv &"
},
{
"name": "",
"type": "const VecCoord &"
},
{
"name": "",
"type": "const VecDeriv &"
},
{
"name": "",
"type": "const Real &"
}
],
"is_virtual": true,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "isInPressuredBox",
"return_type": "bool",
"params": [
{
"name": "",
"type": "const Coord &"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "computePulseModePressure",
"return_type": "Real",
"params": [],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
},
{
"name": "verifyDerivative",
"return_type": "void",
"params": [
{
"name": "v_plus",
"type": "VecDeriv &"
},
{
"name": "v",
"type": "VecDeriv &"
},
{
"name": "DVval",
"type": "VecVec3DerivValues &"
},
{
"name": "DVind",
"type": "VecVec3DerivIndices &"
},
{
"name": "Din",
"type": "const VecDeriv &"
}
],
"is_virtual": false,
"is_pure_virtual": false,
"is_static": false,
"access": "protected"
}
],
"description": "The `SurfacePressureForceField` is a SOFA component that applies pressure forces to a surface composed of triangles or quads, making it suitable for simulating fluid-solid interactions and other scenarios where surface pressures need to be applied in the direction of the normal vectors. This ForceField inherits from `core::behavior::ForceField`, enabling it to integrate into the mechanical simulation loop.\n\n**Interactions with Other Components:**\n- **BaseMeshTopology**: It links to a topology container (`topology`) that provides information about the mesh's triangles and quads. The component can access this data to apply pressure forces on specific elements of the surface. \n\n**Data Fields:***\n- `d_pressure`: Specifies the magnitude of pressure force per unit area.\n- `d_min`, `d_max`: Define a bounding box for selecting affected surfel (surface element) areas.\n- `d_triangleIndices` and `d_quadIndices`: Indices specifying which triangles or quads are affected by the pressure forces.\n- `d_pulseMode`: Enables cyclic application of pressure, toggling between increasing and decreasing modes.\n- `d_pressureLowerBound`, `d_pressureSpeed`: Configure pulse mode parameters for continuous pressure variation over time.\n- `d_volumeConservationMode` and `d_useTangentStiffness`: Control volume conservation during pressure changes and specify whether to use a non-symmetric stiffness matrix, respectively. \n- `d_defaultVolume` and `d_mainDirection`: Specify default volume (for volume-conserving modes) and main direction for applying the pressure force.\n\n**Practical Usage:*\nThe component is commonly used in simulations where fluid forces or other pressures need to be applied on surfaces. For example, simulating blood flow over vessel walls or air resistance against solid objects can benefit from this ForceField. Users should set `d_pressure` and optionally use `d_pulseMode`, `d_pressureLowerBound`, and `d_pressureSpeed` for cyclic pressure effects. The pressure is applied in the direction of surface normals, affecting all vertices within specified triangles and quads.",
"maths": "### Governing Equations and Operators\n\nThe `SurfacePressureForceField` in the SOFA framework implements a pressure force field that is applied to surfaces composed of triangular or quadrilateral elements. This force field contributes primarily to the internal forces, denoted as $\\mathbf{f}_{int}$, which are integrated into the global system equations.\n\n#### Internal Forces ($\boldsymbol{f_{int}}$)\n\nThe pressure force is applied in the direction of the normal vector for each surfel (surface element). The pressure force per unit area is defined by the parameter `d_pressure` and can be cyclically varied if `d_pulseMode` is enabled.\n\nFor a triangle with vertices $\boldsymbol{a}$, $\boldsymbol{b}$, and $\boldsymbol{c}$, the normal vector $\boldsymbol{n}_i$ for each vertex $i \neq 0$ (assuming $i = 1, 2$) is given by:\n\n\begin{align*}\n\\boldsymbol{n}_i &= \\frac{(\\boldsymbol{b} - \\boldsymbol{a}) \\times (\\boldsymbol{c} - \\boldsymbol{a})}{6}\n\\end{align*}\n\nThe pressure force $\boldsymbol{p}$ for each vertex is then computed as:\n\n\begin{align*}\n\\boldsymbol{p}_i &= p \\cdot \\boldsymbol{n}_i,\n\\end{align*}\n\nwhere $p$ is the applied pressure. If `d_mainDirection` is set, the force $\boldsymbol{p}$ is projected onto the main direction vector $\boldsymbol{m}$:\n\n\begin{align*}\n\\boldsymbol{p}_i &= p \\cdot (|\\boldsymbol{n}_i \\\\cdot \\boldsymbol{m}|) \\cdot \\boldsymbol{n}_i,\n\\end{align*}\n\nwhere $|\\boldsymbol{n}_i \\\\cdot \\boldsymbol{m}|$ is the absolute value of the dot product between $\boldsymbol{n}_i$ and $\boldsymbol{m}$.\n\nFor a quadrilateral with vertices $\boldsymbol{a}, \boldsymbol{b}, \boldsymbol{c}, \boldsymbol{d}$, the forces are similarly computed using two triangles formed by splitting the quad into two parts. The pressure force is then applied to each vertex proportionally:\n\n\begin{align*}\n\\boldsymbol{p}_i &= p \\cdot (\\frac{(\\boldsymbol{b} - \\\\boldsymbol{a}) \\\\times (\\\\boldsymbol{c} - \\\\boldsymbol{a})}{6} + \\frac{(\\boldsymbol{c} - \\\\boldsymbol{a}) \\\\times (\\\\boldsymbol{d} - \\\\boldsymbol{a})}{6}),\n\\end{align*}\n\nwhere $p$ is the applied pressure.\n\n#### Constraint and Mapping\n\nThe force field does not directly handle constraints or mappings but instead contributes to the internal forces. However, it can interact with other components that impose constraints on the mesh topology, ensuring consistent application of pressure within those constraints.\n\n#### Numerical Methods and Discretization\n\n- **Pressure Application:** The pressure is discretely applied at each vertex of affected triangles and quads. Each triangle or quad's vertices receive a portion of the total pressure force based on their contribution to the surface area.\n- **Pulse Mode:** If `d_pulseMode` is enabled, the pressure can cyclically vary between two bounds (`d_pressureLowerBound` and `d_pressure`). The variation is controlled by `d_pressureSpeed`, which specifies the rate of change in Pascal per second. This behavior is implemented within the time integration scheme.\n- **Volume Conservation:** If `d_volumeConservationMode` is enabled, the pressure varies inversely with the mesh volume to maintain a constant volume, as defined by `d_defaultVolume`. The mesh volume $V$ is computed using tetrahedral elements formed from the triangles and quads:\n\n\begin{align*}\nV &= \\frac{1}{6} \\sum_{i=1}^N (\\boldsymbol{x}_{2i-1} - \\\\boldsymbol{x}_0) \\\\cdot ((\\\\boldsymbol{x}_{2i} - \\\\boldsymbol{x}_0) \\\\times (\\\\boldsymbol{x}_{2i+1} - \\\\boldsymbol{x}_0)) + \\frac{1}{6} \\sum_{j=1}^M (\\boldsymbol{y}_{3j-1} - \\\\boldsymbol{y}_0) \\\\cdot ((\\\\boldsymbol{y}_{3j} - \\\\boldsymbol{y}_0) \\\\times (\\\\boldsymbol{y}_{3j+1} - \\\\boldsymbol{y}_0)),\n\\end{align*}\n\nwhere $N$ and $M$ are the number of triangles and quads, respectively. The pressure is scaled as:\n\n\begin{align*}\np &= p_0 \\cdot \\frac{V_{default}}{V},\n\\end{align*}\n\nwhere $p_0$ is the initial pressure.\n\n- **Tangent Stiffness:** If `d_useTangentStiffness` is enabled, a non-symmetric stiffness matrix is used to approximate the derivative of forces with respect to displacements. This matrix is assembled by computing the derivatives of the cross-product terms in the force computation.\n\n### Role in the Global FEM Pipeline\n\n- **Assembly Phase:** The `SurfacePressureForceField` contributes to the assembly of internal forces $\\mathbf{f}_{int}$, which are then incorporated into the global system equations during the assembly phase. It also provides the tangent stiffness matrix if enabled.\n- **Time Integration:** Pressure forces contribute to the dynamic equation in both static and dynamic regimes. The pressure can be time-varying if `d_pulseMode` is active, affecting the solution of the nonlinear residual $R(\\mathbf{x}_{n+1})$ during time integration steps.\n- **Nonlinear Solve:** The internal force contributions are linearized during the Newton-Raphson iteration process to solve for the incremental displacement $\\delta \\mathbf{x}_k$. If `d_useTangentStiffness` is enabled, the Jacobian includes the tangent stiffness matrix derived from the cross-product derivatives.\n- **Linear Solve:** The assembled system of equations with internal forces and constraints (if any) are solved using iterative solvers like Conjugate Gradient or direct sparse factorizations.\n\n### Variational / Lagrangian Mechanics Framework\n\nThe `SurfacePressureForceField` adheres to the principles of variational mechanics by providing a force contribution that respects the weak form derived from the Lagrangian. The pressure forces are projected onto the surface normals, ensuring consistency with the underlying continuum mechanics formulation. The use of tangent stiffness matrices and volume conservation mechanisms further enhances the compatibility with the broader framework.\n\n### Summary\nThe `SurfacePressureForceField` contributes to the internal force $\boldsymbol{f_{int}}$ by applying pressure in the direction of normal vectors on triangular or quadrilateral elements. It supports various modes such as pulse mode, volume conservation, and tangent stiffness matrices, making it a versatile component for simulating surface pressures within deformable models.",
"abstract": "The `SurfacePressureForceField` applies pressure forces to surfaces composed of triangular or quadrilateral elements in the direction of their normal vectors, supporting various modes such as pulse mode and volume conservation.",
"sheet": "# SurfacePressureForceField\n\n## Overview\n\nThe `SurfacePressureForceField` is a SOFA component that applies pressure forces to surfaces composed of triangles or quads. It inherits from the `core::behavior::ForceField` class and interacts with other components like `BaseMeshTopology`. The component supports various modes such as pulse mode, volume conservation, and tangent stiffness matrices.\n\n## Mathematical Model\n\nThe `SurfacePressureForceField` computes internal forces based on surface normals for triangular or quadrilateral elements. For a triangle with vertices $\\boldsymbol{a}$, $\\boldsymbol{b}$, and $\\boldsymbol{c}$, the normal vector $\\boldsymbol{n}_i$ for each vertex is given by:\n\n\\begin{align*}\n \\boldsymbol{n}_i &= \\frac{(\\boldsymbol{b} - \\boldsymbol{a}) \\times (\\boldsymbol{c} - \\boldsymbol{a})}{6},\n\\end{align*}\n\nThe pressure force $\\boldsymbol{p}$ for each vertex is then computed as:\n\n\\begin{align*}\n \\boldsymbol{p}_i &= p \\cdot \\boldsymbol{n}_i,\n\\end{align*}\n\nwhere $p$ is the applied pressure. If `d_mainDirection` is set, the force $\\boldsymbol{p}$ is projected onto the main direction vector $\\boldsymbol{m}$:\n\n\\begin{align*}\n \\boldsymbol{p}_i &= p \\cdot (|\\boldsymbol{n}_i \\cdot \\boldsymbol{m}|) \\cdot \\boldsymbol{n}_i,\n\\end{align*}\n\nwhere $|\\boldsymbol{n}_i \\cdot \\boldsymbol{m}|$ is the absolute value of the dot product between $\\boldsymbol{n}_i$ and $\\boldsymbol{m}$.\n\nFor a quadrilateral with vertices $\\boldsymbol{a}, \\boldsymbol{b}, \\boldsymbol{c}, \\boldsymbol{d}$, the forces are similarly computed using two triangles formed by splitting the quad into two parts. The pressure force is then applied to each vertex proportionally:\n\n\\begin{align*}\n \\boldsymbol{p}_i &= p \\cdot \\left(\\frac{(\\boldsymbol{b} - \\boldsymbol{a}) \\times (\\boldsymbol{c} - \\boldsymbol{a})}{6} + \\frac{(\\boldsymbol{c} - \\boldsymbol{a}) \\times (\\boldsymbol{d} - \\boldsymbol{a})}{6}\\right),\n\\end{align*}\n\nwhere $p$ is the applied pressure.\n\n## Parameters and Data\n\nThe `SurfacePressureForceField` has several parameters that control its behavior:\n\n- **pressure**: Specifies the magnitude of pressure force per unit area (`Real`, default: 0.0).\n- **min**, **max**: Define a bounding box for selecting affected surfel areas (`Coord`).\n- **triangleIndices**, **quadIndices**: Indices specifying which triangles or quads are affected by the pressure forces (`VecIndex`).\n- **pulseMode**: Enables cyclic application of pressure, toggling between increasing and decreasing modes (`bool`, default: false).\n- **pressureLowerBound**, **pressureSpeed**: Configure pulse mode parameters for continuous pressure variation over time (`Real`).\n- **volumeConservationMode**: Controls volume conservation during pressure changes (`bool`, default: false).\n- **useTangentStiffness**: Specifies whether to use a non-symmetric stiffness matrix (`bool`, default: false).\n- **defaultVolume**: Specifies the default volume for volume-conserving modes (`Real`).\n- **mainDirection**: Specifies the main direction for applying the pressure force (`Deriv`).\n- **drawForceScale**: DEBUG: scale used to render force vectors (`Real`, default: 1.0).\n\n## Dependencies and Connections\n\nThe `SurfacePressureForceField` requires a link to a topology container (`BaseMeshTopology`) that provides information about the mesh's triangles and quads.\n\n## Practical Notes\n\n- The pressure is applied in the direction of surface normals, affecting all vertices within specified triangles and quads.\n- If `d_pulseMode` is enabled, the pressure can cyclically vary between two bounds (`d_pressureLowerBound` and `d_pressure`).\n- Volume conservation mode ensures that the pressure varies inversely with the mesh volume to maintain a constant volume."
}