Getting Numerical Data
This section provides several examples of how to retrieve general numerical data from models using method code. The examples cover different types of studies including parametric sweeps, time-dependent (transient) simulations, and eigenfrequency analyses.
Getting Values at a Point
This example is based on the Steady-State 2D Heat Transfer with Conduction tutorial model, which you can find in the Application Libraries at COMSOL Multiphysics > Heat Transfer.
Because it is a stationary (steady-state) simulation, it represents one of the simplest scenarios for demonstrating results evaluation.
The examples below, including method code, is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
heat_convection_2d_get_value_at_point.mph
The following code evaluates the temperature at the location defined by a Cut Point 2D feature, demonstrating how to use both an Evaluation Group and a Derived Values feature:
Evaluation Group
// Define a 2D point dataset
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.6);
model.result().dataset("cpt1").set("pointy", 0.2);
 
// Create an Evaluation Group
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
 
// Add an EvalPoint feature to that group
model.result().evaluationGroup("eg1").create("pev1", "EvalPoint");
model.result().evaluationGroup("eg1").feature("pev1").set("data", "cpt1");
 
// Set the expression to be the temperature T
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
 
// Set the unit using Unicode
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Run the group so the feature gets evaluated
model.result().evaluationGroup("eg1").run();
 
// Read back the number and unit
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
double pointValue = pointResult[0][0];
String pointValueUnit = model.result().evaluationGroup("eg1")
.feature("pev1").getString("unit");
 
// Display result
debugLog("Value at point: "+pointValue+" "+pointValueUnit);
 
// Alternative Messages window syntax: message("Value at point: "+pointValue+" "+pointValueUnit);
 
// (Optional) select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("pev1"));
Derived Values
// Define a 2D point dataset
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.6);
model.result().dataset("cpt1").set("pointy", 0.2);
 
// Add an EvalPoint feature to Derived Values
model.result().numerical().create("pev1", "EvalPoint");
model.result().numerical("pev1").set("data", "cpt1");
 
// Set the expression to be the temperature T
model.result().numerical("pev1").setIndex("expr", "T", 0);
 
// Set the unit using Unicode
model.result().numerical("pev1").setIndex("unit", "\u00b0C", 0); // Unicode unit syntax
// (Or ASCII: "degC" instead)
 
// Read back the number and unit
double[][] pointResult = model.result().numerical("pev1").getReal();
double pointValue = pointResult[0][0];
String pointValueUnit = model.result().numerical("pev1").getString("unit");
 
// Display result
debugLog("Value at point: "+pointValue+" "+pointValueUnit);
 
// Alternative Messages window syntax: message("Value at point: "+pointValue+" "+pointValueUnit);
 
// (Optional) select it in the Model Builder
selectNode(model.result().numerical("pev1"));
Note: If you use the Record Code or Record Method tools, the generated code will match the default user interface behavior, it writes all evaluated results into COMSOL table objects. It will not include direct assignments into double[][] arrays or double variables as shown above. The 2D array format is needed because each evaluation feature can compute multiple expressions or perform parametric sweeps.
Evaluating Two Quantities with an Evaluation Group
You can evaluate multiple quantities at once by using an Evaluation Group. In this example, both the temperature and the effective thermal conductivity are evaluated at the point by modifying the middle portion of the previous example:
// Set the expressions to be the temperature T and the effective thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "ht.kmean", 1);
 
// Set the unit for Temperature using Unicode
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Set the unit for thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "W/(m*K)", 1);
 
// Run the group so the feature gets evaluated
model.result().evaluationGroup("eg1").run();
 
// Read back the numbers and units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
double pointValue1 = pointResult[0][0]; // Temperature
double pointValue2 = pointResult[0][1]; // Thermal conductivity
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("pev1").getStringArray("unit");
 
// Display result
debugLog("Value at point: "+pointValue1+" "+pointValueUnitArray[0]);
debugLog("Value at point: "+pointValue2+" "+pointValueUnitArray[1]);
The results and units are retrieved as elements of arrays, corresponding to the evaluated expressions.
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
heat_convection_2d_get_value_at_point_2_expression.mph
This file also includes a corresponding method that demonstrates the use of Derived Values.
Evaluating Quantities For a Parametric Sweep
Building on the previous example, the figure below shows the results of a parametric sweep where the rectangle height parameter h1 is varied in four steps: 0.9, 1.0, 1.1, and 1.2 m.
For parametric sweeps, such output can also be generated programmatically using a custom method, as demonstrated in the figure below where the results are written to the Debug Log.
The following code snipped shows how this can be achieved for an Evaluation Group in a method.
// Create a CutPoint2D dataset at (x=0.6, y=0.2) using the parametric sweep dataset dset2
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.6);
model.result().dataset("cpt1").set("pointy", 0.2);
model.result().dataset("cpt1").set("data", "dset2"); // Use data from parametric sweep
 
// Create an Evaluation Group named eg1
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
 
// Add an EvalPoint feature pev1 to the group
model.result().evaluationGroup("eg1").create("pev1", "EvalPoint");
model.result().evaluationGroup("eg1").feature("pev1").set("data", "cpt1");
 
// Set expressions to evaluate: temperature and effective thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "ht.kmean", 1);
 
// Set the unit for temperature (Unicode)
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Set the unit for thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "W/(m*K)", 1);
 
// Run the Evaluation Group for all parametric values
model.result().evaluationGroup("eg1").run();
 
// Retrieve evaluated values and their corresponding units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("pev1").getStringArray("unit");
 
