Many engineering problems require the results of one simulation to influence the inputs into a second simulation; in effect, a preliminary simulation is used to calibrate a second simulation. This could be done manually, but it makes more sense to automate the process wherever possible. With a little knowledge of the format of Dymola results files, this is a simple process which can be used to create calibrated experiments and the methodology can be applied to create functions to iterate simulations.
To do this, the model is required to be called to run from a function file. A simple 1 degree of freedom undamped vibrational system model has been built to illustrate this, where a force is applied for 1 second before being released to enable the system to vibrate freely. Figure 1 shows the diagram level of the test model. What we will do is to create a function to run the experiment, extract the force vector of the spring, extract the maximum force experienced and re-run the experiment utilising that force as the new excitation force.
Figure 1: Test model, called “One_DOF”. Image: Author.
This blog article makes extensive use of the simulateExtendedModel command, covered previously in an article published on the Claytex Tech Blog, which can be found at How to simulate a model multiple times with different parameter values.
Trajectory files and the .mat extension
As you may have noticed, the results files that Dymola produces have the .mat file extension and can be opened within MatLab; however, this is not a straightforward process due to the file structure of the Dymola results file. Known as a trajectory file, the results file is of a different format compared to MatLab .mat file formats, and cannot thus be treated like a standard MatLab .mat file (of various versions).
The trajectory file is characterised by two matrices; a numeric matrix called “s” and a string matrix known as “N”. Within the numeric matrix, each column refers to a data signal with the first column of the matrix reserved for the time vector. Corresponding to this column structure is the string matrix, which contains the names of the signals in the numeric matrix. The string matrix is structured in rows, with the row number of a string entry corresponding to the column number of signal in the numeric matrix, as illustrated in figure 2.
Figure 2: Visualisation of the trajectory file structure. Image: Dymola.
This is significantly different to how MatLab writes .mat files. As a result, Dymola possesses two sets of inbuilt functions to deal with different file types in the DymolaCommands package. Under the MatrixIO package 4 functions are found; readMatrix, readMatrixSize, readStringMatrix and writeMatrix. These commands are designed to work with and produce .mat files of the MatLab v4 type.
To deal with trajectory files, DymolaCommands contains a package called Trajectories. Within this package are functions which can be used with Dymola results files; MatrixIO functions will not read the trajectory file correctly. Similar functions to the MatrixIO package can be found in the Trajectories package, along with a number of other functions enabling the user to conduct further actions with the simulation results file:
- existTrajectoryNames – Check if a provided name is present in a particular result file
- interpolateTrajectory – Interpolates between discrete data points in a result file
- readTrajectory – Reads user defined signals from result file into Dymola
- readTrajectoryNames – Reads all the signal names from a result file into Dymola
- readTrajectorySize – Reads in the number of rows within a result file into Dymola
- writeTrajectory – Writes user defined data into a trajectory format file
Whilst these functions are very useful for post processing within Dymola, they can also be used to calibrate a second experiment based upon a preliminary experiment as we wish.
Calibration function – “One_DOF_Example”
The initial portion of the function algorithm executes the “One_DOF” model presented in the introduction, with the results saved to a trajectory file called “initial_results” using a method mentioned in a previous blog post, with the link in the introduction. The following code simulates the One_DOF model for 5 seconds with a constant excitation force of 5N which is released after 1s with the system free to vibrate for the following 4s.
//Run the model initially to generate results to be investigated
simulateExtendedModel(
"One_DOF",
initialNames={"step.height","step.offset","step.startTime"},
initialValues={-5,5,1},
finalNames={"step.height"},
stopTime=5,
numberOfIntervals=1000,
resultFile="initial_results");
In order to read the results into Dymola so they can be processed and utilised in the next simulation, the size of the results file must be read. As Dymola will write the result file from a simulation to the working directory, it can be found easily by the Trajectories functions and an extended path name is not required. The only caveat is that the .mat file extension is required in the input string along with the result file name, as the following code shows.
//Read the size of the results file for importation
initialResultsSize := DymolaCommands.Trajectories.readTrajectorySize("initial_results.mat");
With the size of the results file determined, the readTrajectory command can be used to read the required variables into Dymola. As we want to extract the highest spring force, the spring.f signal is the result we are interested in. This command also looks for the result file in the working directory as well, meaning only the filename is required again.
//Read in the results from the initial model for processing
initialResults := DymolaCommands.Trajectories.readTrajectory(
"initial_results.mat",
{"spring.f"},
initialResultsSize);
Now within the variable initialResults is the entire numerical vector (all values in the “s” matrix which correspond to the positon of the string spring.f in the “N” matrix) of results from the simulation result file; it is important to note that only the values from the result vector are returned as the time is contained under a separate variable name. The maximum value is found easily using the max() command.
//Identify the maximum force experienced
newInput := max(initialResults);
The variable newInput can now be used as an input value into simulations executed in the subsequent lines of code within the function, as below. This means the model is excited by a 3.939N force instead of a 5N force.
//Re-run the experiment with the new force value
simulateExtendedModel(
"One_DOF",
initialNames={"step.height","step.offset","step.startTime"},
initialValues={(-1*newInput),newInput,1},
finalNames={"step.height"},
stopTime=5,
numberOfIntervals=1000,
resultFile="newResults");
Results
Plotting the spring forces in figure 3 for the preliminary (red) and secondary (blue) experiments shows the difference in spring forces resulting from the reduction in excitation force.
Figure 3: Comparison of results from preliminary and secondary simulations. Image: Author.
Written by: Theodor Ensbury – Project Engineer