Scripted transient thermal: how to extract end-of-step temperatures? (ThermoSensorExtractor.Results is None)
-
I’m running everything via Python scripts (no UI). To reproduce liver motion, I move the organ geometry at each time step in both the EMLF simulation (to generate Phantom_Liver_i / Overall Field) and the transient thermal simulation. My goal is to use the final temperature at step i as the initial condition of step i+1—but I can’t retrieve temperatures programmatically.
Current behavior (brief):
Thermal sim runs, voxels created, .sab saved.
I attach a thermal.TransientFieldSensorSettings() (Temperature) to Overall Field, enable available store/write flags, and set snapshot times (0–5 s) on both Setup and sensor.
In simulation.Results(), I see ThermoSensorExtractor, but after Update() its Results is always None.
Log excerpt:
[DBG] ThermoExtractor ...
[DBG] Overall Field.Results type=<class 'NoneType'>I tried various other methods to obtain the temperature, but they all failed.
Questions:
In the current API, what is the supported script-only method to obtain temperature values (per entity or field) at the last snapshot of a transient run?
Which exact settings/flags are required so that ThermoSensorExtractor (or an alternative extractor) returns non-None results?
Is there a minimal example showing how to:
attach the correct temperature sensor(s) to the right component,
trigger result generation,
and export the final-step temperatures for reuse as the next step’s initial condition?
I can share the script, logs, and .sab files if helpful.
Thank you!Best regards
-
This is a simplified example (partly generated using the "To Python" action in the context menu). The example does the following
- creates an EM simulation as heat source
- creates a thermal simulation
- creates a "continue" simulation using the thermal distribution from the first simulation
- extracts the temperature field
from pathlib import Path import numpy as np import s4l_v1.document as document import s4l_v1.materials.database as database import s4l_v1.model as model import s4l_v1.simulation.emfdtd as emfdtd import s4l_v1.simulation.thermal as thermal import s4l_v1.units as units from s4l_v1 import Unit def create_emfdtd_simulation(): simulation = emfdtd.Simulation() entity__lines1 = model.AllEntities()["Edge Source"] entity__sphere1 = model.AllEntities()["Sphere 1"] material_settings = simulation.AddMaterialSettings([entity__sphere1]) simulation.LinkMaterialWithDatabase(material_settings, database["IT'IS LF 5.0"]["Liver"]) edge_source_settings = emfdtd.EdgeSourceSettings() simulation.Add(edge_source_settings, [entity__lines1]) edge_sensor_settings = emfdtd.EdgeSensorSettings() simulation.Add(edge_sensor_settings, [entity__lines1]) automatic_grid_settings = [x for x in simulation.AllSettings if isinstance(x, emfdtd.AutomaticGridSettings) and x.Name == "Automatic"][0] simulation.Add(automatic_grid_settings, [entity__lines1, entity__sphere1]) automatic_voxeler_settings = [x for x in simulation.AllSettings if isinstance(x, emfdtd.AutomaticVoxelerSettings) and x.Name == "Automatic Voxeler Settings"][0] simulation.Add(automatic_voxeler_settings, [entity__lines1, entity__sphere1]) simulation.UpdateAllMaterials() simulation.UpdateGrid() return simulation def create_thermal_transient(em_overall_field): simulation = thermal.TransientSimulation() entity__sphere1 = model.AllEntities()["Sphere 1"] material_settings = simulation.AddMaterialSettings([entity__sphere1]) simulation.LinkMaterialWithDatabase(material_settings, database["IT'IS LF 5.0"]["Liver"]) initial_condition_settings = thermal.InitialConditionSettings() initial_condition_settings.InitialTemperature = 37.0, Unit("C") simulation.Add(initial_condition_settings, [entity__sphere1]) transient_heat_source_settings = simulation.AddHeatSourceSettings([em_overall_field]) automatic_grid_settings = [x for x in simulation.AllSettings if isinstance(x, thermal.AutomaticGridSettings) and x.Name == "Automatic"][0] simulation.Add(automatic_grid_settings, [entity__sphere1]) automatic_voxeler_settings = [x for x in simulation.AllSettings if isinstance(x, thermal.AutomaticVoxelerSettings) and x.Name == "Automatic Voxeler Settings"][0] simulation.Add(automatic_voxeler_settings, [entity__sphere1]) simulation.UpdateAllMaterials() simulation.UpdateGrid() return simulation if __name__ == "__main__": # create dummy model line = model.CreatePolyLine([model.Vec3(0,0,20), model.Vec3(5,0,20)]) line.Name = "Edge Source" sphere = model.CreateSolidSphere(model.Vec3(0,0,0), radius=15) sphere.Name = "Sphere 1" sphere.MaterialName = "Liver" # create heat source em_sim = create_emfdtd_simulation() em_sim.Name = "EM Heat Source" document.AllSimulations.Add( em_sim ) # setup initial thermal simulation th_sim = create_thermal_transient(em_sim.AllComponents["Overall Field"]) th_sim.Name = "T Initial Simulation" document.AllSimulations.Add( th_sim ) # setup simulation using result from previous simulation th_continue = th_sim.CloneWithDiscretization() th_continue.Name = "T Continue Simulation" init_cond_settings = th_continue.GlobalInitialConditionSettings init_cond_settings.InitializationOptions = init_cond_settings.InitializationOptions.enum.ContinueSimulation init_cond_settings.InputSensor = "Overall Field" init_cond_settings.InputSimulation = th_sim.Name document.AllSimulations.Add( th_continue ) # run simulations project_file_path = Path.home() / "t_continue.smash" em_sim.CreateVoxels(project_file_path) em_sim.RunSimulation() th_sim.CreateVoxels(project_file_path) th_sim.RunSimulation() th_continue.CreateVoxels(project_file_path) th_continue.RunSimulation() # extract some results th_continue_extractor = th_continue.Results() th_sensor_extractor = th_continue_extractor["Overall Field"] th_sensor_extractor.Outputs["T(x,y,z,t)"].Update() field = th_sensor_extractor.Outputs["T(x,y,z,t)"].Data print(field)