// Retrieve the unit for the sweep parameter
String parUnit = model.study("std1").feature("param").getString("punit");
 
// Loop over the sweep and print results
int lengthSweep = pointResult.length;
for (int k = 0; k < lengthSweep; k++) {
// Extract values
double pointValue0 = pointResult[k][0]; // Sweep parameter value (rectangle height)
double pointValue1 = pointResult[k][1]; // Temperature
double pointValue2 = pointResult[k][2]; // Thermal conductivity
// Display the evaluated results
  debugLog("Parameter: "+pointValue0+" "+parUnit);
  debugLog("Temperature at point: "+pointValue1+" "+pointValueUnitArray[0]);
  debugLog("Conductivity at point: "+pointValue2+" "+pointValueUnitArray[1]);}
 
// (Optional) select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("pev1"));
Note that the evaluation results are stored in the 2D array pointResult in the same order as shown in the Evaluation Group table in the user interface. The first index corresponds to the sweep parameter index, and the second index corresponds to the evaluated expressions. By default, each row begins with the sweep parameter value, followed by the results of the specified expressions.
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
Parametric Sweep with Specific Combinations: Two or More Parameters
Continuing with the Steady-State 2D Heat Transfer with Conduction tutorial model, suppose a parametric sweep is performed over two parameters: the rectangle height h1 and the boundary temperature T0. Assume the Sweep type is set to Specific combinations, with the following values:
Rectangle height h1: 0.9, 1.0, 1.1, and 1.2 m
Boundary temperature T0: 100, 150, 200, and 200 degC (°C)
Note: When using Specific combinations, the parameter lists must have the same length, in this case 4 simulation runs, with each entry representing one combination.
The figure below shows the Parametric Sweep settings used for this configuration
We can now use a breakpoint in the Method Editor to stop the code execution at the assignment of the pointResult array and display the results using the Data Viewer window:
For information on using breakpoints, see the book Introduction to the Application Builder.
The code in this case will resemble the one-parameter sweep case. Only the latter part of the code, where the results are processed, needs to be modified, as shown below:
// Retrieve units for sweep parameters
String[] parUnit = model.study("std1").feature("param").getStringArray("punit");
 
// For specific combinations, each row of pointResult already contains h1, T0, T, and ht.kmean
for (int k = 0; k < pointResult.length; k++) {
double h1 = pointResult[k][0];
double T0 = pointResult[k][1];
double temperature = pointResult[k][2];
double conductivity = pointResult[k][3];
debugLog("h1 = "+h1+" "+parUnit[0]);
debugLog("T0 = "+T0+" "+parUnit[1]);
debugLog(" Temperature at point: "+temperature+" "+pointValueUnitArray[0]);
debugLog(" Thermal conductivity: "+conductivity+" "+pointValueUnitArray[1]);
debugLog("");
}
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant files for this example are:
heat_convection_2d_get_value_at_point_two_parameter_sweep_specific_combinations.mph
heat_convection_2d_get_value_at_point_four_parameter_sweep_specific_combinations.mph
The four-parameter example includes two dummy parameters to demonstrate that the same approach applies when using the Specific combinations option with more than two parameters.
Parametric Sweep with All Combinations: Two Parameters
Continuing with the Steady-State 2D Heat Transfer with Conduction tutorial model, assume now that the Sweep type is set to All combinations, with the following values:
Rectangle height h1: 0.9, 1.0, 1.1, and 1.2 m
Boundary temperature T0: 100, 150, and 200 degC (°C)
This results in 4×3=12 simulation runs, covering all combinations of the two parameters. The figure below shows the Parametric Sweep settings used for this configuration.
Programmatically, this corresponds to a nested for-loop. This loop is indexed, starting from 1. Once an Evaluation Group has been created, the indices can be retrieved using the following call:
double[][] sweepIndices = model.result().evaluationGroup("eg1").feature("pev1").getDoubleMatrix("looplevel");
debugLog(sweepIndices);
The corresponding output for the array sweepIndices in the Debug Log window is:
{{1, 2, 3}, {1, 2, 3, 4}}
However, in the following example this array will not be needed.
We can use a breakpoint in the Method Editor to stop the code execution at the assignment of the pointResult array and display the results using the Data Viewer window:
Note that the pointResult array has dimensions [12][4], where:
The first index corresponds to the parameter combination, with the sweep ordered such that T0 varies fastest (that is, inner loop), and h1 varies slowest (outer loop).
-
-
-
-
In the output, you can confirm this organization:
Rows [0–2] all have h1 = 0.9, with T0 = 100, 150, 200
Rows [3–5] have h1 = 1.0, again sweeping over the same T0 values
This structure follows the row-major order of all combinations: for each value of h1, all values of T0 are iterated through.
The following code snippet shows how data can be retrieved in a method.
// Optionally make sure to use Unicode label for temperature in parametric sweep
model.study("std1").feature("param").setIndex("punit", "\u00b0C", 1);
 
// Create a CutPoint2D dataset at (x=0.6, y=0.2) using the parametric sweep dataset dset2
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.6);
model.result().dataset("cpt1").set("pointy", 0.2);
model.result().dataset("cpt1").set("data", "dset2"); // Use data from parametric sweep
 
// Create an Evaluation Group named eg1
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
 
// Add an EvalPoint feature pev1 to the group
model.result().evaluationGroup("eg1").create("pev1", "EvalPoint");
model.result().evaluationGroup("eg1").feature("pev1").set("data", "cpt1");
 
// Set expressions to evaluate: temperature and effective thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "ht.kmean", 1);
 
