Tutorial: thermal bar
Steady-state heat conduction in a 1 m bar with the left end held at 100 °C and the right end at 0 °C. The analytical solution is a straight line — T(x) = 100·(1−x) — which makes this the perfect correctness check. All numbers below are from a real run.
1. Generate the mesh
Thermal cases have two special rules (the tools' docstrings and the setup_thermal_analysis prompt both encode them):
- use generic simplex elements (
Element2D3N,triangles: true) — the convection-diffusion solver substitutes the physical element at import and its mesh checks reject quads; - use
ThermalFace2D2Nboundary conditions.
mdpa_create_structured_mesh({
"path": "/tmp/bar/mesh.mdpa",
"kind": "rectangle", "size": [1.0, 0.1], "divisions": [20, 2],
"element_name": "Element2D3N", "condition_name": "ThermalFace2D2N",
"triangles": true
})
→ { "num_nodes": 63, "num_elements": 80 }2. Scaffold the case
thermal_stationary defaults to steel-like properties (k = 15 W/m·K) and already fixes ThermalModelPart.left at 100 °C. It also sets element_replace_settings to LaplacianElement — without that, Kratos's "stationary" solver still behaves like one transient step.
create_project({
"directory": "/tmp/bar",
"template": "thermal_stationary",
"name": "bar"
})To change the hot-end temperature or conductivity, pass overrides: {"fixed_temperature": 350.0, "conductivity": 45.0}.
3. Fix the cold end
add_boundary_condition({
"parameters_file": "/tmp/bar/ProjectParameters.json",
"kind": "fix_temperature",
"model_part": "ThermalModelPart.right",
"value": 0.0
})4. Run
run_simulation({"case_dir": "/tmp/bar", "wait_seconds": 120})
→ { "state": "succeeded" }5. Check the profile
results_probe({"file": "/tmp/bar/vtk_output/ThermalModelPart_0_1.vtk",
"variable": "TEMPERATURE", "point": [0.5, 0.05, 0.0]})
→ { "value": 50.0 }
results_probe({"file": "...", "variable": "TEMPERATURE", "point": [0.25, 0.05, 0.0]})
→ { "value": 75.0 }Exactly linear: 50 °C at the midpoint, 75 °C at the quarter point — the FE solution reproduces the analytical profile to machine precision on this mesh. The integration test tests/test_run_integration.py::test_thermal_bar_linear_profile asserts the whole field against 100·(1−x).
6. Preview the field
With the optional viz extra installed (see Visualization), render the temperature field inline:
results_render({
"file": "/tmp/bar/vtk_output/ThermalModelPart_0_1.vtk",
"variable": "TEMPERATURE",
"camera": "xy"
})
→ { "data_range": [0.0, 100.0] } + the PNG shown inlineA clean left-to-right gradient from 100 °C to 0 °C. For the transient variant, results_animate({"files": "/tmp/bar/vtk_output"}) turns the whole time series into a GIF of the profile developing.
Variations
- Transient heating: template
thermal_transientwithend_time/time_stepoverrides; probe the same points across the VTK time series to watch the profile develop. - Heat flux instead of fixed temperature:
kind: "surface_heat_flux"on a boundary part (needs theThermalFace2D2Nconditions the mesh already has), orkind: "volume_heat_source"onThermalModelPart.domain. - Different material:
overrides: {"conductivity": 400.0, "density": 8960.0, "specific_heat": 385.0}for copper.