Macros in Java for STAR-CCM+
This page example functions and approach to automate simulation process partially or fully. It is not intended to created a push-button simulation example. Not all the codes have been tested in live STAR-CCM+ session and hence some bugs can be found.
File and String Handling in Java |+| Java Macros in STAR-CCM+ {*} Array definition and initialization in C (+) Create User Field Function [+] Arrays in Java [=] Set to ArrayList {!} Function to multiply two matrices (!) Function to solve [A]{x} = {b} similar to mldivide function in MATLAB ]=[ Getter and Setter [=] Java Generics
In JAVA, class name should always be the same as file name. If not so, error will be printed: error: class class_name is public, should be declared in a file named class_name.java
If file contains multiple classes, only one class (or interface) in file can be public, and it must have the same name as file. it is not a requirement that "class name must always be the same as file name", the convention is to make one public and make sure that the file name matches. Other conventions: The prefix of a unique package name is always written in all-lowercase ASCII letters. Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Interface names should be capitalized like class names. Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.
To compile the file, "javac file_name.java", to run the generated class file, use file name without extension .java, that is "java file_name".
If classes are in separate files (e.g. main_class.java, class_1.java, class_2.java) and main_class.java is the one containing the main method and references other classes such as class_1.java, compiling main_class.java will also compile class*.java if the source files are present in the same directory. After successful compilation, the folder will have corresponding .class files for each Java file. To run the program, use the 'java' command followed by the name of the class that contains the public static void main(String[] args) method.In Java, the main method can be defined in any class, and from within that main method, you can call any other method defined within that same class or other accessible classes.
public class PipeNetSolver {
// A separate, non-static method in the parent class
public void solve(int max_ter, double tolerance) {
...
}
// The main function can be defined in the same class
public static void main(String[] args) {
// To call a non-static method (like 'solve') from the static main method,
// an instance of the class MUST be created first.
PipeNetSolver pipeNet = new PipeNetSolver ();
// Now all the method using the instance
pipeNet.solve(500, 0.001);
}
}
Java is designed for OOP but it can also be used ad functional or procedural programming where all methods and functions are put inside one parent class containing the mandatory 'main' method explained above.
Set to ArrayList: Set does not allow duplicate elements and has no guaranteed order, while an ArrayList allows duplicates and maintains insertion order, with elements accessible by index. Convert the Set to an ArrayList using the constructor: List<Integer> int_list = new ArrayList<>(int_set); Or List<Integer> int_list = new ArrayList<>(); Add all elements from the set to the list: int_list.addAll(int_set); Collections.sort(int_ist); To sort in descending order: Collections.sort(int_list, Collections.reverseOrder());
If List<Integer> int_list = new ArrayList(); is used (missing <> at the end), compiler will throw warning "Note: ./fileName.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details."
Vectors: The Vector class implements a growable array of objects. Like an array, it contains components that can be accessed using an integer index. However, the size of a Vector can grow or shrink as needed to accommodate adding and removing items after the Vector has been created.
Dictionary: The Java equivalent to Python dictionary is the HashMap class, which is an implementation of the Map interface. Both are used to store data in key-value pairs.
import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;
public class DictExample {
public static void main(String[] args) {
// Declare a Map with String keys and Integer values
Map<String, Integer> nodes = new HashMap<>();
// Add key-value pairs (put method)
nodes.put("N1", 50); nodes.put("N3", 20); nodes.put("N5", 10);
// Retrieve a value by its key (get method)
int v_n1 = nodes.get("N1");
System.out.println("Value of N1: " + v_n1);
// Check if a key exists
if (nodes.containsKey("N3")) {
System.out.println("N3 is in the dictionary.");
}
List<Integer> list_i = new ArrayList<>();
// Iterate over the entries (similar to Python's dict.items())
for (Map.Entry<String, Integer> entry : nodes.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
} System.out.println(list_i);
}
Use Map<String, List<String>> data_map = new HashMap<>(); to create a multi-column table. Define variable to store names of the header: List<String> headers = null, data_map.keySet(): get all keys as a list, data_map.get("key_name"): get values for the key or header name. Assume header names are in variable 'line' separated by comma. Convert the header names into list: headers = Arrays.asList(line.split(","));
Now create an ArrayList for each name in headers:
for (String header : headers) {
data_map.put(header.trim(), new ArrayList<>());
}
Now store values in each header list:
String[] values = line.split(",");
for (int i = 0; i < headers.size() && i < values.length; i++) {
data_map.get(headers.get(i).trim()).add(values[i].trim());
}
In Java, variable names cannot be created at runtime. However, variable names be stored as the header names are stored here in a list: List<String> header_names = new ArrayList<>(data_map.keySet()); Note that the items of the list header_names are not in the same order in which it was present in the string 'line'. The
keySet() method of a standard HashMap in Java does not guarantee any specific order. Replace Map and HashMap above with LinkedHashMap to maintain order in which they were inserted.
Java Generics: In the Java Vector<E> class, the <E> indicates a Type Parameter used in Java Generics, which stands for Element Type. It is a placeholder for a reference type (Integer, String, or a custom class) that is specified when a Vector is instantiated. The letter between the < > is just a placeholder or name. Use of character 'E' is just a convention. It doesn't have to be a single upper-case letter. It can be any name just like classes, variables and methods are given. It represents a generic class, allowing it to hold any object type without needing to cast it upon retrieval.
Generic methods have a type parameter declared within angle brackets < > before return type of method.
public class GenericMethodToPrint {
// A generic method to print elements of an array of any type
public static <E> void printArray(E[] elements) {
for (E element : elements) {
System.out.println(element);
}
}
public static void main(String args[]) {
Integer[] intArray = {10, 20, 30, 40, 50};
String[] strArray = {"Thermal", "Network", "Solver"};
System.out.println("Printing Integer Array:");
printArray(integerArray);
System.out.println("Printing String Array:");
printArray(stringArray);
}
}
Similarly, the type variable, <T> can be any non-primitive type, any class type, any interface type, any array type, or even another type variable. The most commonly used type parameter names are: E - Element (used extensively by the Java Collections Framework), K - Key, N - Number, T - Type, V - Value.
Arrays in Java: example declarations - int[] arr_i = new int[5] or String [][][] zone_names = new String[5][3][2]. Declare an array of integers: int[] arr_i; Allocate memory for 10 integers: arr_i = new int[10];
List<Integer> list_i = new ArrayList<>(); note Integer and not int inside angled bracket. Declaration of a 2D ArrayList (List of Lists): List<List<String>> dataTable = new ArrayList<>();Arrays are accessed by [ ] using index: arr_i[index] and lists are accessed by get method: list_i.get(index).
int array_2d[n_rows][n_cols];
int[][] array_2d =
{ {1, 2, 3},
{5, 6, 7},
{8, 9, 0} };
Arrays are passed by values and by reference. There are subtle differences between the two. Use of arrays can occur in following scenarios: [a] the function takes an array as argument and returns nothing or primitive data type [2] the function takes nothing or primitive data as argument and returns an array [3] the function takes an array as argument and returns a processed array.
import java.io.*;
public class ReadArrays {
public static void getArrays(double[] arr_data) {
// Pass array by reference
for (int i = 0; i < arr_data.length; i++) {
arr_data[i] = arr_data[i]*5;
}
}
public static void main(String[] args) {
// Define input array
double[] arr_items = {10, 20, 30, 50};
// Modify the input array and print each item on a separate line
getArrays(arr_items);
for(double item : arr_items) {
System.out.println(item);
}
// Following shall print garbled text
System.out.println(arr_items);
}
}
Function that takes an array as argument and returns an array.
public class ReadArrays {
public static double[] getArrays(double[] arr_data) {
for (int i = 0; i < arr_data.length; i++) {
arr_data[i] = arr_data[i]*5;
}
return arr_data;
}
public static void main(String[] args) {
// Define input array
double[] arr_items = {10, 20, 30, 50};
// Modify the input array and print each item on a separate line
double[] x;
x = getArrays(arr_items);
for(double item : x) {
System.out.println(item);
}
}
} If "public static double getArrays(double[] arr_data)" is used instead of "public static double[] getArrays(double[] arr_data)", the error would occur: "incompatible types: double cannot be converted to double[]". This is because double is a data type and not an array.
// Helper function to print a matrix
public static void printMatrix(double[][] matrix) {
if (matrix == null) {
return;
}
for (double[] row : matrix) {
for (double element : row) {
System.out.printf("%8.3f ", element);
}
System.out.println();
}
}
Function to multiply two matrices
public static double[][] multiplyMatrices(double[][] A, double[][] B) {
// Get dimensions of matrices A and B
int m = A.length; // Number of rows in A
int n = A[0].length; // Number of columns in A (must equal rows in B)
int p = B[0].length; // Number of columns in B
// Check if multiplication is possible
if (n != B.length) {
System.out.println("Error: " +
"columns in the first matrix != rows in the second matrix.");
return null;
}
// Create the result matrix C (m x p)
double[][] C = new double[m][p];
// Perform matrix multiplication using loops over rows of A and columns of B
for (int i = 0; i < m; i++) {
for (int j = 0; j < p; j++) {
for (int k = 0; k < n; k++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
//Usage: double[][] AxB = multiplyMatrices(mat_A, mat_B);
Function to solve [A]{x} = {b} similar to mldivide function in MATLAB
public static double[] mldivide(double[][] A, double[] b) {
int n = A.length;
// Build augmented matrix [A | b]
double[][] aug = new double[n][n + 1];
for (int i = 0; i < n; i++) {
System.arraycopy(A[i], 0, aug[i], 0, n);
aug[i][n] = b[i];
}
// Forward elimination with partial pivoting
for (int k = 0; k < n; k++) {
// Pivot selection
int pivot = k;
for (int i = k + 1; i < n; i++) {
if (Math.abs(aug[i][k]) > Math.abs(aug[pivot][k])) {
pivot = i;
}
}
// Row swap
double[] temp = aug[k];
aug[k] = aug[pivot];
aug[pivot] = temp;
if (Math.abs(aug[k][k]) < 1e-12) {
throw new RuntimeException("Matrix is singular or ill-conditioned");
}
// Eliminate below pivot
for (int i = k + 1; i < n; i++) {
double factor = aug[i][k] / aug[k][k];
for (int j = k; j <= n; j++) {
aug[i][j] -= factor * aug[k][j];
}
}
}
// Back substitution
double[] x = new double[n];
for (int i = n - 1; i >= 0; i--) {
double sum = aug[i][n];
for (int j = i + 1; j < n; j++) {
sum -= aug[i][j] * x[j];
}
x[i] = sum / aug[i][i];
}
return x;
}
File and String Handling in Java
Example-1: check if a string start with a comment character.
import java.io.*
public class checkComment {
public static void main(String[] args) throws IOException {
String str = " # This is a comment line.";
boolean line_comment = is_comment(str, '#');
System.out.println(line_comment);
}
public static boolean is_comment(String str, char comment_char) {
// Function that returns true if a comment line is read from a file
// The comment character should be a single alphanumeric such as # or *
char c; boolean comment_line = false;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if ( c == comment_char ) {
comment_line = true;
break;
}
} return comment_line;
}
}Read CSV file with size known in advance
Example-2: read a csv file containing comment line(s).
import java.util.Arrays;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class csvToArray {
// Read a csv file separator by specified delimiter in 2d array. The
// size of array MUST be known in advance.
public static void main(String[] args) throws IOException {
// If "throws IOException" not present, "error: unreported exception
// FileNotFoundException; must be caught or declared to be thrown".
String file_name = "csvToArray.txt";
int max_rows = 4; int max_cols = 4; String delimiter = ",";
double [][] array_2d = new double[max_rows][max_cols];
BufferedReader buf_reader = new BufferedReader(new FileReader(file_name));
String line; int i = 0;
while((line = buf_reader.readLine()) != null) {
boolean comment_line = is_comment(line, '#');
if (!comment_line) {
String[] line_data = line.trim().split(delimiter);
if (line_data.length >= max_cols) {
System.out.println("Number of columns in input exceeds size of array!");
System.exit(0);
}
for (int j=0; j<line_data.length; j++) {
array_2d[i][j] = Double.parseDouble(line_data[j]);
} i = i + 1;
}
if (i >= max_rows) {
System.out.println("Number of rows in input exceeds size of array!");
System.exit(0);
}
}
System.out.println(Arrays.deepToString(array_2d));
buf_reader.close();
}
}Previous operation converted into a function
public static void main(String[] args) throws IOException {
String file_name = "csvToArray.txt";
double [][] array_2d = readDateFromText(file_name, ",", 5, 5);
System.out.println(Arrays.deepToString(array_2d));
}
public static double[][] readDataFromText(String file_name, String delimiter,
int max_rows, int max_cols) throws IOException {
double [][] array_2d = new double[max_rows][max_cols];
BufferedReader buf_reader = new BufferedReader(new FileReader(file_name));
String line; int i = 0;
while((line = buf_reader.readLine()) != null) {
boolean comment_line = is_comment(line, '#');
if (!comment_line) {
String[] line_data = line.trim().split(delimiter);
if (line_data.length >= max_cols) {
System.out.println("Number of columns in input exceeds size of array!");
System.exit(0);
}
for (int j=0; j<line_data.length; j++) {
array_2d[i][j] = Double.parseDouble(line_data[j]);
} i = i + 1;
}
if (i >= max_rows) {
System.out.println("Number of rows in input exceeds size of array!");
System.exit(0);
}
} buf_reader.close();
return array_2d;
}
List all files of specified extension
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
public class listFilesInFolder {
public static void main(String[] args) throws IOException {
File folder = new File("/home/Documents/XYZ");
//listFilesFolderSubFolders(folder);
String dir_path = "XYZ";
listFilesRootFolder(dir_path, "*");
}
public static void listFilesFolderSubFolders(final File folder) {
/*
This function prints the files of specified extension in folder and
its sub-folders. The absolute path in input argument should be of
type 'File'.
*/
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesFolderSubFolders(fileEntry);
} else {
System.out.println(fileEntry.getName());
}
}
}
public static void listFilesRootFolder(String dir_path, String extn) {
/*
This function prints the files of specified extension in folder with
relative to current working directory. The input argument should be
of type 'String'. It prints only the file names and not the paths. To
list all files, specify extension as "*".
*/
String cwd = Path.of("").toAbsolutePath().toString();
Path path_dir = Paths.get(cwd + "/" + dir_path);
File root_dir = new File (path_dir.toString());
// Get list_of_files as array
File[] array_of_files = root_dir.listFiles();
Arrays.sort(array_of_files);
for (File f : array_of_files) {
if (f.isFile()) {
// Find the last occurrence of '.' in the filename. One may use
// .endsWith(extn) but shall not work for all types of extensions
String f_name = f.getName();
int dotIndex = f_name.lastIndexOf('.');
String f_extn = (dotIndex > 0) ? f_name.substring(dotIndex + 1) : "";
if (new String("*").equals(extn)) {
System.out.println(f_name);
}
else if (f_extn.equals(extn)) {
System.out.println(f_name);
}
}
}
}
}
Getter and Setter
public class Person {
private String name; // private variable, restricted access
// Public getter method:
// Function = get added to 'name' variable with first letter capitalized
public String getName() {
return name;
}
// A corresponding setter method is often used to modify the variable
// Function = set added to 'name' variable with first letter capitalized
public void setName(String new_name) {
this.name = new_name;
}
}
The STAR-CCM+ user guide describes automation features available in STAR-CCM+ with many examples. There are some sample codes available online such as github.com/nitronayak/StarCCMAutomation
The first step in writing a JAVA macro for STAR CCM+ is to import the relevant packages. For example:
package macro; - similar to #include "udf.h"
import java.util.*; - similar to header files in C
import star.turbulence.*; - import turbulence model data
import star.common.*; import star.material.*;
import star.base.neo.*; import star.vis.*;
import star.flow.*; import star.energy.*;
import star.coupledflow.*;
// defineSim is the name of macro and the file name should be defineSim.java.
public class defineSim extends StarMacro {
public void execute() {
execute0();
}
//Get active simulation data
Simulation getSim = getActiveSimulation();
//Get domain named as FLUID and store it as 'cfd' - similar to Get_Domain in FLUENT UDF
Region cfd = getSim.getRegionManager().getRegion("FLUID");
//Set viscous model
PhysicsContinuum pC0 = (PhysicsContinuum) cfd.getContinuumManager().getContinuum("Physics 1");
pC0.enable(SteadyModel.class);
pC0.enable(SingleComponentGasModel.class);
pC0.enable(CoupledFlowModel.class);
pC0.enable(IdealGasModel.class);
pC0.enable(CoupledEnergyModel.class);
pC0.enable(TurbulentModel.class);
pC0.enable(RansTurbulenceModel.class);
pC0.enable(KEpsilonTurbulence.class);
pC0.enable(RkeTwoLayerTurbModel.class);
pC0.enable(KeTwoLayerAllYplusWallTreatment.class);
//Get boundary named INLET and velocity specification CLASS
Boundary b1 = cfd.getBoundaryManager().getBoundary("INLET");
VelocityProfile vP1 = b1.getValues().get(VelocityProfile.class);
//Specify velocity normal to boundary with specified "MAGNITUDE and DIRECTION"
//Note the word scalar in ConstantScalarProfileMethod.class
b1.getConditions().get(InletVelocityOption.class).setSelected(InletVelocityOption.MAGNITUDE_DIRECTION);
vP1.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(5.0);
//Inlet velocity by its COMPONENTS, note 'vector' in ConstantVectorProfileMethod.class
//b1.getConditions().get(InletVelocityOption.class).setSelected(InletVelocityOption.COMPONENTS);
//vP1.getMethod(ConstantVectorProfileMethod.class).getQuantity().setComponents(5.0, 0.0, 0.0);
//Set turbulence parameters - TURBULENT INTENSITY and VISCOSITY RATIO at INLET boundary
TurbulenceIntensityProfile TI = b1.getValues().get(TurbulenceIntensityProfile.class);
TI.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.02);
TurbulentViscosityRatioProfile TVR = b1.getValues().get(TurbulentViscosityRatioProfile.class);
TVR.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(5.0);
//Specify fluid temperature in [K] at INLET
StaticTemperatureProfile Tin = b1.getValues().get(StaticTemperatureProfile.class);
Tin.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(323.0);
//Get boundary named OUTLET and pressure boundary CLASS
Boundary b2 = cfd.getBoundaryManager().getBoundary("OUTLET");
StaticPressureProfile sP0 = b2.getValues().get(StaticPressureProfile.class);
//Specify static pressure at OUTLET boundary
b2.setBoundaryType(PressureBoundary.class);
sP0.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.0);
//Specify back flow turbulence parameters at OUTLET boundary
TurbulenceIntensityProfile TI2 = b2.getValues().get(TurbulenceIntensityProfile.class);
TI2.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.01);
TurbulentViscosityRatioProfile TVR2 = b2.getValues().get(TurbulentViscosityRatioProfile.class);
TVR2.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(2.0);
//Other options for reverse flow specifications
b2.getConditions().get(BackflowDirectionOption.class)
.setSelected(BackflowDirectionOption.EXTRAPOLATED);
b2.getConditions().get(BackflowDirectionOption.class)
.setSelected(BackflowDirectionOption.BOUNDARY_NORMAL);
b2.getConditions().get(ReversedFlowPressureOption.class)
.setSelected(ReversedFlowPressureOption.ENVIRONMENTAL);
b2.getConditions().get(ReversedFlowPressureOption.class)
.setSelected(ReversedFlowPressureOption.STATIC);
b2.getConditions().get(ReferenceFrameOption.class)
.setSelected(ReferenceFrameOption.LOCAL_FRAME);
b2.getConditions().get(ReferenceFrameOption.class)
.setSelected(ReferenceFrameOption.LAB_FRAME);
b2.getConditions().get(KeTurbSpecOption.class)
.setSelected(KeTurbSpecOption.INTENSITY_LENGTH_SCALE);
b2.getConditions().get(KeTurbSpecOption.class)
.setSelected(KeTurbSpecOption.INTENSITY_VISCOSITY_RATIO);
//Save SIM file by specifying full path - note double backslashes
getSim.saveState(resolvePath("C:\\STAR_CCM\\PipeFlow.sim"));
//Close the simulation scene
getSim.close(true);
}
// STAR-CCM+ macro: Macro.java, Written by STAR-CCM+ 14.02.012
package macro; import java.util.*;
import star.common.*; import star.base.neo.*; import star.segregatedflow.*;
import star.material.*; import star.turbulence.*; import star.rsturb.*;
import star.vis.*; import star.flow.*; import star.kwturb.*;
public class Macro extends StarMacro {
public void execute() {
execute0();
}
private void execute0() {
Simulation sim_0 = getActiveSimulation();
ImportManager IM_0 = sim_0.getImportManager();
IM_0.importMeshFiles(new StringVector(new String[] {resolvePath("D:\\STAR\\Venturi.ccm")}),
NeoProperty.fromString("{\'FileOptions\': [{\'Sequence\': 42}]}"));
FvRepresentation fvRep0 = ((FvRepresentation)
sim_0.getRepresentationManager().getObject("Volume Mesh"));
Region region_0 = sim_0.getRegionManager().getRegion("fluid");
fvRep0.generateCompactMeshReport(new NeoObjectVector(new Object[] {region_0}));
sim_0.getSceneManager().createGeometryScene("Geometry Scene", "Outline", "Geometry", 1);
Scene scene_0 = sim_0.getSceneManager().getScene("Geometry Scene 1");
scene_0.initializeAndWait();
PartDisplayer PD_0 = ((PartDisplayer) scene_0.getDisplayerManager().getDisplayer("Outline 1"));
PD_0.initialize();
PartDisplayer PD_1 = ((PartDisplayer) scene_0.getDisplayerManager().getDisplayer("Geometry 1"));
PD_1.initialize();
SceneUpdate sceneUpdate_0 = scene_0.getSceneUpdate();
HardcopyProperties hardcopyProperties_0 = sceneUpdate_0.getHardcopyProperties();
hardcopyProperties_0.setCurrentResolutionWidth(1600);
hardcopyProperties_0.setCurrentResolutionHeight(900);
scene_0.resetCamera();
sim_0.saveState("D:\\STAR\\Venturi.sim");
}
private void execute1() {
Simulation sim_0 = getActiveSimulation();
MeshManager MM_0 = sim_0.getMeshManager();
Region region_0 = sim_0.getRegionManager().getRegion("fluid");
MM_0.convertTo2d(1.0E-18, new NeoObjectVector(new Object[] {region_0}), true);
Scene scene_0 = sim_0.getSceneManager().getScene("Geometry Scene 1");
CurrentView currentView_0 = scene_0.getCurrentView();
currentView_0.setInput(new DoubleVector(new double[] {0.0, 0.0, 0.0}),
new DoubleVector(new double[] {0.0, 0.0, 1.0}),
new DoubleVector(new double[] {0.0, 1.0, 0.0}), 1.143640, 0, 30.0);
scene_0.resetCamera();
Region region_1 = sim_0.getRegionManager().getRegion("fluid 2D");
region_1.setPresentationName("FLUID");
Boundary BN_0 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region");
Boundary BN_1 = region_1.getBoundaryManager().getBoundary("cyclic 2");
MM_0.combineBoundaries(new NeoObjectVector(new Object[] {BN_0, BN_1}));
MM_0.splitBoundariesByAngle(89.0, new NeoObjectVector(new Object[] {BN_0}));
BN_0.setPresentationName("Axis");
Boundary BN_2 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region 2");
BN_2.setPresentationName("Outlet");
Boundary BN_3 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region 3");
BN_3.setPresentationName("Inlet");
Boundary BN_4 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region 4");
BN_4.setPresentationName("Wall");
PhysicsContinuum Cm_0 = ((PhysicsContinuum) sim_0.getContinuumManager().getContinuum("Physics 1"));
sim_0.getContinuumManager().remove(Cm_0);
PhysicsContinuum Cm_1 = ((PhysicsContinuum) sim_0.getContinuumManager().getContinuum("Physics 1 2D"));
Cm_1.setPresentationName("Physics 1");
Cm_1.enable(SteadyModel.class);
Cm_1.enable(SingleComponentLiquidModel.class);
Cm_1.enable(SegregatedFlowModel.class);
Cm_1.enable(ConstantDensityModel.class);
Cm_1.enable(TurbulentModel.class);
Cm_1.enable(RansTurbulenceModel.class);
Cm_1.enable(ReynoldsStressTurbulence.class);
ReynoldsStressTurbulence RSM_0 = Cm_1.getModelManager().getModel(ReynoldsStressTurbulence.class);
Cm_1.disableModel(RSM_0);
Cm_1.enable(KOmegaTurbulence.class);
Cm_1.enable(SstKwTurbModel.class);
Cm_1.enable(KwAllYplusWallTreatment.class);
sim_0.saveState("D:\\STAR\\Venturi.sim");
}
}
Create User Field Function
public class CreateUserFieldFunctions extends StarMacro {
public void execute() {
execute0();
}
private void execute0() {
Simulation sim_0 = getActiveSimulation();
UserFieldFunction uFF_0 = simulation_0.getFieldFunctionManager().createFieldFunction();
uFF_0.getTypeOption().setSelected(FieldFunctionTypeOption.SCALAR);
uFF_0.setPresentationName("R1");
uFF_0.setFunctionName("R1");
uFF_0.setDefinition("0.50");
UserFieldFunction uFF_1 = sim_0.getFieldFunctionManager().createFieldFunction();
uFF_1.getTypeOption().setSelected(FieldFunctionTypeOption.SCALAR);
uFF_1.setPresentationName("Radius");
uFF_1.setFunctionName("Radius");
x = $$Position[0]
y = $$Position[1]
uFF_1.setDefinition("sqrt(x*x + y*y)");
}
}
Application Productivity Tools (APT)
These are template files containing predefined settings for the mesh, physics, and post-processing scenes to save engineering time. One such template available in STAR-CCM+ is Turbo Aerodynamics Workflow.| Store common variables for mesh generation, boundary conditions, material properties, solver settings, post-processing and report generation in separate file. The constants and variables are stored in file simVars.java and the main function and methods are stored in file named solverSettingsSTAR.java. The two files need to be compiled together: javac solverSettingsSTAR.java simVars.java |
Variables to be copied into public void execute(). The variables are defined to be same as in PyFLUENT example and hence they can be use by removing the qualifier 'double' and semi-colons. The values are in default units (which is SI or MKS unless user has changed to any other such as FPS system). github.com/frkasper/MacroUtils/.../UserDeclarations.java is a good example to declare variables as per project specific requirements.
double max_cell_quality = 0.10;
double max_allowed_skew = 75.0;
double max_volm_change = 0.01;
// Boundary conditions
double[] gravity = { 0.0, -9.806, 0.0 };
double[] v_init = { 0.1, 0.0, 0.0 };
double radEmissivity = 0.80;
// Porous resistances
double i_res = 2500;
double v_res = 50;
// Solver settings
double n_iter = 4000;
double t_step = 1.0e-3;
double duration = 10.0;
double iter_per_step = 20;
double count_t_steps = duration / t_step;
// Reference and limiting values
double ref_den = 1.225;
double Tref = 300;
double t_max = 500;
double t_min = 273;
double p_min = 100;
Alternatively, a table can be defined such as one described below and a Java macro can be used to read and assign boundary conditions.
Zone_Name Type Material_Name Density Thermal_Conductivty Cp RPM LC_I LC_V ------------------------------------------------------------------------------------------------ Tubes Fluid Air 1.120 0.027 1005.5 0 0 0 ...Here LC_I and LC_V is applicable to porous zones. Similar table can be created for wall boundary types. |
| One can define ArrayList<String> bc_list = new ArrayList<String>(Arrays.list("inlet_1", "inlet_2", "wall_htc", "wall_rot", "outlet_p")); to create a list of names to be used in various functions. The list can be name of scenes, reports, plots, derived parts, planes, zone names... where each item can be access using get(i). |
Alternatively, following class/method can be used to read variables stored in a text file in the format var_name = var_value. '=' acts as delimiter. This way, one can use the data file created for other programming language such as Python. The important point to note the value decimal and integer values are interpreted. x = 300.0 - x will be classified as variable type 'double'. x = 300 - x will be categorized as variable type 'integer'. The format of data in 'input.txt' should be as var_name = var_value without any semi-colon at the end of the sentences.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class readDataFromFile {
public static void main(String[] args) {
String file_name = "input.txt";
Map<String, Object> variables = readVariablesFromFile(file_name);
// Print the variable names and their values and type
for (Map.Entry<String, Object> entry : variables.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue() +
" (" + entry.getValue().getClass().getSimpleName() + ")");
}
}
public static Map<String, Object> readVariablesFromFile(String file_name) {
Map<String, Object> variables = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new FileReader(file_name))) {
String line;
while ((line = reader.readLine()) != null) {
// Split the string in '2' parts with separator as '='
String[] parts = line.split("=", 2);
if (parts.length == 2) {
String var_name = parts[0].trim();
String var_value = parts[1].trim();
Object parsed_value = parseValue(var_value);
variables.put(var_name, parsed_value);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return variables;
}
private static Object parseValue(String value) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e1) {
try {
return Double.parseDouble(value);
} catch (NumberFormatException e2) {
// Default is string if not an integer or double
return value;
}
}
}
} |
Methods and Classes: uncomment/comment as needed.import java.util.*;
import star.common.*;
import star.base.neo.*;
import star.motion.*;
public class starMacroTemplate extends StarMacro {
public void execute() {
importCad_Mesh(Simulation simX);
generateSrfMesh(Simulation simX);
generateVolMesh(Simulation simX);
defineMatProps(Simulation simX);
defineBndConds(Boundary bndry);
solverSettings(Simulation simX);
defineMonitors(Simulation simX);
defineReports(Simulation simX);
generateReports(Simulation simX);
defineScenes(Simulation simX);
saveReptPlots(Simulation simX);
}
} |
private void importCad_Mesh() {
...
}
private void generateSrfMesh() {
...
}
|
private void generateVolMesh(simX) {
...
//Check and print mesh quality
MinReport min_cell_q = (MinReport) simX.getReportManager().getReport("minCellQuality");
MaxReport max_skew = (MaxReport) simX.getReportManager().getReport("maxCellSkewness");
}
|
Define a continuum model class, public static final Class<? extends Model>[] gas_models = new Class[] {
ThreeDimensionalModel.class,
SteadyModel.class,
SingleComponentGasModel.class,
CoupledFlowModel.class,
PolynomialDensityModel.class,
CoupledEnergyModel.class,
TurbulentModel.class,
RansTurbulenceModel.class,
KEpsilonTurbulence.class,
RkeTwoLayerTurbModel.class,
KeTwoLayerAllYplusWallTreatment.class,
RadiationModel.class,
S2sModel.class,
ViewfactorsCalculatorModel.class,
GrayThermalRadiationModel.class
};
|
Check if a model exists if(continuum.getModelManager().hasModel(SingleComponentGasModel.class) != null) {
for (Class<? extends Model> model_class : gas_models) {
if (continuum.getModelManager().hasModel(model_class) == null) {
return false;
}
return true;
}
|
Create continua public void createContinuum() {
PhysicsContinuum continuum = physicsContinuumCondition.getSatisfyingObject();
if (continuum != null) {
notifyUser("Continuum \"" + continuum.getPresentationName() + "\" already created");
return;
}
createContinuum(gas_models);
}
|
Define required solver models:
ppublic void enableModels(PhysicsContinuum pc) {
pc.enable(ThreeDimensionalModel.class);
pc.enable(SingleComponentLiquidModel.class);
pc.enable(SegregatedFlowModel.class);
pc.enable(PolynomialDensityModel.class);
pc.enable(GravityModel.class);
pc.enable(CellQualityRemediationModel.class);
pc.enable(PorousMediaModel.class);
pc.enable(ImplicitUnsteadyModel.class);
}
|
private double getZones(Simulation simX, String region_type) {
double cell_count = 0;
ElementCountReport el_count = simX.getReportManager()
.create("star.base.report.ElementCountReport.class);
Collection<Region> all_regions = simX.getRegionManager().getRegions();
Collection<Region> fluid_regions = simX.getRegionManager().getRegions();
Collection<Region> solid_regions = simX.getRegionManager().getRegions();
for (Region reg : all_regions) {
if (reg.getRegionType() instanceof FluidRegion) {
solid_regions.remove(reg);
if (!(reg instanceof ShellRegion)) {
solid_regions.remove(reg);
}
}
if (!(reg instanceof ShellRegion)) {
fluid_regions.remove(reg);
}
}
if(region_type == "fluid") {
el_count.getParts().setObjects("fluid_regions");
cell_count = el_count.getReportMonitorValue();
}
if(region_type == "solid") {
el_count.getParts().setObjects("solid_regions");
cell_count = el_count.getReportMonitorValue();
}
simX.getReportManager().remove(el_count);
return cell_count;
}
|
private static List<String> getFluidZones(Simulation simX) {
Collection<Region> all_regions = simX.getRegionManager().getRegions();
// List to store the names of fluid regions
List<String> fluid_regions = new ArrayList<>();
for (Region reg : all_regions) {
// if (reg.getPhysicsContinuum().getPresentationName().equals("Fluid")) {
if (reg.getRegionType() instanceof FluidRegion) {
fluid_regions.add(region.getPresentationName());
}
}
return fluid_regions;
}
|
private void defineMatProps() {
...
}
|
private void defineBndConds() {
//Create field functions
final double m_dot = 2.50;
UserFieldFunction UFF_mdot = (UserFieldFunction) simX.getFieldFunctionManager().
.getFunction("m_dot");
UFF_mdot.setDefinition(String.valueOf(m_dot))
}
public class SetInletBoundary(Simulation simX, Boundary bnd_name) {
public static void main(String[] args) {
//Simulation sim = getActiveSimulation();
//Region region = sim.getRegionManager().getRegion("region_name");
//Boundary inletBoundary = region.getBoundaryManager().getBoundary("b_inlet");
double b_inlet_v = 5.0; // [m/s]
double b_inlet_p = 500; // [Pa]
doulbe b_inlet_t = 300; // [K]
double b_inlet_mf = 0.25; // [kg/s]
int choice = 1;
switch (choice) {
case 1: // Set Velocity Inlet
InletBoundary v_mag = (InletBoundary) simX.get(ConditionTypeManager.class)
.get(InletBoundary.class);
bnd_name.setBoundaryType(v_mag);
VelocityMagnitudeProfile vmag_value = bnd_name.getValues.
.get(VelocityMangnitudeProfile.class);
Units un_v = (Units) simX.getUnitsManager().getObject("m/s");
vmag_value.getMethod(ConstantScalarProfileMethod.class).getquantity()
.setValueAndUnits(b_inlet_v, un_v);
break;
case 2: // Set Pressure Inlet
...
break;
case 3: // Set Mass Flow Inlet
MassFlowBoundary b_mf = (MassFlowBoundary) simX.get(ConditionTypeManager.class)
.get(MassFlowBoundary.class);
bnd_name.setBoundaryType(b_mf);
MassFlowRateProfile b_mf_value = bnd_name.getValues().
.get(MassFlowRateProfile.class);
Units un_mf = (Units) simX.getUnitsManager().getObjects("kg/s");
b_mf_value.getMethod(ConstantScalarProfileMethod.class).
getQuantity().setValueAndUnits(b_inlet_mf, un_mf);
break;
default:
System.out.println("Invalid choice!");
break;
}
TurbulenceIntensityProfile b_inlet_ti = bnd_name.getValues
.get(TurbulenceIntensityProfile.class);
b_inlet_ti.getMethod(ConstantScalarProfileMethod.class).getQuantity()
.setValue(2.0);
TurbulenceViscosityRatioProfile b_inlet_tvr = bnd_name.getValues
.get(TurbulenceViscosityRatioProfile.class);
b_inlet_tvr.getMethod(ConstantScalarProfileMethod.class).getQuantity()
.setValue(5.0);
sim.saveState("Setup.sim");
}
} |
Define boundary conditions on walls:
public class SetWallBC{
public static void main(String[] args) {
Simulation sim = getActiveSimulation();
Region region = sim.getRegionManager().getRegion("RegionName");
Boundary wallBoundary = region.getBoundaryManager().getBoundary("WallBoundary");
int choice = 1;
switch (choice) {
case 1: // Set Fixed Temperature
...
break;
case 2: // Set Known Wall Flux
...
break;
case 3: // Set HTC
...
...
break;
case 4: // Set Radiation
...
break;
default:
System.out.println("Invalid choice!");
break;
}
// Set Surface Roughness
...
// Enable Shell Conduction
...
sim.saveState("Setup.sim");
}
} |
Print Summary of Mesh Quality: STAR-CCM+ does not have option to print mesh quality one item at a time. That is, you cannot get skewness statistics (maximum, minimum...) alone but the full quality report can be generated by Diagnostics summary as explained here. To get the skewness of aspect ratio values, one need to use Field Function and Report. Step-1) create maximum and/or minimum report as required: MaxReport max_rep = sim_1.getReportManager .create("star.base .report .MaxReport"); Step-2) Create skewness or aspect ratio field function: SkewnessAngleFunction skew_ff = (SkewnessAngleFunction) sim_1.getFieldFunctionManager() .getFunction("SkewnessAngle"); // Use comination of CellAspectRatioFunction and CellAspectRatio as needed Step-3) Assign field function to the report: max_rep.setFieldFunction(skew_ff); Step-4) Assign region to the report: Region reg_x = sim_1.getRegionManager() .getRegion(reg_name); max_rep.getParts() .setObjects(reg_x); Step-5) Print the report in output log or store as a variable to save in a text file: max_rep.printReport(); public double getMaxSkewness(Simulation simX, Region region) {
MaxReport max_skew = simX.getReportManager .create("star.base .report .MaxReport");
SkewnessAngleFunction skew_ff = (SkewnessAngleFunction) simX.getFieldFunctionManager()
.getFunction("SkewnessAngle");
max_skew.setFieldFunction(skew_ff);
max_skew.getParts().setObjects(region);
max_skew.printReport();
}
|
private void summarizeZones(Simulation simX, Boundary bndry) {
Collection <Region> region_list = simX.getRegionManager().getObjects();
System.out.println("Number of regions in model = " + region_list.size());
for (Region region_i : region_list) {
Collection <Boundary> boundary_list = simX.getBoundaryManager().getObjects();
System.out.println("Number of boundarie in " + "region_i + " is " +
boundary_list.size());
}
Collection <Interface> iface_list = simX.getInterfaceManager().getObjects();
integer n_iface = 0;
for (Interface iface : iface_list) {
n_iface = n_iface + 1;
}
System.out.println("Number of interfaces in domain = " + n_iface);
// Ref: community.sw.siemens.com/.../getting-surface-area-using-java-api
// Create a Surface Integral Report of the unity field funcion and then
// use following lines to get or print on those boundaries.
SurfaceIntegralReport surf_int = (SurfaceIntegralReport) simX.getReportManager()
.getReport("Area");
double surf_area = surf_int.getValue();
simX.println(surf_area);
Boundary b_wall_x = reg.getBoundaryManager().getBoundary("Wall_Pipe");
surf_int.getParts().setObjects(b_wall_x);
simX.println("Area of boundary is " + area);
} |
private void solverSettings(Simulation simX) {
Simulation sim_1 = getActiveSimulation();
for (int i=1; i<=3; i++) {
sim_1.saveState("Case_" + i + ".sim");
...
StepStoppingCriterion stopCrit = (StepStoppingCriterion)
sim_1.getSolverStoppingCriterionManager()
.getSolverStoppingCriterion("Maximum Steps");
//Get max stopping criteria number and add additional iteration steps
IntegerValue iter_count = stopCrit.getMaximumNumberStepsObject();
double j = iter_count.getQuantity().getValue();
iter_count.getQuantity().setValue(j);
sim_1.getSimulationIterator().run();
}
// Save final sim file and exit
sim_1.saveState("Case_" + i + "_Full.sim");
}
} |
public class CreateMassBalanceMonitor {
Simulation sim = getActiveSimulation();
// Obtain the region object
Region region = sim.getRegionManager().getRegion(Region_Name);
// Create mass flow monitors for all inlets and outlets
MassFlowReport mass_flow_report_1 = sim.getReportManager()
.createReport(MassFlowReport.class);
mass_flow_report_1.setPresentationName("MF_inlets");
MassFlowReport mass_flow_report_2 = sim.getReportManager()
.createReport(MassFlowReport.class);
mass_flow_report_2.setPresentationName("MF_outlets");
for (Boundary boundary : region.getBoundaryManager().getBoundaries()) {
if (boundary.getBoundaryType() instanceof InletBoundary) {
mass_flow_report_1.getParts().addObjects(boundary);
} else if (boundary.getBoundaryType() instanceof OutletBoundary) {
mass_flow_report_2.getParts().addObjects(boundary);
}
}
// Calculate mass balance
ExpressionReport massBalanceReport = sim.getReportManager()
.createReport(ExpressionReport.class);
massBalanceReport.setPresentationName("Mass_Balance");
massBalanceReport.setDefinition(
"${MF_inlets.Report} - ${MF_outlets.Report}"
);
// Optional: Adding these reports to scalar and XY plots
MonitorPlot massFlowRatePlot = sim.getPlotManager().createMonitorPlot();
massFlowRatePlot.setPresentationName("Mass Flow Rate Plot");
massFlowRatePlot.getMonitorManager().addObjects(massFlowRateReportInlet,
massFlowRateReportOutlet);
MonitorPlot massBalancePlot = sim.getPlotManager().createMonitorPlot();
massBalancePlot.setPresentationName("Mass Balance Plot");
massBalancePlot.getMonitorManager().addObjects(massBalanceReport);
}
} |
private void generateReports(Simulation simX) {
String rept_file = "Rep_Output.txt";
PrintWriter out_file = new PrintWriter(new FileWriter(new File(resolvePath(rept_file))));
Collection <Report> report_list = simX.getReportManager().getObjects();
Iterator<Integer> rep_counter = report_list.iterator();
while (rep_counter.hasNext()) {
String report_name = report_list.next().getPresentationName();
double report_value = report_list.next().getReportMonitorValue();
String report_units = report_list.next().getUnits().GetPresentationName();
System.out.println(report_name + " has value " + report_value + " "
+ report_units();
}
} |
private void saveReptPlots(Simulation simX) {
String sep = System.getProperty("file.separator");
for (StarPlot p : simX.getPlotManager().getObjects()) {
simX.println("Data exported for plot: " + p.getPresentationName());
p.export(simX.getSessionDir() + sep + p.getPresentationName() + ".csv", ",");
}
}From github.com/nitronayak /StarCCMAutomation /blob /main /ExportScenesAndPlots.javaimport star.common.*;
import star.vis.*;
import java.io.File;
import java.util.Scanner;
public class ExportScenesAndPlots extends StarMacro {
public void execute() {
Simulation sim = getActiveSimulation();
//get the name of the simulation's directory
String dir = sim.getSessionDir();
//get the right separator for your operative system
String sep = System.getProperty("file.separator");
File resultFolder = new File(dir + "\\" + sim + "_Results");
resultFolder.mkdir();
File sceneFolder = new File(resultFolder + "\\Scenes");
sceneFolder.mkdir();
File plotFolder = new File(resultFolder + "\\Plots");
plotFolder.mkdir();
for (Scene scn: sim.getSceneManager().getScenes()) {
sim.println("Saving Scene: " + scn.getPresentationName());
scn.printAndWait(resolvePath(sceneFolder + sep + scn.getPresentationName() + ".jpg"), 1,800,450);
}
for (StarPlot plt : sim.getPlotManager().getObjects()) {
sim.println("Saving Plot: " + plt.getPresentationName());
plt.encode(resolvePath(plotFolder + sep + plt.getPresentationName() + ".jpg"), "jpg", 800, 450);
}
}
} |
Print materials defined in the set-up and their thermodynamic propertiespublic class printMatProps extends StarMacro {
public void execute() {
Simulation sim = getActiveSimulation();
Collection<Material> materials = sim.get(MaterialManager.class).getObjects();
for (Material mat : materials) {
String matName = mat.getPresentationName();
System.out.println("Material: " + matName);
Collection<MaterialProperty> properties = mat.getMaterialProperties();
for (MaterialProperty property : properties) {
String propertyName = property.getPresentationName();
double propertyValue = property.getValue();
System.out.println(" Property: " + propertyName + ", Value: " + propertyValue);
}
}
}
} |
public class CreateHistograms extends StarMacro {
public void execute() {
createHistogramsMeshQuality("CellQuality");
createHistogramsMeshQuality("Skewness");
}
private void createHistogramsMeshQuality(String quality_type) {
Simulation sim = getActiveSimulation();
RegionManager regionManager = sim.getRegionManager();
Collection<Region> allRegions = regionManager.getRegions();
List<Region> solidRegions = new ArrayList<>();
List<Region> fluidRegions = new ArrayList<>();
for (Region region : allRegions) {
// Check if region contains solid cells
if (region.getInterfaceBoundaryManager().getInterfaceBoundaries().size() > 0) {
solidRegions.add(region);
} else {
fluidRegions.add(region);
}
}
// Define the cell quality scalar field function
PrimitiveFieldFunction cellQualityFunction =
(PrimitiveFieldFunction) sim.getFieldFunctionManager().getFunction(quality_type);
// Create histograms for solid regions
for (Region solidRegion : solidRegions) {
createHistogram(sim, solidRegion, cellQualityFunction,
solidRegion.getPresentationName() + " " + quality_type + " Histogram";
}
// Create histograms for fluid regions
for (Region fluidRegion : fluidRegions) {
createHistogram(sim, fluidRegion, cellQualityFunction,
fluidRegion.getPresentationName() + " " + quality_type + " Histogram";
}
}
private void createHistogram(Simulation sim, Region region,
PrimitiveFieldFunction function, String plotName) {
// Create histogram report
HistogramReport histogramReport = sim.getReportManager()
.createReport(HistogramReport.class);
histogramReport.setFieldFunction(function);
histogramReport.getParts().setObjects(region);
histogramReport.setPresentationName(plotName);
// Create and display the plot
ReportPlot histogramPlot = sim.getPlotManager().createReportPlot(histogramReport);
histogramPlot.open();
}
} |
STAR-CCM+ java code as functions to generate scalar scenes on planes aligned to Cartesian coordinate systems passing though specified point, align the view perpendicular to the plane and save the plot as PNG file.
public void execute() {
// Specify the point through which the planes pass and field function and range
double[] point = {0.0, 0.0, 0.0};
double[] v_range = {0.0, 10.0};
double[] p_range = {1000, 1E6};
double[] t_range = {300, 400};
String scalarFieldFunctionName = "VelocityMagnitude";
createScalarSceneOnPlane("X", point, "Pressure", p_range);
createScalarSceneOnPlane("Y", point, "Temperature", t_range);
createScalarSceneOnPlane("Z", point, "Velocity", v_range);
}
private void createScalarSceneOnPlane(String planeAxis, double[] point,
String scalarFF, double[] scalarRange) {
Simulation sim = getActiveSimulation();
ScalarScene scalarScene = sim.getSceneManager().createScalarScene("Scalar Scene", "Scalar Scene");
scalarScene.initializeAndWait();
FieldFunction scalarFieldFunction = sim.getFieldFunctionManager().getFunction(scalarFF);
scalarScene.getDisplayerManager().getScalarDisplayers().get(0)
.getScalarDisplayQuantity().setFieldFunction(scalarFieldFunction);
// Set the number of color bands to 11
scalarScene.getDisplayerManager().getScalarDisplayers().get(0)
.getScalarDisplayQuantity().getColorMap().setNumberOfColors(11);
scalarScene.getDisplayerManager().getScalarDisplayers().get(0)
.getScalarDisplayQuantity().setRange(scalarRange);
// Create and set plane section
PlaneSection planeSection = (PlaneSection) sim.getPartManager().createImplicitPart(new
NeoObjectVector(new Object[] {}), new NeoObjectVector(new Object[] {}), "PlaneSection", 0, 0, 0, 0);
planeSection.getInputParts().setObjects(sim.getRegionManager().getRegions());
planeSection.getOriginCoordinate().setCoordinate(point[0], point[1], point[2]);
// Set plane normal based on the specified axis
if (planeAxis.equalsIgnoreCase("X")) {
planeSection.getOrientationCoordinate().setCoordinate(1, 0, 0);
} else if (planeAxis.equalsIgnoreCase("Y")) {
planeSection.getOrientationCoordinate().setCoordinate(0, 1, 0);
} else if (planeAxis.equalsIgnoreCase("Z")) {
planeSection.getOrientationCoordinate().setCoordinate(0, 0, 1);
}
// Add plane section to scalar scene
scalarScene.getDisplayerManager().getPartDisplayer("Scalar Scene 1")
.getInputParts().setObjects(planeSection);
// Align view perpendicular to the plane and zoom to fit window (reset camera)
if (planeAxis.equalsIgnoreCase("X")) {
scalarScene.open(true);
scalarScene.resetCamera();
scalarScene.getViewManager().getAxesOrientation().setCoordinateSystemView(
scalarScene.getActiveCamera(), CoordinateSystemViewType.XY);
} else if (planeAxis.equalsIgnoreCase("Y")) {
scalarScene.open(true);
scalarScene.resetCamera();
scalarScene.getViewManager().getAxesOrientation().setCoordinateSystemView(
scalarScene.getActiveCamera(), CoordinateSystemViewType.YZ);
} else if (planeAxis.equalsIgnoreCase("Z")) {
scalarScene.open(true);
scalarScene.resetCamera();
scalarScene.getViewManager().getAxesOrientation().setCoordinateSystemView(
scalarScene.getActiveCamera(), CoordinateSystemViewType.ZX);
}
String file_name = scalarFF + "_" + planeAxis + "_"+ point[0] + "_"point[1] +
"_" + point[2] + ".png";
scalarScene.printAndWait(resolvePath(file_name), 1, 800, 600);
scalarScene.close();
}
|
Process all *.sim files stored in a specified folder.
public class ProcessSimFiles {
public static void main(String[] args) {
// Folder containing the *.sim files
File folder = new File("E:/CFD_Projects");
String b_inlet = "inlet;
// List all .sim files in the folder
File[] files = folder.listFiles((dir, name)->name.toLowerCase().endsWith(".sim"));
if (files == null || files.length == 0) {
System.out.println("No .sim files found.");
return;
}
Simulation sim = getActiveSimulation();
for (File f : files) {
postProcesSim(sim, f, b_inlet);
}
}
private static void postProcesSim(Simulation sim, File file, String bnd_name) {
...
}
} |
Create Animation from a Transient Run
public void CreateAnimation (Simulation sim, double fps, Scene sc_name, String field_var) {
// Set up the time steps for the animation
SolutionHistory solutionHistory = (SolutionHistory) sim.get(SolutionHistoryManager.class)
.getObjects().iterator().next();
RecordedSolutionView recordedSolutionView = solutionHistory.getRecordedSolutionViewManager().createView();
recordedSolutionView.setMode(RecordedSolutionViewMode.DISPLAY_EVERY_STEP);
// Create an animation from the recorded solution view
Animation animation =
(Animation) sim.getRepresentationManager().createRepresentation(Animation.class, "Animation", "");
animation.setFramesFromView(recordedSolutionView);
// Set the scalar scene for the animation
Scene scene = sim.getSceneManager().getScenes().get(sc_name);
ScalarDisplayer scalarDisplayer =
(ScalarDisplayer) scene.getDisplayerManager().getDisplayer(field_var);
scalarDisplayer.setRepresentation(animation);
// Set the animation properties
animation.setFramesPerSecond(fps);
animation.setStartFrame(0);
animation.setEndFrame(recordedSolutionView.getLastFrame());
// Export the animation as a video
File animationFile = new File("STAR-animation.mp4");
File exportFile = new File(animationFile.getAbsolutePath());
sim.getAnimationExporterManager().exportVideo(animation, exportFile, "mp4");
}
} |
Create Sweep Animation of an XY-Plane
public void SweepAnimation (Simulation sim, Scene sc_name, double fps, double z0,
double zn, double dz) {
// Create a new XY-Plane section at origin
PartManager partManager = simulation.getPartManager();
plane_xy plane_xy = (plane_xy) partManager.createImplicitPart(new NeoObjectVector(
new Object[]{}), new DoubleVector(new double[]{0.0, 0.0, 1.0}),
new DoubleVector(new double[]{0.0, 0.0, 0.0}));
plane_xy.getOrientationCoordinate().setCoordinate(new DoubleVector(new double[] {0.0, 0.0, 1.0}));
plane_xy.getPositionCoordinate().setCoordinate(new DoubleVector(new double[] {0.0, 0.0, 0.0}));
plane_xy.getInputParts().setQuery(null);
// Add the plane section to the scene and set the displayer
sc_name.setInputParts(new NeoObjectVector(new Object[] {plane_xy}));
sc_name.open();
ScalarDisplayer scalarDisplayer = sc_name.getDisplayerManager()
.createDisplayer(ScalarDisplayer.class);
scalarDisplayer.getInputParts().setQuery(null);
scalarDisplayer.getInputParts().setObjects(plane_xy);
// Set up the animation properties
Animation animation = simulation.getRepresentationManager().createRepresentation(
Animation.class, "Sweep Animation", "");
animation.setFramesPerSecond(fps);
// Loop through the range and update plane position
for (double zp = z0; zp <= zn; zp += dz) {
plane_xy.getPositionCoordinate().setCoordinate(new DoubleVector(new double[] {0.0, 0.0, zp}));
sc_name.printAndWait();
animation.addFrame(scene);
}
// Export the animation as a video
File animationFile = new File("sweep_animation.mp4");
File exportFile = new File(animationFile.getAbsolutePath());
simulation.getAnimationExporterManager().exportVideo(animation, exportFile, "mp4");
}
} |
Create a tabulated summary of maximum temperature at the outer walls of each solid zone:
public double maxWallTemperature(Simulation simX, Region region_name) {
MaxReport max_t = simX.getReportManager().create("star.base.report.MaxReport");
PrimitiveFieldFunction ff_t = (PrimitiveFieldFunction)
simX.getFieldFunctionManager().getFunction("Temperature");
max_t.setFieldFunction(ff_t);
MeshPart part_1 = (MeshPart) simX.get(SimulationPartManager.class).getPart(region_name);
max_t.getParts().setObjects(part_1);
max_t.setPresentationName("max_wall_t");
Units deg_C = (Units) simX.getUnitsManager(0.getObjects("C");
max_t.setUnits(deg_C);
max_t.printReport();
}
|
The content on CFDyna.com is being constantly refined and improvised with on-the-job experience, testing, and training. Examples might be simplified to improve insight into the physics and basic understanding. Linked pages, articles, references, and examples are constantly reviewed to reduce errors, but we cannot warrant full correctness of all content.
Template by OS Templates