// Use description labels that are easy to use with Java's string utilities (using underscore)
model.result().evaluationGroup("eg1").feature("pev1").setIndex("descr", "Point_temperature", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("descr", "Point_thermal_conductivity", 1);
 
// Set the unit for temperature (Unicode)
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Set the unit for thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "W/(m*K)", 1);
 
// Run the Evaluation Group for all parametric values
model.result().evaluationGroup("eg1").run();
 
// Retrieve evaluated values and their corresponding units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("pev1").getStringArray("unit");
 
// Retrieve the units for the sweep parameters
String[] parUnits = model.study("std1").feature("param").getStringArray("punit");
 
// Retrieve the description labels from the Evaluation Group column headers, assuming they use underscore in their names
String[] columnHeaders = model.result().evaluationGroup("eg1").getColumnHeaders();
String[] headerNames = new String[columnHeaders.length];
for (int i = 0; i < columnHeaders.length; i++) {
headerNames[i] = columnHeaders[i].split(" ")[0];
}
 
// Loop over each row of results
for (int i = 0; i < pointResult.length; i++) {
double h1 = pointResult[i][0];
double T0 = pointResult[i][1];
double pointTemperature = pointResult[i][2];
double pointConductivity = pointResult[i][3];
debugLog(headerNames[0]+" = "+h1+" "+parUnits[0]+" , "+headerNames[1]+" = "+T0+" "+parUnits[1]);
debugLog(headerNames[2]+": "+pointTemperature+" "+pointValueUnitArray[0]);
debugLog(headerNames[3]+": "+pointConductivity+" "+pointValueUnitArray[1]);
debugLog("");
}
 
// Optionally select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("pev1"));
The (abridged) output from this code is as follows:
h1 = 0.9 m , T0 = 100.0 °C
Point_temperature: 18.187109113310555 °C
Point_thermal_conductivity: 52.0 W/(m*K)
 
h1 = 0.9 m , T0 = 150.0 °C
Point_temperature: 27.280663669965747 °C
Point_thermal_conductivity: 52.0 W/(m*K)
 
h1 = 0.9 m , T0 = 200.0 °C
Point_temperature: 36.37421822662094 °C
Point_thermal_conductivity: 52.0 W/(m*K)
 
h1 = 1.0 m , T0 = 100.0 °C
Point_temperature: 18.265040746500574 °C
Point_thermal_conductivity: 52.0 W/(m*K)
 
...
 
h1 = 1.2 m , T0 = 200.0 °C
Point_temperature: 36.67970125214907 °C
Point_thermal_conductivity: 52.0 W/(m*K)
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
Parametric Sweep with All Combinations: Three or More Parameters
Expanding on the previous example, let us now introduce a dummy parameter par1, for demonstration purposes.
As before, we can use a breakpoint in the Method Editor to pause execution at the assignment of the pointResult array and inspect the contents using the Data Viewer window.
Note that the pointResult array has dimensions [24][5], where:
The first index corresponds to the parameter combination, with the sweep ordered such that par1 varies fastest (that is, inner loop), then T0 varies intermediately, and h1 varies slowest (outer loop).
-
-
-
-
-
The code used for a two-parameter sweep with the All Combinations option can be generalized as follows, by modifying the latter part of the loop:
// Previous code
// ...
/// Loop over each row of results
int numSweepParams = 3; // or headerNames.length - number of result expressions
for (int i = 0; i < pointResult.length; i++) {
// Print all sweep parameters in one line
String paramLine = "";
for (int p = 0; p < numSweepParams; p++) {
if (p > 0) paramLine += " , ";
paramLine += headerNames[p]+" = "+pointResult[i][p]+" "+parUnits[p];
}
debugLog(paramLine);
// Print evaluated results
for (int j = 0; j < pointValueUnitArray.length; j++) {
debugLog(" "+headerNames[numSweepParams+j]+": "+
pointResult[i][numSweepParams+j]+" "+pointValueUnitArray[j]);
}
debugLog("");
}
This code generalizes to more than three parameters.
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant files for this example are:
heat_convection_2d_get_value_at_point_three_parameter_sweep_all_combinations.mph
heat_convection_2d_get_value_at_point_four_parameter_sweep_all_combinations.mph
The second example demonstrates the case of four parameters.
Parametric Sweep that Includes an Auxiliary Sweep
A model can include nested parametric sweeps, consisting of an outer sweep and an inner sweep, where the inner sweep typically represents physics-related parameters, such as material properties or boundary conditions, rather than geometric dimensions or mesh settings. One common type of inner sweep is the auxiliary sweep. For example, in the Steady-State 2D Heat Transfer with Conduction tutorial model, the boundary temperature can be assigned as an auxiliary sweep parameter, whereas the rectangle height, being a geometric property, cannot.
The process of extracting results using an Evaluation Group remains essentially the same, even when an auxiliary sweep is used.
Assume again that the parameters take the following values:
Rectangle height h1: 0.9, 1.0, 1.1, and 1.2 m
Boundary temperature T0: 100, 150, and 200 degC (°C)
The outer sweep is defined as shown in the figure below.
The auxiliary sweep (inner sweep) is defined in settings window for Step 1: Stationary as shown in the figure below.
The following code snippet shows how data can be retrieved in a method.
// Optionally make sure to use Unicode label for temperature in parametric sweep
model.study("std1").feature("stat").setIndex("punit", "\u00b0C", 0); // Auxiliary sweep unit
 
// Create a CutPoint2D dataset at (x=0.6, y=0.2) using the parametric sweep dataset dset2
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.6);
model.result().dataset("cpt1").set("pointy", 0.2);
model.result().dataset("cpt1").set("data", "dset2"); // Use data from parametric sweep
 
