@@ -67,13 +67,15 @@ print(projects)
6767
6868### Running a Simulation
6969
70- The following example runs a non-interactive distributed simulation using a
71- Spring-Mass-Damper project that has already been configured on the STC platform.
70+ The following example runs a ** single non-interactive** distributed simulation
71+ using a Spring-Mass-Damper project that has already been configured on the STC
72+ platform. A simulation is non-interactive when the simulator runs to completion
73+ without user intervention (create → run → finish).
7274
7375``` py
7476import time
7577
76- from pystclient.clients import PyStclient, SimulationResults
78+ from pystclient.clients import PyStclient
7779from pystclient.models import (
7880 LoggingConfiguration,
7981 ModelParameters,
@@ -119,80 +121,88 @@ client.project.update_log_config(
119121 project.id, LoggingConfiguration(post_plotting = True )
120122)
121123
122- # 5 — Create a simulator and wait until it is ready
123- statuses, ready_future = client.simulator.create(
124+ # 5 — Create a non-interactive distributed simulator and wait until it is ready
125+ statuses, future = client.simulator.create(
124126 SimulationConfig(
125127 project_id = project.id,
126128 parameter_set_names = [" Config 1" ],
127129 type = SimulationType.DISTRIBUTED ,
128130 )
129131)
130132simulator_id = statuses[0 ].id
131- assert ready_future.result(600 ), " Simulator did not become ready in time!"
132-
133- # 6 — Start the simulation with recording enabled
134- client.simulator.start(simulator_id, record = True )
133+ assert future.result(600 ), " Simulator did not become ready in time!"
135134
136- # 7 — Poll until the simulation finishes
135+ # 6 — Poll until the simulation finishes
137136while not client.simulator.finished(simulator_id):
138137 s = client.simulator.status(simulator_id)
139138 print (f " simulation_time= { s.simulation_time} end_time= { s.end_time} " )
140- time.sleep(2 )
139+ time.sleep(1 )
141140
142- # 8 — End the simulation and collect results
143- results: SimulationResults | None = client.simulator.end_simulation(simulator_id).result(120 )
144- assert results is not None , " No results returned!"
145- print (f " Results available — { results.measurement_size()} measurement(s). " )
141+ print (" Simulation finished." )
146142```
147143
148144### Fetching and Displaying Results
149145
150- Once a simulation has completed and a ` SimulationResults ` object is available
151- (see the previous example), you can iterate over the time-series data and
152- plot it with [ matplotlib] ( https://matplotlib.org/ ) :
146+ Once a simulation has completed, you can retrieve it from the list of
147+ completed simulations and query time-series data for plotting with
148+ [ matplotlib] ( https://matplotlib.org/ ) :
153149
154150``` py
151+ import time
152+
155153import matplotlib.pyplot as plt
156154
157- from pystclient.models import QueryVariable
155+ from pystclient.models import MeasurementQuery, QueryVariable, SimulationInfo
156+ from pystclient.types import FmuCausalityType
158157from pystclient.utils.time import convert_to_timestamp
159158
160- # Reset the results iterator to start from the beginning
161- results.reset()
159+ # Wait for the simulation to appear in the completed list
160+ completed_simulations: list[SimulationInfo] = []
162161
163- # Iterate through all time windows and collect displacement data
162+ while len (completed_simulations) != 1 :
163+ completed_simulations = client.project.completed_simulations(
164+ project_id = project.id,
165+ simulator_ids = [simulator_id],
166+ limit = 10 ,
167+ )
168+ time.sleep(5 )
169+
170+ sim = completed_simulations[0 ]
171+ print (f " Simulation { sim.id} name= { sim.name} param_set= { sim.parameter_set_name} " )
172+
173+ # Retrieve measurements and query specific variable data
174+ sim_measurements = client.measurement.measurements(project.id, sim.id)
175+ assert sim_measurements, " No measurements found!"
176+
177+ measurement = sim_measurements[0 ]
178+ q = MeasurementQuery(
179+ variables = [
180+ QueryVariable(
181+ instance_name = " Spring1" ,
182+ name = " dis_yx" ,
183+ causality = FmuCausalityType.INPUT ,
184+ )
185+ ],
186+ time_from = 0 ,
187+ time_to = 10 ,
188+ )
189+ results = client.measurement.query(measurement.id, q)
190+
191+ # Plot the displacement data
164192fig, ax = plt.subplots(figsize = (10 , 5 ))
165193
166- for query_result in results:
167- for result in query_result:
168- if result.signal == " dis_yx" :
169- x = convert_to_timestamp(result.x)
170- ax.plot(x, result.y, label = f " { result.module} — { result.signal} " )
194+ for result in results:
195+ x = convert_to_timestamp(result.x)
196+ ax.plot(x, result.y, label = f " { sim.parameter_set_name} " )
171197
172198ax.set_xlabel(" Time [s]" )
173199ax.set_ylabel(" Displacement [m]" )
174- ax.set_title(" Spring-Mass-Damper — Displacement (dis_yx)" )
200+ ax.set_title(" Spring-Mass-Damper — Spring Displacement (dis_yx)" )
175201ax.legend()
176202plt.tight_layout()
177203plt.show()
178204```
179205
180- You can also narrow the query to specific variables using ` query_variables ` :
181-
182- ``` py
183- results.reset(
184- query_variables = [
185- QueryVariable(instance_name = " Mass1" , name = " dis_yx" , causality = " output" ),
186- ]
187- )
188-
189- for query_result in results:
190- for result in query_result:
191- print (f " { result.module} . { result.signal} : { len (result.y)} data points " )
192- ```
193-
194- > ** Tip** : Use ` results.step(timedelta(minutes=5)) ` to change the size of
195- > each time window when paging through results.
196206
197207> ** See also** : For complete, runnable notebooks check the
198208> [ ` examples/ ` ] ( https://github.com/dnv-opensource/pystclient/tree/main/examples ) directory.
0 commit comments