How To: Simulation Results & Queries¶
Create a
QueryResultobject that specifies the domain to be sampled. It takes a singlecomponentor anassemblyas input.assembly = [component_1, component_2] results = QueryResult(component_1) # sample only the defined component results = QueryResult(assembly) # sample on the full assembly
Specify a query class and type that defines what quantity you are querying. The query classes and types available are as follows :
Global Query is for querying quantities defined for the entire domain or structure. The available
GlobalQueryTypes areCompliance,ReactionForce,TotalReactonForce,TotalReactionMoment,TotalAppliedForce, andTotalAppliedMomentfor linear elasticity simulations,Frequencyfor modal simulations,CriticalLoadFactorfor linear buckling simulations, andThermalCompliancefor static thermal simulations.TotalReactionForceis a tuple of dimension 3 containing the total reaction force[x-force, y-force, z-force]
ReactionForceis a tuple of dimension 3 for each restrained boundary, in the order the boundary conditions were added to theLinearElasticScenarioDescriptor.[x-force, y-force, z-force]
TotalReactionMomentis 3 tuples of dimension 3, representing the moments about the origin generated by reaction forces. Using [r1, r2, r3] to represent the vector from the origin to the reaction force, and using [Fx, Fy, Fz] to represent the reaction force, the moments are:[0, r2 * Fx, r3 * Fx] [r1 * Fy, 0, r3 * Fy] [r1 * Fz, r2 * Fz, 0]
TotalAppliedForceis a tuple of dimension 3, representing the total applied load.[Fx, Fy, Fz]
TotalAppliedMomentis 3 tuples of dimension 3, representing the moments about the origin generated by the applied loads. Using [r1, r2, r3] to represent the vector from the origin to the applied load, and using [Fx, Fy, Fz] to represent the applied load, the moments are:[0, r2 * Fx, r3 * Fx] [r1 * Fy, 0, r3 * Fy] [r1 * Fz, r2 * Fz, 0]
# GlobalQuery example # Create a GlobalQuery to query the first mode results = QueryResult(assembly) frequency_query = GlobalQuery(GlobalQueryType.Frequency, DiscreteIndex(0)) # Sample the simulation for the specified query freq_1 = simulator.sample(mode1_query, results) print(freq_1.get(0,0)) # Print out the first mode in Hz # Example use to get the first 10 modes # Note, the simulator would need this: # modal_scenario.modal_metadata.desired_eigenvalues = 10 for i in range(10): # Create the query for the current mode query = GlobalQuery(GlobalQueryType.Frequency, DiscreteIndex(i)) # Sample the query using the simulator r = simulator.sample(query, results) # Append the value obtained from result.get(0, 0) to a list values.append(r.get(0, 0)) print(values) # list of first 10 modes in Hz
Field Query is for querying field quantities defined at any point in the domain. The available field quantities depend on the physics type.
For Stress Simulation, the following
FieldTypeinputs are availableDisplacementtuple of dimension 3 for each point[x-displacement, y-displacement, z-displacement]
StrainandStressare each a tuple of dimension 6 for each point[stress_xx, stress_yy, stress_zz, stress_yz, stress_xz, stress_xy] [strain_xx, strain_yy, strain_zz, strain_yz, strain_xz, strain_xy]
TopologicalSensitivity,StrainEnergyDensity, andVonMisesStressare each a tuple of dimension 1 for each point
For Modal Simulation and Linear Buckling Simulation, the only
FieldTypeavailable isDisplacement, which corresponds to the mode shape information and requires an index for the specified mode.# Create a field query for the displacement/mode shape of mode 1 mode_num = 0 # first mode modal_field_query = FieldQuery(f=Field.Displacement, scheme=DiscreteIndex(mode_num))
For Thermal Simulation, the available
FieldTypes areTemperaturewhich is a tuple of dimension 1HeatFluxwhich is a tuple of dimension 3
Field Query Interface usage
# FieldQuery example # Create a FieldQuery to query displacement results = QueryResult(assembly) displacement_query = FieldQuery(f=Field.Displacement) # Create a FieldQuery with optional input to query the y-component y_displacement_query = FieldQuery(f=Field.Displacement, component=1) # FieldQuery with optional input to query the norm of displacement displacement_magnitude_query = FieldQuery(f=Field.Displacement, norm=True) # Sample the simulation with the given query to create a VectorArray # * more info on VectorArrays are provided in the subsequent section * displacement_VectorArray1 = simulator.sample(displacement_query, results) displacement_VectorArray2 = simulator.sample(y_displacement_query, results) displacement_VectorArray3 = simulator.sample(displacement_magnitude_query, results) displacement1 = displacement_VectorArray1.get(i, j); # jth component of the displacement (0 = X, 1 = Y, or 2 = Z) at the ith sampling point displacement2 = displacement_VectorArray2.get(1, 0); # y-displacement value at the second sampling point displacement3 = displacement_VectorArray3.get(1, 0); # displacement magnitude at the second sampling point
Statistical queries allow querying for the maximum, minimum or mean of any field quantity. The following example queries for the maximum von Mises stress.
# Create a StatisticalQuery to query for the maximum von Mises stress results = QueryResult(assembly) max_von_mises_query = StatisticalQuery(f=Field.VonMisesStress, s=StatisticalQueryType.Maximum) max_von_mises = simulator.sample(max_von_mises_query, results).get(0, 0)
Sample and Export Results¶
Sampling results in-memory
Methods to sample results of the simulation and store/print
VectorArrayresults from the queries created above.# Query results results = QueryResult(assembly) stress_query = FieldQuery(f=Field.Stress) # a field is needed to create a field query stress_VectorArray = simulator.sample(stress_query, results)
This sampling is stored in a
VectorArrayof sizen_tuplebydimension,n_tupleis the number of points sampled in the component/assembly and dimension depends on the query type. For example,FieldQuery(Field.Displacement)has a dimension of 3 for each displacement component, thusVectorArray.get(i, 2)would get the z-displacement of pointi.# Get the number of tuples (vectors) in the VectorArray (one per point results are sampled at) n_tuples = stress_VectorArray.n_tuples() # Get the dimension of each vector - in this case 6, one value for each stress component dimension = stress_VectorArray.dimension() stress_xx = stress_VectorArray.get(i, 0); # stress_xx at i-th sample point stress_yy = stress_VectorArray.get(i, 1); # stress_yy at i-th sample point stress_ij = stress_VectorArray.get(i, j); # jth stress component (0, 1, 2, 3, 4, or 5) of the ith tuple
Export results to a file: Once the query is created,
resultscan be used to write a.vtufile which contains all solution fields viaresults.writeVTKwhich has two inputs:file name
"*.vtu"UnitSystemis an attribute in the*.vtu( Note that this argument is just metadata in the*.vtufile. The result magnitudes are in the unit of the scenario regardless of the unit system specified. )
# Write results to a file (unit system is saved as a metadata in the vtu file) results = QueryResult(assembly) stress_query = FieldQuery(Field.VonMisesStress) simulator.sample(stress_query, results) # Write results to a file (unit system is saved as a metadata in the vtu file) results.writeVTK("cantilever_beam_results.vtu", UnitSystem.MeterKilogramSecond)
Sampling on Custom Geometries¶
Another important functionality is the ability to specify a point set to sample on. This can be done by creating a new
sampling_componentconsisting of vertices at the desired sampling locations. Note that thesampling_componentis not to be included in the assembly that is being simulated.# Create an empty MeshModel to store vertices for desired sampling locations sampling_geometry = MeshModel() # Add the desired sampling point locations and store their ID for later use test_index1 = sampling_geometry.addVertex([6.0, 0.0, 0.0]) test_index2 = sampling_geometry.addVertex([3.0, 0.0, 0.0]) sampling_component = MaterialDomain(sample_geometry, "material_name", scenario) # Define the assembly to be simulated (note that the sampling_component is not included) component = MaterialDomain(component_geometry, "material_name", scenario) assembly = [component] simulator = StressSimulator(assembly, scenario) simulator.solve() displacement_query = FieldQuery(f=Field.Displacement) sampled_results = QueryResult(sampling_component) # sample only the custom point set sampled_VectorArray = simulator.sample(displacement_query, sampled_results) displacement_index1 = sampled_VectorArray.get(test_index1, 0) # x-displacement at above specified index1 displacement_index2 = sampled_VectorArray.get(test_index2, 1) # y-displacement at above specified index2
It also possible to provide only a collection of points to sample on, avoiding the cost of constructing the sampling geometry.
# After simulation has been performed # Create the collection of sample points points = [[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]] # Note that the material name, in this example "Steel", has to be a material defined in the simulation scenario. point_query = simulator.sample(points, "Steel", [FieldQuery(f=Field.VonMisesStress, FieldQuery(f=Field.Displacement)]) # For each point, the results contain the field value for each field in query order for p in point_query: if (p.dimension() == 1): # Print single valued fields, such as von Mises stress print(p.get(0, 0)) if p.dimension() == 3: # Print fields with multiple components, such as displacement print(f"({p.get(0, 0)}, {p.get(0, 1)}, {p.get(0, 2)})")