// Create an Evaluation Group named eg1
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
 
// Add an EvalPoint feature pev1 to the group
model.result().evaluationGroup("eg1").create("pev1", "EvalPoint");
model.result().evaluationGroup("eg1").feature("pev1").set("data", "cpt1");
 
// Set expressions to evaluate: temperature and effective thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "ht.kmean", 1);
 
// Use description labels that are easy to use with Java's string utilities (using underscore)
model.result().evaluationGroup("eg1").feature("pev1").setIndex("descr", "Point_temperature", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("descr", "Point_thermal_conductivity", 1);
 
// Set the unit for temperature (Unicode)
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Set the unit for thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "W/(m*K)", 1);
 
// Run the Evaluation Group for all parametric values
model.result().evaluationGroup("eg1").run();
 
// Retrieve evaluated values and their corresponding units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("pev1").getStringArray("unit");
 
// Retrieve the unit for the sweep parameters
 
// Since h1 is the only parameter in the outer sweep, retrieve its unit directly as a string
String parUnit = model.study("std1").feature("param").getString("punit");
 
// Retrieve the unit for the auxiliary sweep parameter
String auxUnit = model.study("std1").feature("stat").getString("punit");
 
// Retrieve the description labels from the Evaluation Group column headers, assuming they use underscore in their names
String[] columnHeaders = model.result().evaluationGroup("eg1").getColumnHeaders();
String[] headerNames = new String[columnHeaders.length];
for (int i = 0; i < columnHeaders.length; i++) {
headerNames[i] = columnHeaders[i].split(" ")[0];
}
 
// Loop over each row of results
for (int i = 0; i < pointResult.length; i++) {
double h1 = pointResult[i][0];
double T0 = pointResult[i][1];
double pointTemperature = pointResult[i][2];
double pointConductivity = pointResult[i][3];
debugLog(headerNames[0]+" = "+h1+" "+parUnit+" , "+headerNames[1]+" = "+T0+" "+auxUnit);
debugLog(headerNames[2]+": "+pointTemperature+" "+pointValueUnitArray[0]);
debugLog(headerNames[3]+": "+pointConductivity+" "+pointValueUnitArray[1]);
debugLog("");
}
 
// Optionally select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("pev1"));
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
Computing the Average Along a Boundary in a Parametric Sweep
Continuing with the Steady-State 2D Heat Transfer with Conduction tutorial model, consider the case of a parametric sweep over one parameter: the rectangle height. Suppose now that we want to compute the average temperature along the right boundary of the rectangle.
In this case, a point dataset is not required, but aside from that, the code remains very similar to the approach demonstrated earlier. One important detail is to ensure that the correct dataset corresponding to the parametric sweep is used. In this example, that is the dataset with the tag dset2.
The following code snippet shows how to use an Evaluation Group to retrieve the average temperature on a boundary within a method.
// Create the Evaluation Group and set it to use the parametric sweep dataset
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
model.result().evaluationGroup("eg1").set("data", "dset2"); // Set sweep dataset
 
// Add an AvLine feature to the Evaluation Group to compute average values along a boundary
model.result().evaluationGroup("eg1").create("av1", "AvLine");
// model.result().evaluationGroup("eg1").feature("av1").set("intsurface", true); // Needed if an axisymmetric model
model.result().evaluationGroup("eg1").feature("av1").selection().set(4); // Apply to boundary 4
 
