Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[examples] Add a thermo-elastic example #204

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions examples/thermoelasticity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Required import for python
import Sofa
import numpy as np


def main():
import SofaRuntime
import Sofa.Gui

root = Sofa.Core.Node("root")
createScene(root)
Sofa.Simulation.init(root)

Sofa.Gui.GUIManager.Init("myscene", "qglviewer")
Sofa.Gui.GUIManager.createGUI(root, __file__)
Sofa.Gui.GUIManager.SetDimension(1080, 1080)
hugtalbot marked this conversation as resolved.
Show resolved Hide resolved
Sofa.Gui.GUIManager.MainLoop(root)
Sofa.Gui.GUIManager.closeGUI()


def createScene(root):
root.gravity=[0, -9.81, 0]
root.dt=0.01

root.addObject('DefaultAnimationLoop')
root.addObject('DefaultVisualManagerLoop')
root.addObject('VisualStyle', displayFlags="hideCollisionModels showVisualModels hideForceFields showBehaviorModels")
root.addObject('RequiredPlugin', pluginName="SofaSimpleFem SofaSparseSolver SofaEngine SofaImplicitOdeSolver SofaLoader SofaOpenglVisual SofaBoundaryCondition SofaGeneralLoader SofaGeneralSimpleFem SofaGeneralEngine CImgPlugin SofaTopologyMapping")

root.addObject('RegularGridTopology', name="gridGenerator", nx="16", ny="6", nz="6", xmin="0", xmax="1", ymin="0", ymax="0.2", zmin="0", zmax="0.2")
root.addObject("OglColorMap", legendTitle="A-dimensional temperature", min=0, max=1, showLegend=True, colorScheme="Blue to Red")


tetraTopo = root.addChild('TetraTopology')
tetraTopo.addObject("TetrahedronSetTopologyContainer", name="tetContainer", tags="3dgeometry")
tetraTopo.addObject("TetrahedronSetTopologyModifier", name="Modifier")
tetraTopo.addObject("Hexa2TetraTopologicalMapping", input="@../gridGenerator", output="@tetContainer")
tetraTopo.addObject("MechanicalObject", name="tetraO", position="@../gridGenerator.position", tags="3dgeometry")
tetraTopo.addObject("BoxROI", name="BoundaryCondition", box="-0.01 -0.01 -0.01 0.01 0.21 0.21")


meca = tetraTopo.addChild("Mechanics")
meca.addObject("EulerImplicitSolver", name="Euler Impl IntegrationScheme")
meca.addObject("SparseLDLSolver", name="LDL LinearSolver", template="CompressedRowSparseMatrixMat3x3d")
meca.addObject("TetrahedronSetTopologyContainer", name="tetContainer", src="@../tetContainer")
meca.addObject("TetrahedronSetGeometryAlgorithms", name="tetGeometry", template="Vec3d")
meca.addObject("MechanicalObject", name="MO", position="@../tetraO.position")
Copy link
Contributor

@damienmarchal damienmarchal Oct 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

related to .linkpath and this (PR #265)

meca.addObject("MeshMatrixMass", name="Mass", massDensity="100")
meca.addObject("FixedConstraint", name="FixedBoundaryCondition", indices="@../BoundaryCondition.indices")

#initialization of the vector multiplying the local Young's modulus (need to activate updateStiffness=True)
initVector = np.full((1, 576), 1.0)
damienmarchal marked this conversation as resolved.
Show resolved Hide resolved
meca.addObject("TetrahedronFEMForceField", name="LinearElasticity", youngModulus="3e5", poissonRatio="0.4", computeVonMisesStress="1", showVonMisesStressPerElement=True, localStiffnessFactor=initVector, updateStiffness=True)
damienmarchal marked this conversation as resolved.
Show resolved Hide resolved


thermo = tetraTopo.addChild("Thermodynamics")
thermo.addObject("EulerImplicitSolver", name="Euler Impl IntegrationScheme", firstOrder="1")
thermo.addObject("CGLinearSolver", name="Conjugate Gradient", iterations="1000", tolerance="1.0e-10", threshold="1.0e-30")
thermo.addObject("TetrahedronSetTopologyContainer", name="tetContainer", src="@../tetContainer")
thermo.addObject("TetrahedronSetGeometryAlgorithms", name="tetGeometry", template="Vec3d")
thermo.addObject("MechanicalObject", name="Temperatures", template="Vec1d", size="576", showObject=True)
thermo.addObject("MeshMatrixMass", name="Conductivity", massDensity="1.0")
thermo.addObject("FixedConstraint", name="Heating", indices="495")
thermo.addObject("TetrahedronDiffusionFEMForceField", name="DiffusionForceField", template="Vec1d", constantDiffusionCoefficient="0.05", tagMechanics="3dgeometry", mstate="@Temperatures")

thermoVisu = thermo.addChild("Visu")
thermoVisu.addObject("TextureInterpolation", template="Vec1d", name="EngineInterpolation", input_states="@../Temperatures.position", input_coordinates="@../../Mechanics/MO.position", min_value="0.", max_value="1.", manual_scale="1" , drawPotentiels="0", showIndicesScale="5e-05")
thermoVisu.addObject("OglModel", template="Vec3d", name="oglPotentiel", handleDynamicTopology="0", texcoords="@EngineInterpolation.output_coordinates" ,texturename="textures/heatColor.bmp", scale3d="1 1 1", material="Default Diffuse 1 1 1 1 0.5 Ambient 1 1 1 1 0.3 Specular 0 0.5 0.5 0.5 1 Emissive 0 0.5 0.5 0.5 1 Shininess 0 45 No texture linked to the material No bump texture linked to the material ")
thermoVisu.addObject("IdentityMapping", input="@../../Mechanics/MO", output="@oglPotentiel")

# Add the controller
root.addObject(ThermoMecaController(name = "MultiPhysicsController", ThermalObject=thermo.Temperatures, MechanicalForceField=meca.LinearElasticity))

return root


class ThermoMecaController(Sofa.Core.Controller):
def __init__(self, *args, **kwargs):
# These are needed (and the normal way to override from a python class)
Sofa.Core.Controller.__init__(self, *args, **kwargs)
# Recover the pointers to the thermal object and the ForceField responsible of the linear elastic constitutive law
self.ThermalObject = kwargs.get("ThermalObject")
self.MechanicalForceField = kwargs.get("MechanicalForceField")

def onAnimateEndEvent(self, event):
time = self.getContext().getTime()

self.temperatures = self.ThermalObject.position.array()

if time > 0.5 :

# Make the Young's modulus related to the temperature: E = E_init / (1 + 50*Temperature)
with self.MechanicalForceField.localStiffnessFactor.writeableArray() as wa:
for i in range(576) :
damienmarchal marked this conversation as resolved.
Show resolved Hide resolved
wa[i] = 1.0 / ( 1.+ 50.*self.temperatures[i][0] )

#Enforce temperature of the node 495 (extremity of the bar)
# Heating phase until t = 4
if time < 4.0 :
with self.ThermalObject.position.writeableArray() as wt:
wt[495][0] = 1.0
# Cooling down phase when t > 4
else :
with self.ThermalObject.position.writeableArray() as wt:
wt[495][0] = 0.0


# Function used only if this script is called from a python environment
if __name__ == '__main__':
main()