// Set expressions and units
model.result().evaluationGroup("eg1").feature("av1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("av1").setIndex("expr", "ht.kmean", 1);
 
model.result().evaluationGroup("eg1").feature("av1").setIndex("unit", "\u00b0C", 0);
model.result().evaluationGroup("eg1").feature("av1").setIndex("unit", "W/(m*K)", 1);
 
// Set optional labels
model.result().evaluationGroup("eg1").feature("av1").setIndex("descr", "Avg_temperature", 0);
model.result().evaluationGroup("eg1").feature("av1").setIndex("descr", "Avg_thermal_conductivity", 1);
 
// Run the Evaluation Group
model.result().evaluationGroup("eg1").run();
 
// Retrieve results and units
double[][] resultArray = model.result().evaluationGroup("eg1").getReal();
String[] resultUnits = model.result().evaluationGroup("eg1")
.feature("av1").getStringArray("unit");
 
// Retrieve sweep parameter unit
String parUnit = model.study("std1").feature("param").getString("punit");
 
// Loop over results
for (int i = 0; i < resultArray.length; i++) {
double sweepVal = resultArray[i][0]; // Sweep parameter (h1)
double avgTemp = resultArray[i][1]; // Average temperature
double avgCond = resultArray[i][2]; // Average conductivity
debugLog("Parameter: "+sweepVal+" "+parUnit);
debugLog(" Average temperature: "+avgTemp+" "+resultUnits[0]);
debugLog(" Average conductivity: "+avgCond+" "+resultUnits[1]);
}
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
heat_convection_2d_get_value_at_point_one_parameter_sweep_global.mph
The feature type used in the Evaluation Group for computing an average along a line is AvLine. Similar feature types exist for other combinations of geometric entities and evaluation operations, as summarized in the table below.
Computing Global Quantities in a Parametric Sweep
Continuing with the Steady-State 2D Heat Transfer with Conduction tutorial model and a parametric sweep over the rectangle height, suppose we now want to compute a global quantity, for example, the number of degrees of freedom (DOFs) in the model for each parameter value. (A global quantity is one that is not associated with a specific geometric entity.)
This value will vary throughout the sweep because, as the rectangle height changes, the mesh is regenerated and the number of mesh elements, and thus the number of DOFs, changes.
The variable name for the number of DOFs is numberofdofs.
The following code snippet shows how to use an Evaluation Group to retrieve the number of degrees of freedom at each step of a parametric sweep within a method.
// Create the Evaluation Group and set it to use the parametric sweep dataset
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
model.result().evaluationGroup("eg1").set("data", "dset2"); // Set sweep dataset
 
// Add a Global Evaluation feature to the Evaluation Group
model.result().evaluationGroup("eg1").create("gev1", "EvalGlobal");
 
// Set the expression to evaluate: number of DOFs
model.result().evaluationGroup("eg1").feature("gev1").set("expr", new String[]{"numberofdofs"});
 
// Optional: Set a label and unit
model.result().evaluationGroup("eg1").feature("gev1").set("descr", new String[]{"Number of degrees of freedom"});
model.result().evaluationGroup("eg1").feature("gev1").set("unit", new String[]{"1"});
 
// Run the evaluation group for all sweep points
model.result().evaluationGroup("eg1").run();
 
// Retrieve the results (1 column: DOFs, 1 row per sweep point)
double[][] dofResults = model.result().evaluationGroup("eg1").getReal();
 
// Retrieve the unit for the sweep parameter
String parUnit = model.study("std1").feature("param").getString("punit");
 
// Loop through results
for (int i = 0; i < dofResults.length; i++) {
double h1 = dofResults[i][0]; // Sweep parameter (h1)
int ndof = (int) dofResults[i][1]; // Number of DOFs
debugLog("h1 = "+h1+" "+parUnit);
debugLog(" Number of DOFs: "+ndof);
}
Note: As an alternative to using Evaluation Group features such as AvLine and MaxVolume, you can define a nonlocal coupling operator under Component > Definitions > Nonlocal Couplings, and then evaluate it as a global quantity.
This example is part of a collection available for download and is included in the same file as the previous example, Computing the Average Along a Boundary in a Parametric Sweep.
Nested Parametric Sweep Nodes
Instead of using a single Parametric Sweep feature with the All combinations or Specified combinations option, you can use multiple nested Parametric Sweep nodes. Accessing results from a nested sweep is very similar to retrieving data from a sweep that uses only one Parametric Sweep node.
Consider the earlier example where the sweep type is set to All combinations, with the following parameter values:
Rectangle height h1: 0.9, 1.0, 1.1, and 1.2 m
Boundary temperature T0: 100, 150, and 200 degC (°C)
This sweep can also be performed by nesting two Parametric Sweep nodes, as illustrated in the figures below.
The following code snippet shows how to retrieve data from such a nested sweep. While the process is similar to the single-node case, there are some minor differences.
// Optionally make sure to use Unicode label for temperature in parametric sweep
model.study("std1").feature("param").setIndex("punit", "\u00b0C", 0);
model.study("std1").feature("param2").setIndex("punit", "m", 0);
 
// Create a CutPoint2D dataset at (x=0.6, y=0.2) using the parametric sweep dataset dset2
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.6);
model.result().dataset("cpt1").set("pointy", 0.2);
model.result().dataset("cpt1").set("data", "dset2"); // Use data from parametric sweep
 
// Create an Evaluation Group named eg1
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
 
// Add an EvalPoint feature pev1 to the group
model.result().evaluationGroup("eg1").create("pev1", "EvalPoint");
model.result().evaluationGroup("eg1").feature("pev1").set("data", "cpt1");
 
// Set expressions to evaluate: temperature and effective thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "ht.kmean", 1);
 
// Use description labels that are easy to use with Java's string utilities (using underscore)
model.result().evaluationGroup("eg1").feature("pev1").setIndex("descr", "Point_temperature", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("descr", "Point_thermal_conductivity", 1);
 
// Set the unit for temperature (Unicode)
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Set the unit for thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "W/(m*K)", 1);
 
// Run the Evaluation Group for all parametric values
model.result().evaluationGroup("eg1").run();
 
// Retrieve evaluated values and their corresponding units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("pev1").getStringArray("unit");
 
// Retrieve the units for the sweep parameters
String parUnit1 = model.study("std1").feature("param").getString("punit");
String parUnit2 = model.study("std1").feature("param2").getString("punit");
 
// Retrieve the description labels from the Evaluation Group column headers, assuming they use underscore in their names
String[] columnHeaders = model.result().evaluationGroup("eg1").getColumnHeaders();
String[] headerNames = new String[columnHeaders.length];
for (int i = 0; i < columnHeaders.length; i++) {
headerNames[i] = columnHeaders[i].split(" ")[0];
}
 
// Loop over each row of results
for (int i = 0; i < pointResult.length; i++) {
double h1 = pointResult[i][0];
double T0 = pointResult[i][1];
double pointTemperature = pointResult[i][2];
double pointConductivity = pointResult[i][3];
debugLog(headerNames[0]+" = "+h1+" "+parUnit2+" , "+headerNames[1]+" = "+T0+" "+parUnit1);
debugLog(headerNames[2]+": "+pointTemperature+" "+pointValueUnitArray[0]);
debugLog(headerNames[3]+": "+pointConductivity+" "+pointValueUnitArray[1]);
debugLog("");
}
 
// Optionally select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("pev1"));
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
Nested Parametric Sweep Nodes, Ragged Sweep
In certain cases, the nested node option gives you additional flexibility. For example, you can perform sweeps where the inner parameter is a function of the outer parameter. This results in an irregular sweep where some parameter combinations are missing. Other names for this type of sweep are jagged or ragged sweep.
The following example of a spinning aluminum disk demonstrates a sweep over a geometry with a varying number of holes depending on the hole radius. The example is available for download (see below) and demonstrates accessing results for a ragged sweep.
// Set number of displayed digits
int digits = 4;
 
// Set parametric sweep units
model.study("std1").feature("param").setIndex("punit", "1", 0);
model.study("std1").feature("param1").setIndex("punit", "m", 0);
 
// Create an Evaluation Group named eg1 and set it to the parametric sweep dataset
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
model.result().evaluationGroup("eg1").set("data", "dset2");
 
// Create an average surface evaluation feature
model.result().evaluationGroup("eg1").create("av1", "AvSurface");
model.result().evaluationGroup("eg1").feature("av1").selection().set(1);
 
// Set expressions to evaluate and their units
model.result().evaluationGroup("eg1").feature("av1").setIndex("expr", "solid.disp", 0);
model.result().evaluationGroup("eg1").feature("av1").setIndex("expr", "solid.mises", 1);
model.result().evaluationGroup("eg1").feature("av1").setIndex("unit", "\u00b5m", 0);
model.result().evaluationGroup("eg1").feature("av1").setIndex("unit", "MPa", 1);
 
// Use description labels that are easy to use with Java's string utilities (using underscore)
model.result().evaluationGroup("eg1").feature("av1").setIndex("descr", "Displacement_magnitude", 0);
model.result().evaluationGroup("eg1").feature("av1").setIndex("descr", "von_Mises_stress", 1);
 
// Run the Evaluation Group for all parametric values
model.result().evaluationGroup("eg1").run();
 
// Retrieve evaluated values and their corresponding units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("av1").getStringArray("unit");
 
// Retrieve the units for the sweep parameters
// String parUnit1 = model.study("std1").feature("param").getString("punit"); // parUnit1 is not needed since it is 1 (the unit of the number of holes)
String parUnit2 = model.study("std1").feature("param1").getString("punit");
 
// Retrieve the description labels from the Evaluation Group column headers, assuming they use underscore in their names
String[] columnHeaders = model.result().evaluationGroup("eg1").getColumnHeaders();
String[] headerNames = new String[columnHeaders.length];
for (int i = 0; i < columnHeaders.length; i++) {
headerNames[i] = columnHeaders[i].split(" ")[0];
}
 
// Loop over each row of results
for (int i = 0; i < pointResult.length; i++) {
int numHoles = (int) (pointResult[i][0]);
String holeRadius = toString(pointResult[i][1], digits);
String avDisp = toString(pointResult[i][2], digits);
String avStress = toString(pointResult[i][3], digits);
debugLog(headerNames[0]+" = "+numHoles+" , "+headerNames[1]+" = "+holeRadius+" "+parUnit2);
debugLog(headerNames[2]+": "+avDisp+" "+pointValueUnitArray[0]);
debugLog(headerNames[3]+": "+avStress+" "+pointValueUnitArray[1]);
debugLog("");
}
 
// Optionally select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("av1"));
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
Retrieving Data from a Transient Simulation
This example is based on the Axisymmetric Transient Heat Transfer tutorial model, which you can find in the Application Libraries at COMSOL Multiphysics > Heat Transfer.
This is a transient (time-dependent) simulation and retrieving transient data is very similar to that of a parametric sweep. You will notice that the code below is very similar to the example in Evaluating Quantities For a Parametric Sweep.
// Remove any existing features
model.result().evaluationGroup().remove("eg1");
model.result().dataset().remove("cpt1");
 
// Create a CutPoint2D dataset at (R=0.1 (pointx), Z=0.3 (pointy))
// Note, this is an axisymmetric model
model.result().dataset().create("cpt1", "CutPoint2D");
model.result().dataset("cpt1").set("pointx", 0.1);
model.result().dataset("cpt1").set("pointy", 0.3);
 
// Create an Evaluation Group named eg1
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
 
// Add an EvalPoint feature pev1 to the group
model.result().evaluationGroup("eg1").create("pev1", "EvalPoint");
model.result().evaluationGroup("eg1").feature("pev1").set("data", "cpt1");
 
// Set expressions to evaluate: temperature and effective thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "T", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("expr", "ht.kmean", 1);
 
// Set or confirm the unit for time (optional, defaults to seconds)
model.study("std1").feature("time").set("tunit", "s");
 
// Set the unit for temperature (Unicode)
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "\u00b0C", 0);
// (Or ASCII: "degC" instead)
 
// Set the unit for thermal conductivity
model.result().evaluationGroup("eg1").feature("pev1").
setIndex("unit", "W/(m*K)", 1);
 
// Run the Evaluation Group for all parametric values
model.result().evaluationGroup("eg1").run();
 
// Retrieve evaluated values and their corresponding units
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
String[] pointValueUnitArray = model.result().evaluationGroup("eg1")
.feature("pev1").getStringArray("unit");
 
// Retrieve the unit for the transient parameter
String timeUnit = model.study("std1").feature("time").getString("tunit");
 
// Loop over output times (that is, times stored in the solution), which may differ from internal solver steps
int lengthTimeList = pointResult.length;
for (int k = 0; k < lengthTimeList; k++) {
// Extract values
double pointValue0 = pointResult[k][0]; // Time value (similar to a sweep parameter value)
double pointValue1 = pointResult[k][1]; // Temperature
double pointValue2 = pointResult[k][2]; // Thermal conductivity
// Display the evaluated results
debugLog("Time: "+pointValue0+" "+timeUnit);
debugLog("Temperature at point: "+pointValue1+" "+pointValueUnitArray[0]);
debugLog("Conductivity at point: "+pointValue2+" "+pointValueUnitArray[1]);
debugLog("");
}
 
// (Optional) select it in the Model Builder
selectNode(model.result().evaluationGroup("eg1").feature("pev1"));
The (abridged) output from this code is as follows:
Time: 0.0 s
Temperature at point: 5.307062156134634E-5 °C
Conductivity at point: 52.0 W/(m*K)
 
Time: 10.0 s
Temperature at point: 0.002430733497874371 °C
Conductivity at point: 52.0 W/(m*K)
 
Time: 20.0 s
Temperature at point: 0.056482830296829434 °C
Conductivity at point: 52.0 W/(m*K)
 
...
 
Time: 380.0 s
Temperature at point: 410.03241468409624 °C
Conductivity at point: 52.0 W/(m*K)
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
heat_transient_axi_get_value_at_point_.mph
Accessing The Length of a Parametric List
There are multiple ways to retrieve the number of parameters or time steps in a solution. In the previous examples, calls such as:
double[][] pointResult = model.result().evaluationGroup("eg1").getReal();
int lengthSweep = pointResult.length;
can be used to retrieve the length of the sweep.
An alternative for an Evaluation Group is:
int nOfRows = model.result().evaluationGroup("eg1").getNRows();
which returns the number of rows in the corresponding result table.
If you instead have access to a Plot Group (for example, with the tag pg1), you can use:
int lengthOfSweep = model.result("pg1").getStepCount(0);
Here, the argument to getStepCount represents the parameter index. However, note that getStepCount belongs to a different part of the API that is more tightly linked to the solution data structures. As a result, the ordering of parameters differs from that of an Evaluation Group.
For sweeps involving 1, 2, or 3 parameters, the order is simply the reverse of that used in an Evaluation Group. For 4 parameters, however, the last two parameters are combined into a single sequence. Alternatively, you can think of it as the first two parameters being grouped together.
To illustrate this, consider a sweep over the parameters h1, T0, par1, and par2, as shown in the figure below.
A corresponding 2D Plot Group setting is shown in the figure below.
Here, we can see that the first two parameters h1 and T0 are grouped together. An expanded view of this list is presented in the following figure.
This list contains 4x3=12 entries, which is reflected by the value returned by:
int lengthOfSweep = model.result("pg1").getStepCount(2);
The figure below show all the returned values for the inputs 0, 1, and 2, using the Java Shell window.
Accessing a Subset of a List of Output Times
A list of output times can be very long and there could be reasons to access only the solutions for a subset. Consider the example in the section Retrieving Data from a Transient Simulation. Recall that this example uses a point evaluation at a cut point.
To access a subset of output times based on index, you can use the following syntax:
model.result().evaluationGroup("eg1").feature("pev1").setIndex("looplevelinput", "manualindices", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("looplevelindices", "range(5,10,45)", 0);
To access a subset of output times based on interpolated times, you can use the following syntax:
model.result().evaluationGroup("eg1").feature("pev1").setIndex("looplevelinput", "interp", 0);
model.result().evaluationGroup("eg1").feature("pev1").setIndex("interp", "range(11.5,0.5,25.5)", 0);
Note that for interpolated times, the time values given as input do not need to match the output times of the Time Dependent study step.
If you want to clear the Debug Log window before running the method, you can call the clearDebugLog() method.
However, keep in mind that the primary purpose of these examples is not to print results to the Debug Log window, but rather to illustrate how data can be retrieved, processed, and used in other methods or incorporated into simulation apps.
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
heat_transient_axi_get_value_at_point_subset.mph
As an alternative to using an Evaluation Group, one can instead use a SolutionInfo object. This technique is more general but also more advanced.
The example below illustrates how the first and last time output times can be retrieved from a model using this technique.
// Use a SolutionInfo object to retrieve the first and last output times
SolverSequence sol = model.sol("sol1");
SolutionInfo info = sol.getSolutioninfo();
int[] indx1 = info.getIndices(0, new int[]{0}); // Not needed but used for demonstration purposes
double[][] values = info.getVals(0, new int[]{0});
double firstTime = values[0][0];
double lastTime = values[0][indx1.length-1];
The the methods getIndices and getVals are described in more detail in the Programming Reference Manual in the section SolutionInfo Object and its Methods.
Update a Choicelist Dynamically for Output Times
The following method updateOutputTimeList is part of an app where a Combo Box form object is used to select the output time used for evaluation and visualization.
// Set dummy expression 1 and use an Evaluation Group to evaluate first and last times
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
EvaluationGroupFeature eg1 = model.result().evaluationGroup("eg1");
eg1.create("gev1", "EvalGlobal");
eg1.feature("gev1").setIndex("expr", 1, 0);
eg1.run();
 
// Get first and last output times
eg1.setIndex("looplevelinput", "first", 0);
eg1.run();
double firstTime = eg1.getReal()[0][0];
 
eg1.setIndex("looplevelinput", "last", 0);
eg1.run();
double lastTime = eg1.getReal()[0][0];
 
// Calculate N evenly spaced times
int N = numberOfOutputTimes;
double[] times = new double[N];
for (int i = 0; i < N; i++) {
times[i] = firstTime+i*(lastTime-firstTime)/(N-1);
}
 
// Convert to string and interpolate
String[] timeStrs = new String[N];
for (int i = 0; i < N; i++) {
timeStrs[i] = toString(times[i], digits);
}
String interpList = String.join(" ", timeStrs);
 
// Set expression to evaluate (average)
model.result().evaluationGroup().create("eg2", "EvaluationGroup");
EvaluationGroupFeature eg2 = model.result().evaluationGroup("eg2");
eg2.create("av1", "AvVolume");
eg2.feature("av1").setIndex("expr", "T", 0);
eg2.set("data", "rev1");
 
eg2.setIndex("looplevelinput", "interp", 0);
eg2.setIndex("interp", interpList, 0);
eg2.run();
 
// Update choicelist and the current output time used for plot and evaluation
app.declaration("choicelist1").setList(timeStrs, timeStrs);
outputTimeStr = timeStrs[N-1];
changeOutputTime();
The method evaluates a dummy expression, "1", to retrieve the first and last output times. As an alternative, one can use the SolutionInfo method described in the section Accessing a Subset of a List of Output Times.
The call
app.declaration("choicelist1").setList(timeStrs, timeStrs);
is used to dynamically update choicelist1, which is used by a Combo Box in the app’s user interface.
The code for the changeOutputTime method is as follows.
EvaluationGroupFeature eg2 = model.result().evaluationGroup("eg2");
eg2.setIndex("interp", outputTimeStr, 0);
eg2.run();
 
double[][] pointResult = eg2.getReal();
pointValue = toString(pointResult[0][1], digits);
 
model.result("pg4").setIndex("looplevel", "interp", 0);
model.result("pg4").set("interp", outputTimeStr);
model.result("pg4").run();
 
model.result("pg2").setIndex("looplevel", "interp", 0);
model.result("pg2").set("interp", outputTimeStr);
model.result("pg2").run();
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant files for this example are:
heat_transient_axi_get_average_value_for_subset_evaluation_group_app.mph
heat_transient_axi_get_average_value_for_subset_solution_info_app.mph
Accessing Eigenfrequency Data
This example is based on the Tuning Fork tutorial model, which you can find in the Application Libraries at COMSOL Multiphysics > Structural Mechanics.
This is a combined parametric and eigenfrequency simulation that is also very similar to that of a parametric sweep. You will notice that the code below is very similar to the example in Evaluating Quantities For a Parametric Sweep.
The code below evaluates the eigenfrequencies for a subset of parameter values from a parametric sweep, using a Global Evaluation feature inside an Evaluation Group.
// Remove existing features if needed
model.result().evaluationGroup().remove("eg1");
 
// Create the Evaluation Group and set it to use the parametric sweep dataset
model.result().evaluationGroup().create("eg1", "EvaluationGroup");
model.result().evaluationGroup("eg1").set("data", "dset2"); // Set sweep dataset
 
// Add a Global Evaluation feature to the Evaluation Group
model.result().evaluationGroup("eg1").create("gev1", "EvalGlobal");
 
// Set the expression to evaluate a dummy expression 1
model.result().evaluationGroup("eg1").feature("gev1").setIndex("expr", "1", 0);
 
model.result().evaluationGroup("eg1").setIndex("looplevelinput", "manualindices", 0);
model.result().evaluationGroup("eg1").setIndex("looplevelindices", "7 8 9", 0);
 
model.result().evaluationGroup("eg1").setIndex("looplevelinput", "manual", 1);
model.result().evaluationGroup("eg1").setIndex("looplevel", "1 2 3", 1);
 
// Run the evaluation group for all sweep points
model.result().evaluationGroup("eg1").run();
 
// Retrieve the unit for the sweep parameter
String parUnit = model.study("std1").feature("param").getString("punit");
 
// Retrieve the unit for the eigenfrequency parameter
//String auxUnit = model.study("std1").feature("stat").getString("punit");
String efqUnit = model.study("std1").feature("eig").getString("eigunit");
 
// Retrieve the results
double[][] efqResults = model.result().evaluationGroup("eg1").getReal();
 
// Loop through results
for (int i = 0; i < efqResults.length; i++) {
double L = efqResults[i][0]; // Sweep parameter (L)
double efq = efqResults[i][1]; // Eigenfrequency (resonant frequency)
debugLog("L = "+L+" "+parUnit);
debugLog(" Eigenfrequency: "+efq+" "+efqUnit);
debugLog("");
}
Specifically it creates an Evaluation Group named eg1 and sets its dataset to dset2, which contains results from a parametric eigenfrequency sweep.
It uses dummy expression 1 to trigger evaluation at the selected sweep points. It manually selects which parametric indices and eigenmode indices to evaluate:
looplevelindices = "7 8 9" selects specific parameter values (for example, geometry or material settings).
looplevel = "1 2 3" selects specific eigenmodes at each sweep point.
The Evaluation Group is then run, and the output table contains:
The parameter value (L) used in the sweep.
Finally, the code logs each parameter and eigenfrequency pair. The eigenfrequencies vary with the parameter L, due to the fact that the resonance frequency is a function of the length of the tuning fork.
The (abridged) output from this code is as follows:
L = 0.078 m
Eigenfrequency: 451.12805182824405 Hz
 
L = 0.078 m
Eigenfrequency: 692.8198415933232 Hz
 
L = 0.078 m
Eigenfrequency: 1678.173090553073 Hz
 
...
 
L = 0.07875 m
Eigenfrequency: 1657.9561032429424 Hz
This example is part of a collection available for download:
www.comsol.com/model/application-programming-guide-examples-140771
The relevant file for this example is:
tuning_fork_get_eigenfrequency_data.mph