Cross-learning: FLUENT / CFX / STAR / COMSOL
This page is intended to enhance the learning one CFD software to another by providing similarities and difference in approach. The purpose it to help users learn new software when he/she is familiar with one, the purpose is not to rate any particular software.
Table of Contents: Surface Preparation | Mesh Generation | Mesh Quality Checks | Field Functions in STAR-CCM+ | Heat Exchangers Models | Java Macros | License Manager | Continua: Solver Setting | Surface wrapping and partial wrapping | Macro: Import STL, Generate Mesh | Post-Processing in STAR-CCM+ | Sample Java Codes for STAR-CCM+ | Mesh Generation using Macro
Fluids: the colour of fluid nodes change from gray to blue to indicate that fuid models have been activated and continuum is valid.
Solids: the colour of node changes from gray to shaded gray to indicate that models have been activated for this continuum.Regions in STAR-CM+ | Parts in STAR-CCM+ |
Computational domains in STAR-CCM+ are called Region where each region is completely surrounded by boundaries. Boundaries common between two regions can be joined with an interface allowing mass, momentum and energy to pass between the regions. | Parts in STAR-CCM+ are geometrical representation of Objects. Parts can be modified in different ways and used as input for meshing operation and the result of this meshing process gets placed in a region specified in advance. One or several parts can be used as input to one region. Contacts can be created for surfaces common between two parts which are transformed into interfaces when the parts are meshed into regions. |
Following table is an attempt to draw some similarities and analogies between various names and concepts used in CFD programs. However, there is no distinct boundaries and there are overlaps the way these designations refer to underlying objects and collectors.
Identifier | STAR-CCM+ | FLUENT | CFX | OpenFOAM / ParaView |
Solvers | Physics Continua | Viscous Model | - | Application |
Parts | Mesh Continua | Zones | Boundary | |
Regions | Continua | Cell Zones, Face Zones | Cell Zones, Face Zones | Blocks |
Domains | Continua | Cell Zones, Face Zones | Cell Zones, Face Zones | Blocks |
Boundaries | Cell Zones, Face Zones | Face Zones, Edge Zones | Boundary | |
Zones | Regions, boundaries | Boundary, Patch | ||
Case | Model | Case | Definition | Folder |
Scenes | Separate for Geometry, Mesh, Scalar, Vector | Common for Scalar and Vectors, Planes | Common for Scalar and Vectors, Planes | Views and Filters: Render View, Slice View... |
The terms used in this table are building blocks of a simulation which consists of physical space (3D volume designated as domain or region), boundaries of a volume (known as surface regions or face zones), solver types (known as viscous model or continua) and so on. A generic term which can be used for all the objects mentioned in above table is 'collector' which is a collection or group of different physical (nodes, faces...) objects and numerical (turbulence model, material properties ...) objects. Few additional terms used to describe the computational volume are walls, interfaces and contacts.
Excerpts from STAR-CCM+ User Manual: Parts-based meshing is a method for generating surface and volume meshes on geometry parts. It is different to region-based meshing in that it uses a series of mesh operations to define the process from the initial geometry to the final volume mesh. Having a series of operations allows you to modify the initial geometry and repeat the entire process with no additional inputs. This makes parts-based meshing particularly suitable for parametric design studies.
Geometry is defined in terms of geometry volume, surfaces, curves and points. The discretized geometry is defined in terms of body points (volumes), faces, edges and nodes / vertices. The collection of these entities are designated as 'parts' in ICEM CFD, zones in "FLUENT", "regions and boundaries" in STAR CCM+ and "Assembly, Primitive 2D, Primitive 3D" in CFX. The computational model to which physics can be applied is defined in terms of regions (domains or zones defined in FLUENT, CFX) and boundaries. Defining the simulation topology is the process of mapping between the geometrical definition of the problem and the computational (or physical) definition.
In STAR CCM+ geometry parts refers to volume which can be assigned to regions, part surfaces can be assigned to boundaries, and part curves can be assigned to objects called feature curves. This mapping is important if all the operations, CAD import till simulation is performed inside STAR CCM+ environment. If mesh is generated out of STAR-CCM+ environment, these operations need to be performed in that application which will also write output file compatible to STAR-CCM+ requirements. For a typical CFD analysis, simple geometries are usually imported in CAD or non-CAD formats (or in more scientific terms, discrete or tessellated formats), while complex geometries usually come in mixed or hybrid formats, containing both CAD and non-CAD parts.
You can import a surface or volume mesh from an external file via File > Import > Import surface mesh. During geometry import, a choice of centimeters (cm), feet (ft), inches (in), kilometers (km), meters (m) (default), miles (mi), millimeters (mm), micrometers (um) and yards (yd) is allowed. The selection determines the scale factor that is applied to the import surface to make it conform to SI (meters). For example, selecting millimeters automatically scales the vertices by 0.001. If a unit other than one listed was used for the surface file, select the meters option (equivalent to no scaling). After the import process is complete, you can apply a user-defined scaling factor to scale the mesh.
If a unit other than meters (m) was selected, then the option to Set preferred units for length is available (off by default). This option can be used to set the selected unit as the default for all mesh reference and input values that involve length. Leaving the option off maintains meters as the default unit for length.
Surface Repair Tool: This is a utility that allows to directly repair the part surface. It is easy to use and will highlight each error. But in case any geometry upstream isbe changed, one need to redo the repair manually, as it is not a pipelined operation. This utility is a good place to start after importing the geometry as it will show how many errors must be fixed and where they are and what type they are.
Find Similar: This features allows user to select a single body or a topology and find similar topologies within the entire assembly. Users can select and define one topology with a single click and then use the find similar feature to select all similar topologies to work with. Prior to adding the search tool, users had to handpick all the entity and right-click select the defeature option to remove the selected entity.Fill holes is an operation for preparing a geometry for an internal flow simulation by doing what the name suggests: capping and filling holes in the part. This is possible in 3D-CAD and the surface repair tool, but this operation lets you add it to an automated pipeline. Note there is no Apply button. First select the closed loop (manually or double click on one the edge elements) and then click the fill hole button.
Extract volume pulls an internal volume from a part, typically after Fill Holes or similar operation has been used to cap the openings to prepare the geometry for an internal flow simulation.
One of the most useful operations is that to replace a part. This operation makes swapping out a geometry part repeatable and traceable, unlike manually replacing the part by right clicking it in the tree.
Repairing Features: All feature curves that are required to represent the geometry needs to be correctly identified in the surface mesh. This process identifies feature errors - that is, edges that are features but are not represented as such, and edges that are incorrectly represented as features. Feature curves indicate where sharp edges exist and are listed under the Feature Curves node for each region. If the surface remesher operation is performed to improve the surface mesh quality, then including feature curves is necessary to preserve sharp edges and surface detail (such as imprints). If the feature curves are not included, then edges are rounded off and surface detail is lost.
Closing Gaps: Project vertices onto a set of faces to close a gap using "project selected vertices tool".
Duplicate Faces -- surface repair -- Merge/Imprint: The tool also lets you merge two or more overlapping (co-planar) surfaces or sets of faces. When using Merge/Imprint on a single part, the result is either a common shared surface or no surface at all (that is, the common area is removed). If there are multiple parts, the tool creates part contacts for the shared surface. Similarly, for feature curves belonging to the same parts, the tool can imprint two or more edges onto each other, effectively zipping them together. You can also imprint edges onto faces and imprint faces onto edges, depending on the requirement. No edge options are available when imprinting across multiple parts. In all instances, the faces or edges do not need to belong to a closed surface in order to use the tool.
Automatic repair tool can fix certain global surface problems that relate to bad quality, close proximity and/or intersections (pierced faces) at the push of a button. If you want to fill a large number of holes automatically or zip a large number of edges then you should use the hole filler and edge zipper tools respectively.
To capture the complex and intricate features of the geometry the mesh generation process utilizes contact prevention conditions, volumetric controls and the wrapper scale factor. Wrapped surface is then retriangulated using the surface remesher.
STAR-CCM+ offers 7 types of meshing models: [1] Tetrahedral - tetrahedral cell shape based core mesh, [2] Polyhedral* - arbitrary polyhedral cell shape based core mesh, [3] Trimmed - trimmed (Cartesian or cut-and-cell or snappyHexMesh) hexahedral cell shape based core mesh, [4] Thin Mesh - tetrahedral or polyhedral based prismatic thin mesh, [5] Extrduder Mesher, [6] Prism Layer Mesher and [7] Advancing Layer Mesh - polyhedral core mesh, with in-built prismatic layers that advance inward from a polygonal surface mesh.
*In STAR-CCM+, a special dualization scheme is used to create the polyhedral mesh from an underlying tetrahedral mesh, which is automatically created as part of the process. The polyhedral cells that are created typically have an average of 14 cell faces.Local Refinement
Excerts from User Guide: "Volumetric controls in the shapes of bricks (cuboids), spheres, cylinders, and cones can be used during the volume meshing of the core mesh to increase or decrease the local cell density. Arbitrary shaped volumes that are imported as parts can also be used to define the refinement volume. Feature refinement is automatically included in the case of the trimmer meshing model."
There are two meshing approach in STAR: parts-based meshing and region-based meshing. Parts-based meshing approach is recommended, though one need not always follow this approach to generate a mesh. For simple geometry and assemblies consisting of few sub-assemblies, one can import parts, assign parts to regions, then generate mesh at the regions level. However, if while working with assemblies that contain tens or hundreds of parts, parts-based meshing approach is recommended.
There is an option to use Automatic Surface Repair during Surface Remesher operation. This can help repair small errors in the surface, although it is not recommended for multi-volume models. Automatic Surface Repair cannot repair non-manifold edges or vertices or correct free edges.
Excerpts from User Guide: Parts-based meshing detaches the meshing process from physics modeling and provides a flexible and repeatable sequence of mesh operations. The sequence of mesh operations is called the meshing pipeline.
STAR-CCM+ also includes a comprehensive set of surface-repair tools that allow users to interactively enhance the quality of imported or wrapped surfaces, offering the choice of a completely automatic repair, user control, or a combination of both. One of the most important elements of surface repair tool is its diagnostics tool. It offers functionality to identify error prone parts, surfaces and feature edges and provide real time information via the browse tool as you fix them.
Operations – utilities that perform actions on 'Parts', Certain operations such as "extract volume", "surface wrapper" ... create new parts.
Directed meshing or swept meshing: Directed meshing allows you to generate a high-quality structured mesh by creating quadrilateral elements on a surface of a body and then sweeping them through its volume. It requires a Source Face, a Target Face, and the guide face along which the directed mesh is swept. A directed mesh is a Parts Based Meshing Operation. Identify the source and target faces. Highlight the source face and Right-click > Add to Source. Repeat for target face to Add to Target. Next, set up a new source mesh. Right-click Source Meshes > New Source Mesh > Patch Mesh. This brings up the patch mesh editor. Select the edges (feature curves) of the source face to generate quad elements as per desired refinement.
Once surface mesh on source face is ready, to create the volume distribution, Right-click Mesh Distributions > New Volume Distribution. In the Properties window for the volume mesh, set the number of layers to required refinement in sweep direction and then right-click Directed Mesh > Execute.
Generate and Display a Mesh
To generate a mesh: Right-click Geometry -> Operations and select New -> Automated Mesh. In the Create Automated Mesh Operation dialog: Select the zones or volumes from the Parts list. To specify the mesh settings: Right-click the Geometry -> Operations -> Automated Mesh -> Default Controls node and select Edit.... In the Default Controls dialog, set the desired parameters such as Base Size, Number of Prism Layers, Surface Curvature, Surface Proximity... To customize the mesh to modify the mesh settings only on specific surfaces: Right-click the Geometry -> Operations -> Automated Mesh -> Custom Controls node and select New -> Surface Control -> Right-click the Custom Controls -> Surface Control node and select Edit -> Update Minimum Surface Size and tick 'Disable' under Prism Layers.To display the mesh: Select the Scenes -> Geometry Scene 1 -> Displayers -> Geometry 1 node. In the properties window, activate (tick checkbox) Mesh to display the surface of the mesh. Right-click an empty part in the geometry display graphics area and select Apply Representation -> Volume Mesh.
Surface wrapping and partial wrapping: In addition to refining the surfaces of parts in the wrap, partial wrapping can be used to exclude selected parts or part surfaces from the wrap operation. Excluded parts from the wrap, the original tessellation of the those parts is passed through to the final wrap surface. Some geometries only require surface wrapping for a portion of their surface. The surface wrapper allows you to exclude part surfaces that you consider sufficiently well tessellated for subsequent mesh operations. In some cases wrapping the whole geometry is unnecessary and can defeature highly detailed part surfaces unless the surface wrapper is excessively refined using custom controls and contact preventions. Select the Geometry > Operations > Surface Wrapper node and activate the "Perform Partial Wrapping".
Per-part meshing feature of "surface wrapping" operation allows multiple disconnected parts to be wrapped separately. The Minimum Size value indicates the triangle size in the space between the two parts, which determines the octree refinement in the area. The value should be set smaller than the gap size (typically one half or one quarter of the distance). It is just a stopping size for the surface wrapper refinement, which results in the two surfaces being separated.
Surface wrapping process steps:
There are two categories of interfaces in STAR-CCM+ and any interfaces that are created during the simulation setup process are accessible via the Interfaces manager node. The Interfaces node has properties and a pop-up menu.
Interface Types determines the behavior of the interface with respect to the modeling of flow and heat transfer. Interfaces can connect individual boundaries (faces) or entire regions (volumes). Following interface types and connectivity are available in STAR-CCM+
Type | Connects to | Topology | Connectivity |
Baffle | Boundaries | Direct Interface | Imprinted |
Porous Baffle | Boundaries | Direct Interface | Imprinted |
Contact | Boundaries | Direct Interface | Imprinted |
Fan | Boundaries | Direct Interface | Imprinted |
Fluid Film | Boundaries | Direct Interface | Imprinted |
Fully Developed | Boundaries | Direct Interface | Imprinted |
Internal | Boundaries | Direct Interface | Imprinted |
Mapped Contact | Boundaries | Indirect Interface | Mapped |
Mixing Plane | Boundaries | Indirect Interface | Connect Average |
Blower | Boundaries | Indirect Interface | Connect Average |
Heat Exchanger | Regions | Heat Exchanger Topology | Modeled |
Overset Mesh | Regions | Overset Mesh Topology | Modeled |
Note that "creating an interface" is not same as "converting boundaries to an interface". While "converting boundaries to an interface" single and usually common boundary belonging to a surface mesh is duplicated and then an interface made between the original and the copy for the primary purpose of defining multiple regions for meshing. To create an interface between boundaries, select the two boundaries that define the interface. The first boundary selected is termed the master boundary and the second is called the slave boundary.
Imprint is a process of making a common boundary between two volumes. If two square blocks are touching each other, there are two faces, one each belong to each square. When imprint is performed, the one of the common surface is deleted. The imprint operation will result into entity known as 'contacts' in STAR, and may become interfaces when parts are transferred to regions. Four types of contact definition exists: In-place, Weak in-place (meshed non-conformally), Periodic, Baffle. Part-part contacts may be created (a) automatically during geometry import, (b)by imprinting, (c)by tolerance based searching and (d)manually. STAR-CCM+ allows to imprint parts non-conformally. This process is useful when:
The compact report for a volume mesh generates statistics for each mesh region having following sub-sections: Entity count, Mesh extents, Mesh validity check, Face validity statistics and Volume change statistics.
The full diagnostics report is structured in a similar way to the compact report and contains all the information the compact report produces with following extra items for each region and the overall summary: Boundary details, Entity count per cell shape, Volume range (the minimum and the maximum volumes of an element in entire domain), Maximum interior skewness angle. The boundary details are split up as Number of faces, Boundary extent, Surface area and Maximum boundary skewness angle. To check if the volume mesh has zero or negative volume cells, either run the mesh diagnostics report or initialize the solution. Cells havin ≥ 0 volumes can be identified and visualized using threshold values.
Face quality is a measure of similarity between a face and the ideal face shape which is an equilateral triangle. The surface diagnostics calculate face quality = "in-circle radius / circumcircle radius" x 2. For an equilaterl triangle, in-circle radius * 2 = circum-circle radius. Thus, face quality '0' is degenerate triangle and 1 is the ideal shape. Default value of poor element setting in STAR-CCM+ is 0.01. The other definition in STAR-CCM+ as used in Surface Remesher is that quality of a triangle = the ratio of the triangle face area to the area of an equilateral triangle that would exactly fit inside the circumcircle of the triangle. The default value for surface remesher is 0.05
Dihedral angle of an edge is the angle between its adjacent faces. Edges are considered invalid if they are free or non-manifold as a dihedral angle cannot be calculated for such edges.
Removing Invalid Cells tool allows to remove mesh cells from the volume mesh region definition based on one or more of the following 4 mesh criteria: Face Validity, Cell Quality, Volume Change and Contiguous Cells. STAR-CCM+ moves all the removed cells into a separate region that is not used in the analysis. Symmetry plane boundaries are automatically added to the neighboring cell faces of cells that have been removed, minimizing the impact of these removed areas on the solution. Cells that do not meet the provided criteria are moved into a new region called Cells deleted from [Region] where [Region] is the name of continuum which these deleted cells belong to.
The polygonal patch filler is a quick and easy way of closing arbitrary shaped holes which do not have a closed loop definition and/or are not planar. The process literally 'patches' up the surface by creating faces that cover the hole area completely. Having an overlap in the patched surface is perfectly acceptable as the wrapper deals with this overlap automatically.
Compute Volumes: Right click on 'Reports' in the simulation tree and selecting New Report > User > Sum. To compute the volume, select 'Volume' as the scalar field function and the Volume Mesh as the representation. Further, only the (3D) region of interest needs to be selected under parts and not its boundaries. When a boundary is selected, the report includes the volume of those cells that touch the surface. This can result in double counting of cells in the report resulting in a value larger than the actual volume.
Excerpts from User Guide: Assigning parts to regions creates a relationship between the meshed part and the physics region where part-level objects (parts, part surfaces, and part curves) are associated to their equivalent region-level objects (regions, boundaries, and feature curves). This action allows STAR-CCM+ to convert the volume mesh to a finite volume representation that the solver can use to obtain a solution. These assignments do not need to be one-to-one. That is, you can assign multiple part-level objects to the same region-level objects.
If Steady State option is selected, Eulerian Multiphase model would not be available. Lagrangian Multiphase gets active only when Liquid or Gas and flow as Coupled or Segregated are selected.
Set Boundary Conditions
Follow the tutorial "Multi-Part Solid: Graphics Card Cooling" to understand creation of a Multi-Part Solid physics model, which allows multiple solid parts in a single continuum.File Auto Save in STAR-CCM+
For transient simulations as well as steady state simulations, intermediate bak-up results files need to be created and monitored. To set auto-save option: Main Menu > File > Auto Save: Under "Max Autosaved Files" set it 10. Under the node Update, tick Enbaled and update field appropriately.To overwrite same set-up file (the one used to start the run), use "Max Autosaved Files = 0" with the option "Autosave Batch Run" selected.Create Monitors in STAR-CCM+
Monitors such as heat balance of pressure drop between inlet to outlet are recommended to monitor for convergence. If reports named "Pressure Inlet", "Pressure Outlet", "HTR_Hot" and "HTR_Cold" are created, corresponding field functions are generated for each report, allowing to be used in an expression. Create an Expression report -> Rename this report to "Heat Balance" -> Click (Custom Editor) in the Definition property -> In the "Heat Balance" - Definition dialog, enter (${HTR_HotReport} - ${HTR_ColdReport}) -> Right-click the "Heat Balance" node and select Create Monitor and Plot from Report. To be able to visualize the cells with high residuals, enable the option "Temporary Storage Retained" for the solver under 'Properties' window.Stopping Criteria in STAR-CCM+
Automatically generated stopping criteria cannot be deleted, but the Enabled property can be activated or deactivated.Options exist to create stopping criteria based on monitors already defined. The node of a monitor-based stopping criterion has properties just like the automatically generated ones.The monitor-based convergence check and stopping criteria can be used to identify possible divergence or unrealistic results early during the simulation thereby reducing HPC cores and license usage. For example, area-averaged pressure or temperature can be monitored on key planes or walls and if the value exceeds some unreasonably high value say 0.5 [MPa] or 500 [K], the solution should be stopped immediately. This is important when runs are made on a cluster with queueing of large number of tasks. The simulation shall get terminated as soon as divergence conditions emerge and result files shall get saved as well. Note that ANSYS FLUENT does not save any file if divergence occurs."Time (s), "Temperature (C)" 0, 25 2, 50 5, 75Read .csv file using File option above.
Field Functions in STAR-CCM+
Field functions are mathematical expressions to define boundary conditions, material properties and booleans. Few basic rules that applies to creating Field Functions in STAR are described below.From User's Guide: Examples of Field Function Mesh Refinement - The following examples show mesh refinement using the trimmed, polyhedral, and tetrahedral mesher. The field function refines the mesh in areas where turbulence kinetic energy is greater than 4.0 [J/kg]: Trimmed Cell Mesher: ($TurbulentKineticEnergy > 4)? 0.1 : 0, Polyhedral Mesher: ($TurbulentKineticEnergy > 4)? 0.1 : 1.2*pow($Volume, 1/3), Tetrahedral Mesher: ($TurbulentKineticEnergy > 4)? 0.1 : 2*pow($Volume, 1/3)
Reference: "Simulation of Hypersonic Flowfields Using STAR-CCM+" by Peter G. Cross and Michael R. West, Aeromechanics and Thermal Analysis Branch, Weapons Airframe Division. ${CellRefinement} = (${cellDelP} > ${CellRefineThreshold}) ? 1 : (${cellDelP} < ${CellCoarsenThreshold}) ? -1 : 0. This expression sets the cell refinement flag to 1 if the pressure differential across the cell is > the user-specified refinement threshold, or to -1 if the differential is < the coarsening threshold. Otherwise, the flag is set to zero. Here ${cellDelP} = ${magGradP} * ${CellSize}, ${magGradP} = mag(grad( ${AbsolutePressure} )) and ${CellSize} = pow(${Volume}, 1/3).
The updated cell size is computed such that the change in cell size (before any limiting) does not exceed a factor or two: ${RefinedCellSize} = max(min((${CellRefinement} > 0) ? ${CellSize}/2 : (${CellRefinement} < 0) ? ${CellSize}*2 : ${CellSize},${MaxCellSize}), ${MinCellSize}).
Thus, the size of cells marked for refinement is cut in half, while cells marked for coarsening are doubled in size. These updated cell sizes are further limited to fall within user-specified maximum and minimum cell sizes. These limits prevent excessive refinement or coarsening of the mesh, and should be specified as suitable for any given problem. This limited refined cell size is then extracted into an 'internal' table and then used to specify the new cell size in the refined mesh.
The weakness is that this technique results in excessive refinement of the prism mesh in the boundary layer, even if these cells have not been flagged for refinement. This extra refinement comes as a result of how the cell size is computed based on an isotropic assumption, which is not appropriate for highly anisotropic cells.
The previous reference provides a solution to excessive refinements (including unnecessary refinement of prism layers) where cells are flagged for refinement based upon a normalized pressure differential: ${cellNormDelP} = ${magGradP}*${CellLength} / ${AbsolutePressure}. Here, the pressure differential is computed based upon a cell length, instead of an average cell size. This cell length approximately corresponds to the largest dimension of a cell. ${CellLength} = pow(${Volume} / ${CellAspectRatio}, 1/3) * (-1.0 * pow(${CellAspectRatio}, 3) + 1.0 * pow(${CellAspectRatio}, 2) - 0.68 * ${CellAspectRatio} + 1.68). When flagging cells for refinement, an extra condition is introduced that prevents cells with aspect ratios below a user-defined threshold from being refined: ${CellNormRefinement} = (${cellNormDelP} > ${CellRefineNormThreshold}) ? ((${CellAspectRatio} < $PrismLayerRefineThreshold) ? 0 : 1) : (${cellNormDelP} < ${CellCoarsenNormThreshold}) ? -1 : 0
Finally, the refined (or coarsened) cell sizes needs to be computed for the flagged cells based on the cell length of the previous mesh: ${CellSizeNormRefined} = max(min((${CellNormRefinement} > 0) ? ${CellSize}/2 : (${CellNormRefinement} < 0) ? ${CellSize}*2 : ${CellLength}, ${MaxCellSize}), ${MinCellSize}).Adaptivity Criterion
Reference: m4-engineering.com/simcenter-star-ccm-adaptive-mesh-refinement - "In order to refine the mesh, the solver needs to have some criteria on when to either coarsen or refine an element. For this example, change in vorticity is ideal for tracking the vortex sheet as it transverses downstream. The value is scaled by the element size to ensure that there is a bias to refine larger elements and keep or coarsen smaller elements. The expression is: mag(grad( mag($${VorticityVector}) )) * {$AdaptionCellSize}"Heat Exchangers Models in STAR-CCM+
Heat Exchangers models are used to replicate the transfer of heat between two fluid streams - hot fluid and cold fluid. Applications include air conditioner evaporators, condensers, charge air coolers, radiators, electric heaters, and electronic devices. There are two options available:
STAR-CCM+ Lite can be used to post-process the results of a simulation that were solved using STAR-CCM+ (ccmpsuite). STAR-CCM+ Lite can be used to run the simulation for further iterations providing all models are available in STAR-CCM+ Lite including Java macros that were generated by STAR-CCM+ (ccmpsuite). However, if the macro activates any models that are not permitted under the STAR-CCM+ Lite license, the simulation shall fail to run.
The stopping criteria in STAR is not incremental. That means, if stopping criteria is set to 4000 iterations and that many iterations are already completed, this value needs to be increased to 5000 when you modify (such as change inlet velocity) the *.SIM file and want to make additional 1000 iterations. In batch runs, the output of the program can be saved to a file: starccm+ -batch mySim.sim > log.text. For work in the interactive (GUI) client, check the option: Menu bar > Tools > Options > Environment > Log output to File.
As described in the user manual, Design Manager has two possible ways to submit: "General Job Submission" and "Pre-Allocation Job Submission". Single run (No Design Manager) - The single run submission is for cases where only a single simulation without the use of Design Manager is submitted. To submit to the cluster, the sim file and any macros are to be uploaded all in the same directory.
The parallel batch (non-interactive or non-GUI) runs on local machines can be made using command line or from shell/batch files such as: [1]When batch or shell script and *.sim files are in same folder --- starccm+ -np 32 -batch javaFile.java simFile.sim [2]When batch or shell script and *.sim files are in different folders --- starccm+ -np 32 -batch javaFile.java folder1/sub-folder1/simFile.sim. starccm+ -batch geoImport.java, geoClean.java, geoReanme.java, mesh, step, run - multiple commands within the -batch argument can be specified, three macros are run in order before running the mesh pipeline, step and the solver.
If the properties in the simulation file are correctly set, many batch simulations can be run using the default operations with no java file: starccm+ -batch myCase.sim. For example, reports, auto-save, auto-export, and scene hardcopies can all be specified in the simulation properties. Command line to open the STAR-CCM+ workspace, start a new simulation, and play a macro: starccm+ -new -m macro.java Batch mode for macros is run from the command line using the -batch option: starccm+ -batch macro.java myCase.sim. This option runs STAR-CCM+ with a script (macro.java in the above example). The -batch option ensures that no GUI is displayed. If you do not want the server process to exit once the batch file has completed, then add the -noexit option to the command line.
Set File parameter from command line using -param command-line option. Change global parameter values without opening the GUI: Use the .ini input file to supply multiple parameter values at once.
The mesh generation in parallel is not scalable linearly, that is the speed-up is not proportional to the increase in number of cores (CPUs). Refer the image below from official documents:CHECKPOINT and ABORT: STAR-CCM+ runs can be aborted (saved at current iteration and exit the run) by creating a blank 'ABORT' file in home directory. A blank CHECKPOINT file shall save the simulation file at current iteration and let the run continue as per convergence setting.
Multiple Simulations Consecutively
Multiple simulation files can be loaded and run consecutively using a single macro. The following sample macro looks for all the .sim files in a specified directory, then for each simulation file it starts a server, iterates, and saves to a new filename. Use the command line: starccm+ -batch runMultiple.java. Save the macro as runMultipleCases.java and upload *.sim files along with this Java macro.
package macro; import java.io.*; import star.base.neo.*; import star.common.*; public class runMultipleCases extends StarMacro { // Create a file filter 'SimFileFilter' to list only *.sim files public class SimFileFilter implements FilenameFilter { //Test if a specified file should be included in a file list public boolean accept(File dir, String name) { return name.endsWith(".sim"); } } public void execute() { // For runs on a cluster, folder path may not be known in advance // Change "." to local folder while running on a local host File simDir = new File("."); Simulation sim_0 = getActiveSimulation(); sim_0.kill(); for (File f : simDir.listFiles(new SimFileFilter())) { startAndRun(f); } } public void startAndRun(File f) { System.out.println("\n Starting "+f); String fileName = f.getAbsolutePath(); Simulation sim_i = new Simulation(fileName); sim_i.getSolution().clearSolution(); sim_i.getSimulationIterator().run(); String nuName = fileName.replaceAll(".sim", "-new.sim"); sim_i.saveState(nuName); sim_i.kill(); } }Refer the tutorial "Solution Recording and Playback: Vortex Shedding" to know about recording solution histories, animating them and many other features of STAR. Node named "Simulation Operations" under Tools can be used to design a set of commands like meshing, running physics, setting different parameter value, clear solution, saving simulation, exporting scenes... though the options are applicable within the same simulation (*.sim) file.
The plots in STAR are generated using scenes which are collection of 2 objects - Displayers and Outline. (a)Outline can be used to select section plane, boundary faces and edges (b)Scalar or vector - the actual component of contour plot - here again parts need to be selected on which contour plots are to be generated and (c)Attributes - this refers to features available to control the generation and display of the plots. In ANSYS Fluent as on V2021 R2, separate plots for mesh and scalar need to be generated. Then a scene needs to be manually created where required mesh plot and scalar plot can be combined which makes it close to the concept of Scenes used in STAR.
To visualize the solution: Right-click the Scenes node and select New Scene > Scalar. To visualize streamlines in STAR-CCM+, following steps are required: Create a scene. Create a streamline derived part. Add a streamline displayer, with suitable properties, to the scene created earlier based on the streamline derived part. Specify Seed Mode, Specify Direction: Forward or Forward and BackWard. Select the Displayers > Section Stream 1 node to customize how the streamlines appear: Set the Mode to Tubes > Set Orientation to Normals > Specify width of the tubes in meters. To extend the streamlines through the fluid domain up to the outlet, increase the maximum propagation property at Derived Parts > streamline > 2nd Order Integrator node.To animate streamlines: Click scene/plot > Edit the Displayers node > Streamline Stream 1 > Animations > Animation Mode > Tracers. Displayers > Streamline Settings > Delay between tracers (sec), Head size, Tail Length (sec)
Section Planes and Reports
The post-processing planes can be created under Derived Part tab in the Model Tree. Quantitative values such as area-averaged pressure needs to be defined under Reports tab in the Model Tree. The convergence history charts are available under tab Plots.Delete a report: While trying to delete a report from a sim file, following message shall appear: "<report name> is being used by another object and cannot be deleted". This means there are other objects in the simulation tree such as monitors and plots that are dependent on the report being removed. Clicking on the Details button shows the dependencies and gives the user the option to delete the report along with all the dependent objects, "Delete All" button.
Add Annotations: Expand the Tools > Annotations node and drag the appropriate node into the scene. Available built-in options are: Iteration, Logo, Scene, Solution Time, Time Step. The "Time Step" or "Solution Time" annotations are useful to track progress of transient simulations or creating animations to show time on each frame. Annotation gets added to the bottom left of the scene. One can add the annotation to a plot or a scene by drag-and-drop annotations from Tools > Annotations directly into scenes. Alternatively,for a scene, the annotations are found under Scene > Attributes > Annotations. Report annotations can be used to display values calculated by report on the graphical displayers in a scene.
License Manager: LMTOOLS
Most of the CFD programs be it ANSYS FLUENT or STAR-CCM+ use LMTools to manage the licenses at their customers. The executable utility is installed in the same folder where main program such as ANSYS FLUENT is installed. The syntax to use LMSTAT is: lmstat [-a] [-c license_file_list] [-f [feature]] [-i [feature]] [-s[server]] [-S [vendor]] [-t timeout_value]. The purpose of each option is:Finding Names of Feature: to use -f option, one need to know the exact names of feasures. This can be found in license.dat file or check the output from -a options. lmutil.exe lmstat -s licServers -f "feature_name"
For scripting and partial automation of pre-processing, solver and post-processing activities, refer to this section of scripting page.
For dealing with file handling in Linux and Windows, refer to short summary of shell scripting.
In JAVA, class name should always be the same as file name. 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".
public class macroX extends StarMacro { ... }: A class called macroX is declared, and is specified as a subclass of the StarMacro class. public: informs the Java compiler that there are no access restrictions on this class, class: keyword to define a class, macroX: name of the class [must match the name of the file containing the class], extends: indicates that the class is derived from another class (and inherits all the public and protected methods of that class), StarMacro: name of the base class from which this one is derived.
public void execute() { executeX(); }: The main method, execute(), is declared. When the macro is run in STAR-CCM+ it uses execute(), which calls executeX(). Instread of writing every line of code within execute(), other methods can be used as shown below:
public void execute() { genVolMesh(); applyBC(); makeRun(); } void genVolMesh() { ... } void applyBC() { ... } void makeRun() { ... }
Summary of Java Programming relevant to STAR-CCM+ automation: case-sensitive, line terminated by semi-colon, // is single line comment, /* ... */ is multi-line comment, Member: variable belonging to a class, Method: subroutine belonging to a class, Instance Variable: variable contained in an object, Method Variable: subroutine contained in an object, Constructor: used to create new objects, dot operator is used to access field / variables / methods in a class object. Angle brackets, like html tags, containing one or more variables (separated by commas) refers to unspecified [declaring classes that use the generic type construct] type names: for example Collection<Part> allDerivedParts = pm_0.getObjects(); @Override annotation specifies the compiler that the method after this annotation overrides the method of the parent class: child method must have the same name and parameter(s) as in the parent class. Languages like C, Java, and C++ require parenthesis '( ... )' around an entire expression when used in loops like if, while, or switch. A function need not be defined prior to accessing it so long the function and the calling statements are in same file. For each loop is shortened by using ':' such as "for (String strg : string_list)" is equivalent to "for each strg (which is of type String) in string_list". Double colon :: is called method reference operator.
The demonstation Java file used above can be access here.
The @ symbol denotes a Java Annotation, attributes in C# which adds a special attribute to the variable, method, class, interface... the most common annotation is @Override, which indicates that a method is declared in a superclass.
import star.base.report.ScalarReport - here star.base.report is a package and ScalarReport is the class which has constructor ScalarReport(ClientServerObject key). Here, ClientServerObject is a class in package star.base.neoInheritance, like in dictionary meaning of heritage or act of inheriting property, refers to the concept of one object or class acquiring all the properties and behaviors of a parent object or class. It is a method to create new classes based on existing ones, reuse the methods and fields of parent class and if required add new fields and methods to newly created child class. The keyword 'extends' is used for inheritance in Java. A new object is created as: objName instanceName = new objName(); note that objName is repeated, once without () and once with (). For example, Employees supervisors = new Employees(); Hashtable class provide key-value data structure like tuple and dictionaries in Python.
java.util.*: This Java package contains classes and interfaces designed to facilitate storing and manipulating groups of objects. This family of related interfaces and classes is called the Java collections framework.
When a wildcard is used in import statement, such as "import star.common.*", it does not include classes from subpackages. In other words, it imports classes directly only within the specified package. To include classes from a subpackage, they must be explicitly imported separately: for example "import star.common.graph.DataSet;". Ref: community.sw.siemens.com/s/.../macro-to-loop-through-internal-data-set-of-xy-plot
Some statements are put inside parentheses (...) and child classes are accessed with dots. The parentheses shown in bold fonts are optional and any space, tab, newline or combination of these characters are allowed before dot oprators: PhysicsContinuum pc = ( (PhysicsContinuum) sim_1 .getContinuumManager() .getContinuum("Physics 1") ); In other words, any statement between a curly brace and semi-colon (;) or between semi-colon to next semi-colon are considered valid.
Try..Catch Loop: Almost all the programming languages have options for Exception Handling which are useful to handle cases when an error occurs, or 'exception' as it is referred as, the program or code stops and generates an error message. These exceptions are handled using the try ... catch statement in Java similar to try ... except block in Python.
try { ...codes... } catch (IOException err) { sim_1.println("An error occurred while ..."); err.printStackTrace(); }
A loop can be created over methods also: Runnable[] methods = {class_A:: method_A, class_B:: method_B, class_C:: method_C}; int i = 1; To run the require method: methods[i].run(); Normally the macro waits till the command is finished running. However, in case of complex problems requiring large memory and graphics power, the execution may jump to next statment before previous one is completed. This problem may occur with scenes where scene_x.initializeAndWait() can be used to circumvent this problem.
Java built-in methods for built-in arrays: compare(), copyOf(), deepEquals(), equals(), fill(), mismatch(), sort(). Property 'length' returns the length of an array. Build-in methods for ArrayList, a resizable array: add(), addAll(), clear(), clone(), contains(), ensureCapacity(), forEach(), get(), indexOf(), isEmpty(), iterator(), lastIndexOf(), listIterator(), remove(), removeAll(), removeIf(), replaceAll(), retainAll(), set(), size(), sort(), spliterator(), subList(), toArray(), trimToSize(). Create an ArrayList object called 'employees' that will store strings: ArrayList<String> employees = new ArrayList<String>();
Java built-in methods for files: canRead(), canWrite(), createNewFile(), delete(), exists(), FileFilter(), FilenameFilter(), getAbsolutePath(), getName(), getParent(), getParentFile(), getPath(), isDirectory(), isFile(), length(), list(), listFiles(), mkdir()
How to use the macros described here? Common variables have been used in all the statements. Search for the variable such as zone name or boundary name for their definitions. The statements are listed as per simulation workflow though may not 100% comply with any specific sequence of GUI-based operations. Java macro in STAR-CCM+ can be used with standard Java functions and customized function for STAR. For example, getObject method, which is the most commonly used method for retrieving an object from within the repository, requires understanding of hierarchy in STAR-CCM+ repository. When using this method, one must fetch actual (Java) objects. To access attributes from that object, wrap the object in an invocation that calls the object’s getter methods. STAR-CCM+ Java API has getObjects() method which returns collection of objects. getModelManager() is used to get attributes of an object such as PhysicsContinuum.
Like API documents for Java programming itself such as "docs.oracle.com/javase/8/docs/api", STAR-CCM+ has its API available through Main Menu -> Help -> Java API. However, this document is not for beginners and does not contain any examples (they are not meant to serve purpose of textbooks or tutorials but act more like an index or dictionaries).Format and names of classes and methods in STAR-CCM+ are similar: for exampe get***Manager() where *** represents various components of simulation.
get|Continuum |Manager(), get|Region |Manager() get|Model |Manager(), get|Scene |Manager() get|PassiveScalar |Manager(), get|Table |Manager() get|Representation|Manager(), get|Report |Manager() get|Boundary |Manager(), get|Plot |Manager()and so on.
The understanding of method to create an object in Java is critical to understand how macro can be developed for STAR-CCM+ such as: Creating object using 'new' keyword: className obj_name = new className();
Creation of object in STAR: Units un_deg = (Units) sim_1.getUnitsManager( ).getObject("deg"); Notice the similarity and difference between standard Java method and that followed in STAR-CCM+ macros.
Get reference to active simulation: Simulation sim_1 = getActiveSimulation(); Print message in output log window: sim_1.println("\n Starting run for case " + "i");
Global Constants: Math.PI, Provided by java.lang.Math class can be used to access π e.g. deg2rad = angle * Math.PI/180; or use field functions: UserFieldFunction uff_pi = sim_1.getFieldFunctionManager() .createFieldFunction(); uff_pi.setPresentationName("Pi"); uff_pi.setFunctionName("Pi"); uff_pi.setDefinition("3.1416");
Play a macro from within a macro: new StarScript(sim_1, new java.io .File(resolvePath( "createCsvReport.java" ))) .play();
Define Unit Vector: Units un_1 = sim_1.getUnitsManager( ).getPreferredUnits( new IntVecor( new int[] {...} ) ) which is equivalent to following lines of code.
Units un_len = sim_1 .getUnitsManager() .getPreferredUnits( new IntVector( new int[] {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ) );
Units un_mm = (Units) sim_1.getUnitsManager().getObject("mm")); The 'UnitsManager' object through the call to 'getPreferredUnits' is used to find the 'Units' object that represents the default units in the active simulation. The value 0 or 1 are exponent to variables in the order Mass, Length, Time, Temperature, Current, Luminosity, Quantity, Angle, Temperature Difference, Solid Angle, Force, Energy, Power, Pressure, Velocity, Angular Velocity, Volume...
To set units of a variable into degree: Units un_deg = (Units) sim_1.getUnitsManager( ) .getObject("deg"); Units un_angle = sim_1.getUnitsManager( ) .getPreferredUnits( Dimensions .Builder() .angle(1) .build() ); Units un_len = sim_1.getUnitsManager( ) .getPreferredUnits( Dimensions .Builder() .length(1) .build() ); Units un_pr_pa = (Units) sim_1.getUnitsManager( ) .getObject( "Pa" ); sim_1.getUnitsManager( ) .getSystemOption( ) .setSelected( UnitsManagerSystemOption .SYSTEM_USCS ); Units for density: Units un_den = sim_1.getUnitsManager( ) .getPreferredUnits( new IntVector( new int[] {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0}) );
Creating units using dimension builder: HTC.setDimensions( Dimensions .Builder() .length(-2) .temperature(-1) .power(1) .build() );
Create Dimensionless Unit: Units un_dim_less = sim_1.getUnitsManager() .getPreferredUnits( new IntVector( new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) ); Applicable to variables like Pressure Coeffcients, Drag Coefficients... Units un_celsius = (Units) sim_1.getUnitsManager() .getObject("C");
Pre-Processing
Create Import Manager: ImportManager im_1 = sim_1.getImportManager();
Import STL mesh: im_1.importStlSurface(resolvePath("D:\\Projects\\Geom.stl"), "OneBoundaryPerPatch", un_1, true, 1.0E-8);
Import a CAD Part:: PartImportManager p_im_mgr = sim_1.get(PartImportManager.class); p_im_mgr. importCadPart(reolvePath("D:\\Projects\\Geom.stp"), "SharpEdges", 30.0, 3, true, 1.0e-5, true, false, false, false, true, NeoProperty.fromString("{\'STEP\': 0, \'NX\': 0, \'CATIAVS\': 0, \'SE\': 0, \'JT\': 0}"), true, false);
Getting the name of the root directory or current working directory: String root_dir = sim_1.getSessionDir(); Get the right separator as per OS: String sep = System.getProperty("file.separator");
Create a folder and/or file: Files.createDirectories( Paths.get(root_dir + "/field_data") ); File f_out = new File(resolvePath( "Output.csv" )); FileReader f_reader = new FileReader(f_in); BufferedReader b_reader = new BufferedReader(f_reader); Scanner f_scan = new Scanner(b_reader) .useLocale(Locale.ENGLISH); Define delimiter for .csv format: f_scan.useDelimiter(","); Get name of a file: f_in.getName(); Delete a file: f_in.delete(); Check if a file exists: f_out.exists();
Get name of the current sim file: String sim_file = sim_1.getPresentationName();
Define variables - all values are assumed to be in SI units: double holeDia; double TubeLength = 0.25; boolean isUnSteady = true; String TurbulenceModel = "RANS-kOmega"; int numPrismLayers = 10;
Generate Volume Mesh: MeshPipelineController v_mesh = sim_1.get( MeshPipelineController.class ); v_mesh.generateVolumeMesh();
Select imported part for Mesh Generation: CadPart cadPart_1 = (CadPart) sim_1.get(SimulationPartManager.class) .getPart("Geom");
Apply mesh operation on a CAD part: AutoMeshOperation autoMeshCad = (AutoMeshOperation) sim_1.get(MeshOperationManager .class) .createAutoMeshOperation(new String [] {"star.resurfacer .ResurfacerAutoMesher"}), new NeoObjectVector( new Object[] {cadPart_1});
Create mesh continuum:
MeshContinuum meshCont = sim_1.getContinuumManager().createContinuum (MeshContinuum.class); meshCont.enable(ResurfacerMeshingModel.class); meshCont.getReferenceValues() .get(BaseSize.class) .setValue(2.0);
Define mesh sizes: autoMeshCad.getDefaultValues() .get(BaseSize.class) .setValue(0.1); autoMeshCad.getDefaultValues .get(BaseSize.class) .setUnits(un_1);
Automesh: AutoMeshOperation autoMesh = (AutoMeshOperation) sim_1.get(MeshOperationManager .class) .getObject("Automated Mesh"); autoMeshOperation .execute();
Translate Mesh: sim_1.getRepresentationManager() .translateMesh( new NeoObjectVector( new Object[] {zone_htx}), new DoubleVector( new double[] {0.0, del_y, 0.0} ), new NeoObjectVector( new Object[] {un_mm, un_mm, un_mm}), CartCS );
Rotate Mesh: sim_1.getRepresentationManager() .rotateMesh( new NeoObjectVector( new Object[] {zone_mrf}), new DoubleVector( new double[] {0.0, 0.0, 1.0}), new NeoObjectVector( new Object[] {un_mm, un_mm, un_mm}), rot_angle, CartCS);
At this stage, it is useful to have a macro which prints all the mesh operations and refinements that are present in the simulation. This could be the step to make statistics about mesh as a more automated process. One may try following lines to print sample information:
MeshContinuum meshContinuum = (MeshContinuum) sim_1.getContinuumManager() .getContinuum("Mesh 1"); Collection<Object> mesh_obj = meshContinuum .getModelManager() .getChildren(); String mesh_ops = mesh_obj.toString();
Define Boundary Conditions
Get a fluid region: Region zn_1 = sim_1.getRegionManager() .getRegion("air_domain");
Change the name of a continuum from "Physics 1" to 'air_domain': PhysicsContinuum pc_1 = (PhysicsContinuum) sim_1.getContinuumManager() .getContinuum("Physics 1"); pc_1.setPresentationName("air_domain"); To delete a continuum: sim_1.deleteObjects(new NeoObjectVector(new Object[] {air_domain})); Add a region to a continuum: air_domain.add(zn_1);
Contextual Focus to expand the physics model manager node and collapse other nodes: selectAndExpandNodeExclusive( pc_1.getModelManager() ); To exapand a node without affecting other open nodes, use selectAndExpandNode. To expand material property node: selectAndExpandNode( gas_0.getMaterialProperties() .getMaterialProperty( DynamicViscosityProperty .class ) .getMethod());
Set Coupled Solver: CoupledFlowModel coupledFlow = pc_1.getModelManager() .getModel(CoupledFlowModel .class); coupledFlow.getCoupledInviscidFluxOption() .setSelected(CoupledInviscidFluxOption .ROE_SCHEME);
Enable Solvers: pc_1.enable( SteadyModel .class ); pc_1.enable( SingleComponentGasModel .class ); pc_1.enable( CoupledFlowModel .class ); pc_1.enable( IdealGasModel .class ); pc_1.enable( CoupledEnergyModel .class ); pc_1.enable( TurbulentModel .class ); pc_1.enable( RansTurbulenceModel .class ); pc_1.enable( KOmegaTurbulence .class ); pc_1.enable( SstKwTurbModel .class ); pc_1.enable( KwAllYplusWallTreatment .class );
Turn ON Radiation: pc_1.enable(GrayThermalRadiationModel .class); GrayThermalRadiationModel gray_radiation = pc_1.getModelManager() .getModel(GrayThermalRadiationModel .class); RadiationTemperature T_rad = gray_radiation.getThermalEnvironmentManager() .get(RadiationTemperature .class); T_rad.getEnvRadTemp() .setValue(500.0);
Get name of a zone: Boundary bz_i = zn_1.getBoundaryManager() .getBoundary("inlet");
Define Material Properties - Density: pc_1.enable(ConstantDensityModel .class); SingleComponentGasModel single_gas_model = pc_1.getModelManager() .getModel(SingleComponentGasModel .class); Gas gas_0 = (Gas) single_gas_model.getMaterial(); ConstantMaterialPropertyMethod constant_density = (ConstantMaterialPropertyMethod) gas_0.getMaterialProperties() .getMaterialProperty( ConstantDensityProperty .class) .getMethod(); constant_density.getQuantity() .setValue(1.225);
Define Incompressible Ideal Gas: IdealGasModel idealGas = pc_1.getModelManager() .getModel(IdealGasModel .class); idealGas.setIncompressible(true);
Define Constant Value or Sutherland Model for Viscosity: SingleComponentGasModel gas_model = pc_1.getModelManager() .get_model(SingleComponentGasModel .class); Gas gas_0 = (Gas) gas_model.getMaterial(); gas_0.getMaterialProperties() .getMaterialProperty( DynamicViscosityProperty .class) .setMethod(SutherlandLaw .class); ConstantMaterialPropertyMethod visc = ConstantMaterialPropertyMethod gas_0.getMaterialProperties( DynamicViscosityProperty .class ) .getMethod(); visc.getQuantity() .setValue(1.716e-5);
Define Polynomial Density for a Liquid: SingleComponentLiquidModel liq_density = pc_1.getModelManager() .getModel( SingleComponentLiquidModel .class); Liquid water = (Liquid) liq_density.getMaterial(); TemperaturePolynmial poly_density = (TemperaturePolynmial) water.getMaterialProperties() .getMaterialProperty( PolynomialDensityProperty .class) .getMethod();
Define Reference Pressure: Units un_pr_atm = (Units) sim_1.getUnitsManager() .getObject( "atm" ); pc_1.getReferenceValues() .get(ReferencePressure .class) .setUnits(un_pr_atm); pc_1.getReferenceValues() .get(ReferencePressure .class) .setValue(1.0);
Change name of boundary: bz_i.setPresentationName("mf_inlet");
VelocityProfile vp_1 = bz_i.getValues() .get( VelocityProfile.class ); vp_1.getMethod( ConstantVectorProfileMethod .class) .getQuantity( ) .setComponents(10, 0, 0);
Mass Flow Profile: Boundary b_mf_in = zn_1.getBoundaryManager() .getBoundary( "mf_in" ); MassFlowRateProfile mf_p = b_mf_in.getValues() .get(MassFlowRateProfile.class); mf_p.getMethod( ConstantScalarProfileMethod.class ) .getQuantity() .setValue( 0.5 ); Use StaticPressureProfile.class and Constant ScalarProfileMethod.class to get and set pressure boundary conditions.
Get interface boundary: BoundaryInterface b_iface = (BoundaryInterface) sim_1.getInterfaceManager() .getInterface( "fin_air" );
Change an internal wall to interface: InternalInterface int_face = (InternalInterface) sim_1.get( ConditionTypeManager.class ) .get( InternalInterface.class ); b_iface.setInterfaceType(int_face);
Change an interface face to Baffle Interface: BaffleInterface baf_iface = (BaffleInterface) sim.get( ConditionTypeManager.class ) .get( BaffleInterface.class ); b_iface .setInterfaceType(baf_iface);
Specify Symmetry Boundary: Boundary b_sym = zn_1.getBoundaryManager() .getBoundary("Symmetry"); b_sym.setBoundaryType( SymmetryBoundary.class );
Specify Heat Sources: Region region_hs = sim_1.getRegionManager() .getRegion("hs_solid"); HeatSourceProfile hs_profile = region_hs.getValues().get(HeatSourceProfile .class); Units un_kW = (Units) sim_1.getUnitsManager().getobject("kW"); hs_profile.getMethod( ConstantScalarProfileMethod .class) .getQuantity() .setUnits(un_kW); hs_profile.getMethod( ConstantScalarProfileMethod .class) .getQuantity() .setValue(0.10);
Create Cartesian Coordinate System: LabCoordinateSystem labCS_cart = sim_1.getCoordinateSystemManager( ) .getLabCoordinateSystem( ); CartesianCoordinateSystem CartCS = labCS_cart.getLocalCoordinateSystemManager( ) .createLocalCoordinateSystem( CartesianCoordinateSystem .class, "Cartesian"); Coordinate originCS = CartCS.getOrigin( ); Units un_cs = (Units) sim_1.getUnitsManager( ) .getObject( "m" ); originCS.setCoordinate(un_cs, un_cs, un_cs, new DoubleVector(new double[] {0.1, 0.2, 0.0}));
Create Cylindrical Coordinate System: LabCoordinateSystem labCS_cyl = sim_1 .getCoordinateSystemManager( ) .getLabCoordinateSystem( ); CylindricalCoordinateSystem CCS = labCS_cyl .getLocalCoordinateSystemManager( ) .createLocalCoordinateSystem( CylindricalCoordinateSystem .class, "Cylindrical" ); CCS.setBasis0( new DoubleVector( new double[] {0.0, 1.0, 0.0}) );
Set Gradient Model: GradientsModel gradModel = pc_1.getModelManager() .getModel( GradientsModel.class ); gradMode.getGradientMethodOption() .setSelected( GradientMethodOption.GAUSS_GRADIENTS );
Set Translational Motion: TranslatingMotion v_x = sim_1.get(MotionManager.class) .createMotion(TranslatingMotion .class, "Translation"); Units un_v_x = sim_1.getUnitsManager() .getInternalUnits( new IntVector(new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0})); v_x.getTranslationVelocity() .setDefinition("$$x_v");
Rotating and Translating Reference Frame: UserRotatingAndTranslatingReferenceFrame rot_trans_ref_frame = (UserRotatingAndTranslatingReferenceFrame) sim_1.get( ReferenceFrameManager .class) .getObject( "Rotating And Translating" ); rot_trans_ref_frame.getTranslationVelocity() .setComponents(0.0, v_trans_y, 0.0); MotionSpecification motion_zone = zone_mrf.getValues() .get( MotionSpecification.class ); motion_zone.setReferenceFrame( rot_trans_ref_frame );
Add rotation: RotatingMotion rot_X = (RotatingMotion) sim_1.get(MotionManager.class) .getObject("Rotation"); SuperposingRotatingMotion rot_Y = (SuperposingRotatingMotion) rot_X.getSuperposingMotionManager() .getObject( "Pitch" );
Create Field Monitor: FieldMeanMonitor FMM = sim_1.getMonitorManager() .createMonitor( FieldMeanMonitor.class ); FMM.getParts() .setQuery(null); FMM.getParts() .setObjects(zn_1); FMM.setFieldFunction( "FF name" ); FMM.setPresentationName( "Monitor Name" );
Set S2S radiation parameters: PatchPerBFaceProportion n_patch_face = zn_1.getValues(getPatchPerBFaceProportion .class); PatchPerBFaceLeaf n_patch_per_leaf = n_patch_face.getModelPartValue(); n_patch_per_leaf.setValue(20.0); SharpAngle sharp_angle = zn_1.getValues() .get(SharpAngle .class); sharp_angle.setSharpAngle(175.0);
Calculate View Factorfor S2S Radiation Model: ViewfactorCalculationSolver VFcalc = (ViewfactorCalculatorSolver) sim_1.getSolverMananger() .getSolver(ViewfactorCalculation.class); VFcalc.generatePatches(); VFcalc.calculateViewfactors(); VFcalc.displayViewfactorSummary();
Define Porous Boudary Conditions
porous_1.setRegionType(PorousRegion.class); //Set inertial resistances PorousInertialResistance porousIR = porous_1.getValues().get(PorousInertialResistance.class); ScalarProfile IR_0 = porousIR.getMethod(PrincipalTensorProfileMethod.class).getProfile(0); IR_0.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(2500); ScalarProfile IR_1 = porousIR.getMethod(PrincipalTensorProfileMethod.class).getProfile(1); IR_1.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.500); ScalarProfile IR_2 = porousIR.getMethod(PrincipalTensorProfileMethod.class).getProfile(2); IR_2.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(50.0); //Set viscous resistances PorousViscousResistance porousVR = porous_1.getValues().get(PorousViscousResistance.class); ScalarProfile VR_0 = porousVR.getMethod(PrincipalTensorProfileMethod.class).getProfile(0); VR_0.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(500); ScalarProfile VR_1 = porousVR.getMethod(PrincipalTensorProfileMethod.class).getProfile(1); VR_1.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(5.5); ScalarProfile VR_2 = porousVR.getMethod(PrincipalTensorProfileMethod.class).getProfile(2); VR_2.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(7.5);
Solver Settings
Clear solution: sim_1.getSolution().clearSolution();
Initialize Field Variables: InitialPressureProfile p0 = pc_1.getInitialConditions() .get( InitialPressureProfile .class); p0.getMethod( ConstantScalarProfileMethod .class) .getQuantity() .setUnits(un_pr); p0.getMethod( ConstantScalarProfileMethod .class) .getQuantity() .setValue(p_0); StaticTemperatureProfile T0 = pc_1.getInitialConditions() .get( StaticTemperatureProfile.class); T0.getMethod( ConstantScalarProfileMethod .class) .getQuantity() .setValue(T_0); VelocityProfile V0 = pc_1.getInitialConditions() .get( VelocityProfile .class); V0.getMethod( ConstantVectorProfileMethod.class ) .getQuantity() .setComponents(u_0, v_0, z_0); StaticTemperatureProfile T_bnd_1 = bnd_1.getValues() .get( StaticTemperatureProfile .class ); T_bnd_1.getMethod( ConstantScalarProfileMethod .class) .getQuantity() .setValue(T_b_1);
Set Relaxation Factors: SegregatedFlowSolver segregated_solver = (SegregatedFlowSolver) sim_1.getSolverManager() .getSolver( SegregatedFlowSolver .class ); VelocitySolver velocity_solver = segregated_solver.getVelocitySolver( ); velocity_solver.setUrf(0.50); PressureSolver pressure_solver = segregated_solver.getPressureSolver(); pressure_solver.setUrf(0.25);
Set Maximum and Mimimum Allowable Temperature: pc_1.getReferenceValues() .get(MaximumAllowableTemperature .class) .setValues(1000.0); pc_1.getReferenceValues() .get(MinimumAllowableTemperature .class) .setValues(273.0);
Set Discretization Scheme: ImplicitUnsteadySolver implicit_uss = (ImplicitUnsteadySolver) sim_1.getSolverManager() .getSolver(ImplicitUnsteadySolver .class)); implicit_uss.getTimeStep() .setDefinition( "$del_t/50" ); implicit_uss.getTimeDiscretizationOption() .setSelected(TimeDiscretizationOption .SECOND_ORDER);
Set expert parameters: CoupledImplicitSolver cpl_ImpSolver = (CoupledImplicitSolver) sim_1.getSolverManager() .getSolver( CoupledImplicitSolver .class); cpl_ImpSolver .getExpertInitManager() .getExpertInitOption() .setSelected( ExpertInitOption .GRID_SEQ_METHOD); cpl_ImpSolver .getRampCalculatorManager() .getRampCalculatorOption() .setSelected( RampCalculatorOption .LINEAR_RAMP); LinearRampCalculator linRampCalc = (LinearRampCalculator) cpl_ImpSolver .getRampCalculatorManager() .getCalculator(); linRampCalc .setEndIteration( n_RampIters ); linRampCalc.setInitialRampValue( n_RampStart ); cpl_ImpSolver .getSolutionDriverManager() .getExpertDriverOption() .setSelected( ExpertDriverOption .EXPERT_DRIVER); cpl_ImpSolver .setCFL( max_CFL );
Get time step of an unsteady simulation: double dt = (ImplicitUnsteadySolver) sim_1.getSolverManager() .getSolver(ImplicitUnsteadySolver.class) .getTimeStep() .getValue();
Set stoping criteria: StepStoppingCriterion ssc = (StepStoppingCriterion) sim_1.getSolverStoppingCriterionManager() .getSolverStoppingCriterion( "Maximum Steps" ); ssc.setMaximumNumberSteps(75); ssc.setIsUsed( true ); PhysicalTimeStoppingCriterion maxTimeStopCrit = (PhysicalTimeStoppingCriterion) sim_1.getSolverStoppingCriterionManager() .getSolverStoppingCriterion( "Maximum Physical Time" ); while( ssc.getIsSatisfied() ); can be used to check if stopping criteria is reached or not.
Set Update Frequency: AutoSave auto_save = sim_1.getSimulationIterator() .getAutoSave(); StarUpdate star_update = auto_save.getStarUpdate(); star_update.getUpdateModeOption() .setSelected(StarUpdateModeOption .ITERATION); IterationUpdateFrequency iter_update_freq = star_update.getIterationUpdateFrequency(); iter_update_freq.setIterations( 500 ); For transient runs: deltaTimeUpdateFrequency delTimefreq = star_update.getDeltaTimeupdateFrequency(); LogicUpdateEven logicUpEvent = delTimefreq.getLogicUpdateEvent(); RangeMonitorUpdateEvent rangeMonitorUpdateEvent_0 = (RangeMonitorUpdateEvent) logicUpEvent.getUpdateEventManager() .getUpdateEvent("AutoSave .StarUpdate .DeltaTime .LogicEvent .StopEvent"); un_up_time = (Units) sim _1.getUnitsManager() .getObject("s"); rangeMonitorUpdateEvent_0.getRangeQuantity() .setValueAndUnits(600.0, un_up_time);
Statement to run the simulation: change the number of iterations that the batch job runs: sim_1.getSimulationIterator( ).step( 2000 );
At this stage, it is good to have a macro which creates summary of settings: For example, cfd-online.com/.../if-model-enabled-java-macro.html:
Collection <Object> models = sim_1.physicsContinuum .getModelManager() .getChildren(); String Modelnames = models.toString(); Collection <Region> region_list = sim_1.getRegionManager() .getObjects();
Utility Examples
Create Collection of Entities: To collect geometry parts - Collection<GeometryPart> parts_list = sim_1.getGeometryPartManager() .getLeafParts(); To collect regions: Collection<Region> region_list = sim_1.getRegionManager() .getRegions(); To collect boundaries: Collection<Boundary> bnd_list = region_1.getBoundaryManager().getBoundaries(); To collect interfaces: Collection<Interface> int_faces = sim_1.getInterfaceManager() .getObjects(); Collection<GeometryPart> parts_list = getSimulation() .get(SimulationManager .class) .getParts();
The page community.sw.siemens.com/.../Filtering-collections-in-java-macro-depending-on-names-of-wished-objects contains multiple example to generate collections of entities.From cfd-online.com/Forums/star-ccm/119587-loop-parts-java.html: to loop over all parts.
package macro; import java.util.*; import star.common.*; import star.meshing.*; public class partCollection extends StarMacro { public void execute() { Simulation sim = getActiveSimulation(); Collection<GeometryPart> myParts = sim.get(SimulationPartManager.class).getLeafParts(); for (Iterator<<GeometryPart> it = myParts.iterator(); it.hasNext();) { GeometryPart iPart = it.next(); sim.println(iPart.getPresentationName()); } } }
Define a List of boundaries: List<Boundary> wall_names = new ArrayList(); Create an array to store inlet pressures: double[] inletPr = new double[5];
Get List of Boundaries: Region region_1 = sim_1.getRegionManager() .getRegion( "Region" ); Collection<Boundary> bnd_names = region_1.getBoundaryManager() .getBoundaries(); or Collection<WallBoundary> bnd_names = region_1.getBoundaryManager() .getObjectsOf(WallBoundary .class); Alternatively: MeshPart mp_1 = (MeshPart) sim_1.get( SimulationPartManager.class ) .getParts() .toArray()[0]; Collection<PartSurface> bnd_names = mp_1.getPartSurfaceManager() .getPartSurfaces ();
Check boundary condition type of a boundary: String bcType = bndName.getConditions() .get(WallThermalOption.class) .getSelectedInput() .getSelected();
if(bcType == WallThermalOption.Type.TEMPERATURE) { sim_1.println("Specified boundary has thermal option TEMPERATURE"); }
Add a boundary to a list if it is of type wall: for (Boundary b_name : bnd_names) { if (b_name .getBoundaryType( ) instanceofWallBoundary) { wall_names .add(WallTypeBoundaries) } }; or if (b_name .getBoundaryType() == sim_1.get( ConditionTypeManager.class ) .get(WallBoundary .class) ) { wall_names .add( WallTypeBoundaries ) };
Macro to count number of elements in a boundary
PartSurface prtSrf_1 = (PartSurface) Part_0.getPartSurfaceManager() .getPartSurface( "Inlet" ); eCountRep_0.getParts().setObjects(prtSrf_1); eCountRep_0.printReport();
Print areas of all boundaries:
Iterator bnd_i = bnd_names.iterator(); String bnd_area; while ( bnd_i.hasNext() ) { PartSurface bdn_name_i = (PartSurface) bnd_i.next(); bnd_area = GetArea(bdn_name_i ); }
Monitor Points and Post-Processing
Create Report Monitors: ReportMonitor repMonFx = (ReportMonitor) sim_1.getMonitorManager() .getMonitor("Fx Monitor 2"); ReportMonitor repMonFy = (ReportMonitor) sim_1.getMonitorManager() .getMonitor("Fy Monitor 2"); ReportMonitor repMonMz = (ReportMonitor) sim_.getMonitorManager() .getMonitor("Mz Monitor 2");
Create Plot Monitor: sim_1.getMonitorManager() .createMonitorAndPlot(new NeoObjectVector(new Object[] {forceRep}), true, "Fx Plot"); ReportMonitor reportMon = (ReportMonitor) sim_1.getMonitorManager() .getMonitor("Force X Monitor"); MonitorPlot monitorPlot = sim_1.getPlotManager() .createMonitorPlot(new NeoObjectVector(new Object[] {reportMon}), "Force X Monitor Plot");
Combine multiple monitors: MonitorPlot monitorPlots = sim_1.getPlotManager() .createMonitorPlot(new NeoObjectVector(new Object[] {repMonFx, repMonFy, repMonMz}), "Reports Plot");
Create Scalar Field Function:
UserFieldFunction scalarFF = sim_1.getFieldFunctionManager().createFieldFunction(); scalarFF.getTypeOption().setSelected(FieldFunctionTypeOption.Type.SCALAR); scalarFF.setPresentationName("FF_" + num); //here 'num' is a variable scalarFF.setFunctionName("FF_Fun_" + num); scalarFF.setDefinition("($$Position[0] <= " + 0.25 +"&& $$Position[0] <= " + 0.75 + "? 1 : 0)");
Create Null Field Function: NullFieldFunction nullFF = (NullFieldFunction) sim_1.getFieldFunctionManager() .getFunction ("NullFieldFunction");
Create Field Function: PrimitiveFieldFunction positionFF = (PrimitiveFieldFunction) sim_1.getFieldFunctionManager() .getFunction("Position"); Get z-coordinate: VectorComponentFieldFunction vectorCompFF = (VectorComponentFieldFunction) positionFF.getComponentFunction(2); User "Velocity" instead of "Position" to create field function for Velocity. To get magnitude of the velocity: VectorMagnitudeFieldFunction velMag = (VectorMagnitudeFieldFunction) velFF.getMagnitudeFunction();
Create Vector Field Function: UserFieldFunction vel_FF = sim_1.getFieldFunctionManager() .createFieldFunction(); vel_FF.setPresentationName("V_X"); vel_FF.setFunctionName("V_X"); vel_FF.getTypeOption().setSelected(FieldFunctionTypeOption .VECTOR); vel_FF.setDefinition("[$vx, $vy, $vz]");
Field function for Dynamic Pressure: UserFieldFunction dynaPr = sim_1.getFieldFunctionManager() .createFieldFunction(); dynaPr.getTypeOption() .setSelected( FieldFunctionTypeOption .SCALAR); dynaPr.setPresentationName( "Dynamic Pressure" ); dynaPr.setFunctionName( "Dynamic Pressure" ); dynaPr.setDefinition( "$Density/2 * mag2($$Velocity)" ); dynaPr.setDimensionsVector(new IntVector(new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
Access Field Function: maxY.setScalar( sim_1.getFieldFunctionManager() .getFunction("Position") .getComponentFunction(1) ); Here maxY is a report defined as MaxReport maxY = sim_1.getReportManager() .createReport(MaxReport .class); maxY.getParts().setObjects(bnd_1); maxY.setPresentationName("Max_Extent_Y");
Create Threshold Part: ThresholdPart threshPart = sim_1.getPartManager() .createThresholdPart(new NeoObjectVector(new Object[]{}), new DoubleVector(new double[] {0.0, 1.0}), un_dim_less, nullFF, 0); thresPart.getInputParts() .setObjects(bnd_1); threshPart.getInputParts() .setQuery(null); threshPart.setFieldFunction(scalarFF); thresholdPart.getRangeQuantities() .setArray(new DoubleVector(new double[]{0.5, 0.5})); threshPart.setMode(ThresholdMode .ABOVE_TAG); threshPart.setPresentationName("thresh_" + num); (ClientServerObjectGroup) sim_1.getPartManager() .getGroupsManager() .getObject("groupSurf_1") .getGroupsManager() .groupObjects("groupSurf_1", new NeoObjectVector(new Object[ ] {threshPart} ), true); Here groupSurf_1 is the name of a group created by sim_1.getPartManager() .getGroupsManager() .createGroup("groupSurf_1");
Create Field Table: FileTable ft_1 = (FileTable) sim_1.getTableManager() .createFromFile(resolvePath( "ft.csv" ));
Read XYZ Table: XyzInternalTable xyzTab = (XyzInternalTable) sim_1.getTableManager() .getTable("XYZ Internal Table"); int n_rows = xyzTab.getRowCount(); int n_cols = xyzTab.getColumnCount(); val_ij = xyzTab.getValueAt(i, j);
Create a Residuals plot in which the simulation progress shall be displayed: ResidualPlot rp_1 = (ResidualPlot) sim_1 .getPlotManager() .getObject( "Residuals" ); rp_1.open();
Create XY Plot and Get Dataset: StarPlot plt_xy = sim_1.getPlotManager() .getObject("XYPlot 1"); Collection<DataSet> plot_datasets = plt_xy.getDataSetManager() .getObjects();
Import arbitrary surface for post-processing
Units un_arb_surf = (Units) sim_1.getUnitsManager().getObject("mm"); ArbitrarySection postProcessPlane = (ArbitrarySection) sim_1.getPartManager() .createArbitraryImplicitPart(new NeoObjectVector(new Object[] {}), resolvePath("C:\\Users\\Mid_plane.stl"), un_arb_surf); postProcessPlane.setPresentationName("curvedSurfaces"); postProcessPlane.getInputParts().setObjects(zn_1);
Export mintor points to a CSV file: monitorPlots.export(resolvePath("monitorData.csv"), ",");
Create Groups: sim_1.getReportManager() .getGroupsManager() .createGroup("wall_fluxes");
Find class names of various reports: MaxReport regionMaxY = sim_1.getReportManager() .createReport(MaxReport.class); MinReport regionMinY = sim_1.getReportManager() .createReport(MinReport.class);
Create Heat Transfer Coefficient (HTC) Report:
ExpressionReport local_HTC = sim_1.getReportManager() .createReport(ExpressionReport.class); // Define expression inline or specify FF name e.g. setDefinition("$FF_1") local_HTC.setDefinition("-${q_wall} / (${T_wall} - ${T_bulk})"); local_HTC.setDimensions( Dimensions .Builder().length(-2).temperature(-1).power(1).build() ); local_HTC.setPresentationName("HTC_local"); sim_1.getReportManager().getGroupsManager().createGroup("HTC_Group"); ((ClientServerObjectGroup) sim_1.getReportManager().getGroupsManager() .getObject("HTC_Local")).getGroupsManager().groupObjects("HTC_Group", new NeoObjectVector( newObject[] {local_HTC}), true);
Find drag coefficient report and store a reference to its location in a variable: ForceCoefficientReport fc_0 = (ForceCoefficientReport) sim_1.getReportManager().getReport("Drag Coefficient"); Report tqReport = sim_1.getReportManager() .getReport("TorqueReport");
Force Reports: ForceReport forceRep = sim_1.getReportManager() .createReport(ForceReport .class); forceRep.setPresentationName("FX"); forceRep.getDirection() .setComponents(1.0, 0.0, 0.0); forceRep.getParts() .setObjects(bnd_1, bnd_2); ForceReport forceX = (ForceReport) sim_1.getReportManager() .getReport("Fx"); Use Fy and Fz for force components in other directions.
Moment Reports: MomentReport momentZ = sim_1.getReportManager() .createReport(MomentReport .class); momentZ.setPresentationName( "Moment Z" ); momentZ.getDirection() .setComponents(0.0, 0.0, 1.0); momentZ.getOrigin(). setComponents(Cx, Cy, Cz); momentZ.getParts() .setObjects(wall_valve, wall_lever); MomentReport momentZ = (MomentReport) sim_1.getReportManager() .getReport("Mz");
Create a Geometry Scene: sim_1.getSceneManager() .createGeometrySceneAndWait("Geometry Scene", "Outline", "Geometry", 1);
Access a Scalar Scene: Scene scene_sc = sim_1.getSceneManager() .getScene("Scalar Scene 1");
Create a Part Displayer: PartDisplayer pd_1 = (PartDisplayer) scene_sc.getCreatorDisplayer( );
Retrieve a displayer from scene: ScalarDisplayer scDisp_1 = (ScalarDisplayer) scene_sc.getDisplayerManager() .getDisplayer( "Scalar 1" );
Defines particular representation to be used in the PartDisplayer: FvRepresentation fv_mesh = (FvRepresentation) sim_1.getRepresentationManager() .getObject("Vol_Mesh"); pd_1.setRepresentation( fv_mesh);Find a scene and assign it to a variable: Scene sc_v = sim_1.getSceneManager() .getScene("Velocity Magnitude");
Set background colour: sc_v.setBackgroundColorMode(0);
Remove Logo: FixedAspectAnnotationProp starLogo = (FixedAspectAnnotationProp) sc_v.getAnnotationPropManager() .getAnnotationProp( "Logo" ); sc_v.getAnnotationPropManager() .remove(starLogo);
Set number of colour band in legend: Legend colrBand = scDisp_1.getLegend(); colrBand.setLevels(10);
Print the image to file: sc_v.printAndWait(resolvePath( "projects/velMag.png" ), 1, 1280, 720); rp_1.encode(resolvePath( "./projects/residuals.png" ), "png", 960, 540); or: plots = sim_1.getPlotManager().getObjects(); plots.get(1).encode(resolvePath(root_dir + sep + plots.get(1) .getPresentationName() + ".jpg"), "jpg", 800, 450); Here plots.get(1) is used to acess the second item in the list 'plots'. 'root_dir' and 'sep' are defined earlier.
Retrieve all Derived Parts: PartManager pm_1 = sim_1.getPartManager(); Collection<Part> allDerivedParts = pm_1.getObjects( ); scDisp_1.getParts( ).setObjects( allDerivedParts );
Retrieve reports based on a Tag for a chosen report type such as "Mass Flow Report": Collection
Get collection of report names of particular type: Collection<ForceReport> forceReports = sim_1.getReportManager() .getObjectsOf(ForceReport.class); Get collection of all reports: Collection<Report> col_reps = sim_1.getReportManager() .getObjects(); col_reps.size() returns number of reports.
for(Report report_i : col_reps){ System.out.println = report_i.getReportMonitorValue(); }
Save a STAR-View+ scene file of the Streamlines: Scene scene_s = sim_1.getSceneManager() .getScene( "Streamlines" ); scene_s.open(true); scene_s.export3DSceneFileAndWait( resolvePath( "./projects/streamlines.sce" ), true);
Save simulation file:sim_1.saveState(resolvePath( "./projects/newFileName.sim")); sim_1.saveState(folder + "newFileName_" + i + ".sim"); sim_1.saveState("Y:\\CFD_Runs\\" + sim_1.getPresentationName() + "_new.sim");
getObjects() - returns a collection of the objects being managed and already typecast. Get the report value, use getReportMonitorValue() to return a double. For example, AreaAverageReport arAvgPr = (AreaAverageReport) sim_1.getReportManager( ).getReport( "avgPressure" ); double avgP = arAvgPr.getReportMonitorValue();
Area Average Report:
AreaAverageReport areaAvgRep = sim_1.getReportManager() .createReport(AreaAverageReport.class); PrimitiveFieldFunction static_pr_ff = (PrimitiveFieldFunction) sim_1.getFieldFunctionManager() .getFunction("StaticPressure"); areaAvgRep.setFieldFunction(static_pr_ff); areaAvgRep.getParts() .setQuery(null); areaAvgRep.getParts() .setObjects( "wall_valve" ); Units un_pr_pa = (Units) sim_1.getUnitsManager( ) .getObject("Pa"); areaAvgRep.setUnits(un_pr_pa); AreaAverageReport arAvgRepValue = (AreaAverageReport) sim_1.getReportManager() .getReport("reportAvgPressure"); arAvgRep.printReport();
Volume Average Report:
VolumeAverageReport volumeAvgT = sim_1.getReportManager() .createReport(VolumeAverageReport.class); PrimitiveFieldFunction field_func_T = (PrimitiveFieldFunction) sim_1.getFieldFunctionManager() .getFunction("TotalTemperature"); volumeAvgT.setFieldFunction(field_func_T); Units un_celsius = (Units) sim_1.getUnitsManager() .getObject("C"); volumeAvgT.setUnits(un_celsius);
Report with velocity-weighting
PrimitiveFieldFunction ff_vel = (PrimitiveFieldFunction) sim_1.getFieldFunctionManager() .getFunction ("Velocity"); VectorMagnitudeFieldFunction vec_mag_FF = (VectorMagnitudeFieldFunction) ff_vel.getMagnitudeFunction(); volumeAvgT.setWeightingFF(vec_mag_FF); volumeAvgT.getParts().setQuery(null); volumeAvgT.getParts().setObjects("cd_nozzle"); volumeAvgT.setPresentationName("T_bulk_nozzle");As you can see the steps to create a report are:
Following set of statements print volume of each region in the simulation domain
SumReport volm_of_regions = sim_1.getReportManager() .createReport(SumReport.class); PrimitiveFieldFunction PFF_Volm = (PrimitiveFieldFunction) sim_1.getFieldFunctionManager().getFunction("Volume"); volm_of_regions.setFieldFunction(PFF_Volm); volm_of_regions.getParts().setQuery(null); for (Region zone_i : getActiveSimulation().getRegionManager().getRegions()) { volm_of_regions.getParts().setObjects(zone_i); volm_of_regions.printReport(); }
By changing SumReport to VolumeIntegralReport and Primitive Field Function to 'Density', mass of each zone can be printed.
VolumeIntegralReport mass_of_regions = sim_1.getReportManager() .createReport(VolumeIntegralReport.class); PrimitiveFieldFunction PFF_Dens = (PrimitiveFieldFunction) mass_of_regions.setFieldFunction(PFF_Dens); mass_of_regions.getParts().setQuery(null); for (Region zone_i : getActiveSimulation().getRegionManager().getRegions()) { mass_of_regions.getParts().setObjects(zone_i); mass_of_regions.printReport(); }sim_1.getReportManager() .getGroupsManager() .createGroup( "groupVolAvgT" ); ((ClientServerObjectGroup) sim_1. getReportManager() .getGroupsManager(). getObject( "groupVolAvgT" )) .getGroupsManager() .groupObjects( "groupVolAvgT", new NeoObjectVector(new Object[] {volumeAvgT}), true);
Store the value of a report in a variable: int repValue = (int) some_Report.getReportMonitorValue(); avgT = sim_1.getReportManager() .getReport("avg_T_fluid") .getReportMonitorValue();
Export Monitor Points to a CSV file: Collection<Monitor> monitorList = sim_1.getMonitorManager() .getMonitors(); for (Monitor mn : monitorList) { mn.export(root_dir + mn.getPresentationName() .replace(" ", "") + ".csv"); }
Pressure Coefficient: PressureCoefficientFunction prCoeff = (PressureCoefficientFunction) sim_1.getFieldFunctionManager() .getFunction( "PressureCoefficient" )); prCoeff.getReferenceDensity() .setUnits(un_dim_less); prCoeff.getReferenceDensity() .setValue(ref_den); prCoeff.getReferenceVelocity() .setValue(ref_vel);
Print all regions and number of boundaries:
for (Region r : getActiveSimulation().getRegionManager().getRegions()) { r_name = r.getPresentationName() System.out.println(r_name + ", " + r.getBoundaryManager() .getBoundaries().size()); }
The output can be written to a file as well: File out_f = new File("bnd_list.txt"); BufferedWriter out_file = new BufferedWriter(new FileWriter(out_f)); out_file.write( ... );
Exports all reports to a csv file: Refer to this Java code available at cfd-online.com. Note that any operation in STAR-CCM+ which generates output to the 'Output' window log, can be stored in a string. For example, radiation view factor summary is printed in log window which can be stored in a variable as "String vfSummary = VFcalc.getViewfactorSummary();"
Exports a report by name to a csv file: Refer to this Java code available at cfd-online.com.
Convert Unsteady Simulation to Steady: the order of 'if' loops can be reversed to convert an Steady simulation to Unsteady.
for (PhysicsContinuum pc : sim_1.getContinuumManager().getObjectsOf(PhysicsContinuum.class)) { if (pc.getEnabledModels() .containsKey("star.common.ImplicitUnsteadyModel")) { pc.disableModel(pc.getModelManager() .getModel(ImplicitUnsteadyModel.class)); } if (!pc.getEnabledModels() .containsKey("star.common.SteadyModel")) { pc.enable(SteadyModel.class); } }
Get Heat Flux on Walls
String name_bnd_1 = "wall_tp"; Boundary bnd_1 = region_1.getBoundaryManager().getBoundary(name_bnd_1); AreaAverageReport arAvg_HFlux = sim_1.getReportManager().createReport(AreaAverageReport.class); PrimitiveFieldFunction primitiveFF_HFlux = (PrimitiveFieldFunction) sim_1.getFieldFunctionManager() .getFunction("BoundaryHeatFlux "); arAvg_HFlux.setFieldFunction(primitiveFieldFunction_q); arAvg_HFlux.getParts().setQuery(null); arAvg_HFlux.getParts().setObjects(bnd_1); arAvg_HFlux.setPresentationName("hflx_bnd_1");
Create Lines: The LinePart object is the Derived Part and the PartManager on the simulation object has the method to create this. LinePart linePart = sim_1.getPartManager() .createLinePart( new NeoObjectVector( new Object[] {region_0}), new DoubleVector( new double[] {0.2, 0.0, 0.0}), new DoubleVector( new double[] {0.5, 0.0, 0.0}), 20 );
The LinePart object must be specified what coordinate system it is using. Also, the units on each axis and the position of the start and end point of linePart is to be set.
LabCoordinateSystem labCS = (LabCoordinateSystem) sim_1 .getCoordinateSystemManager() .getLabCoordinateSystem(); linePart.setCoordinateSystem(labCS); Coordinate startPoint = linePart.getPoint1Coordinate(); startPoint.setCoordinate(un_1, un_1, un_1, new DoubleVector(new double[] {0.2, 0.0, 0.0})); Coordinate endPoint = linePart.getPoint2Coordinate(); endPoint.setCoordinate(un_1, un_1, un_1, new DoubleVector(new double[] {0.5, 0.0, 0.0}));
Initialize Unsteady Simulations
protected void initUnsteady(String func, int nStep) { Simulation sim_1 = getActiveSimulation(); StepStoppingCriterion stopCrit = (StepStoppingCriterion) sim_1.getSolverStoppingCriterionManager() .getSolverStoppingCriterion( "Maximum Steps" ); stopCrit.setIsUsed(false); ImplicitUnsteadySolver implicitUss = (ImplicitUnsteadySolver) sim_1.getSolverManager() .getSolver(ImplicitUnsteadySolver.class); FixedStepsStoppingCriterion fixedStopCrit = implicitUnsteadySolver .getSolverStoppingCriterionManager() .createSolverStoppingCriterion(FixedStepsStoppingCriterion.class); fixedStopCrit.setFixedSteps(1); implicitUss.getTimeStep() .setDefinition( "$dt" ); InnerIterationStoppingCriterion innerItStopCrit = (InnerIterationStoppingCriterion) sim_1.getSolverStoppingCriterionManager( ).getSolverStoppingCriterion( "Maximum Inner Iterations" ); innerItStopCrit.setMaximumNumberInnerIterations( nStep ); }
Set Asymptotic Convergence Criteria:
MonitorIterationStoppingCriterion iter_stop_criteria = (MonitorIterationStoppingCriterion) sim_1.getSolverStoppingCriterionManager() .getSolverStoppingCriterion("Z-momentum Criterion"); MonitorIterationStoppingCriterionAsymptoticType iter_stop_asymptotic = (MonitorIterationStoppingCriterionAsymptoticType) iter_stop_criteria.getCriterionType(); iter_stop_asymptotic.getMaxWidth().setValue(1.0E-8); iter_stop_asymptotic.setNumberSamples(100);
Create Vector Field Functions
FieldFunction vectorFF = (FieldFunction) sim_1.getFieldFunctionManager() .getFunction("Velocity"); VectorComponentFieldFunction vectCompFF = (VectorComponentFieldFunction) vectorFF.getComponentFunction( idx ); idx = 0 for x-component, 1 for y-component and 2 for z-component.Create Scalar Field Functions
UserFieldFunction uff_rad = sim_1.getFieldFunctionManager().createFieldFunction(); uff_rd.getTypeOption().setSelected(FieldFunctionTypeOption.SCALAR); uff_rad.setPresentationName("Radius"); uff_rad.setFunctionName("Radius"); uff_rad.setDefinition("sqrt(($$Position[0]*$$Position[0])+($$Position[1]*$$Position[1]))");
The code to add field function can be simplified as addScalarFF("WallHeatFlux", 5000); addVectorFF("InletVelocity", "10" ); by using following functions (note that it ignores dimensions that is, SI units with no conversions are assumed).
protected void addScalarFF(String ffName, String definition) { addScalarFF(ffName, definition, false); } protected void addScalarFF(String functionName, String definition, boolean ignoreBoundaryValues) { Simulation sim_x = getActiveSimulation(); UserFieldFunction uff_s = sim_x.getFieldFunctionManager() .createFieldFunction(); uff_s.setPresentationName(functionName); uff_s.setFunctionName(functionName); uff_s.setDefinition(definition); uff_s.setIgnoreBoundaryValues(ignoreBoundaryValues); } protected void addVectorFF(String ffName, String definition) { addVectorFF(ffName, definition, false ); } protected void addVectorFF(String functionName, String definition, boolean ignoreBoundaryValues ) { Simulation sim_x = getActiveSimulation(); UserFieldFunction uff_v = sim_x.getFieldFunctionManager() .createFieldFunction(); uff_v.setPresentationName(functionName); uff_v.setFunctionName(functionName); uff_v.getTypeOption() .setSelected(FieldFunctionTypeOption.VECTOR); uff_v.setDefinition(definition); uff_v.setIgnoreBoundaryValues(ignoreBoundaryValues); }
Function to set sliding velocity
public void setSlidingMotion(Boundary w_boundary, double sliding_v, String vel_unit) { Units un_vel = sim_1.getUnitsManager().getObject(vel_unit); if (un_vel.equalsIgnoreCase("km/h") || unit.equalsIgnoreCase("m/s")) { w_boundary.getConditions() .get(WallSlidingOption .class) .setSelected (Wal1SlidingOption .Type.VECTOR); w_boundary.getValues() .get(WallVelocityProfile .class) .getMethod(ConstantVectorProfileMethod .class) .getQuantity() .setComponents (sliding_v, 0, 0); w_boundary.getValues() .get(WallVelocityProfile.class) .getMethod(ConstantVectorProfileMethod .class) .getQuantity().setUnits (un_vel) ; } }
Change legend colour scheme: ScalarDisplayer scalar_disp_1 = (ScalarDisplayer) scene_1.getDisplayerManager() .getObject("Scalar 1"); Legend legend_1 = scalar_disp_1.getLegend(); PredefinedLookupTable lookupTableLegends = (PredefinedLookupTable) simulation.get(LookupTableManager .class) .getObject("blue-yellow-red"); legend_1.setLookupTable(lookupTableLegends);
This code to generate mesh and this Java macro to make runs contains examples to carry out various pre-processing operations in STAR-CCM+ including volume mesh generation.
Macro to extend the functionality of the Simulation Operations by inserting java macros inside the pipeline. Reference: community.sw.siemens.com/s/article/How-can-I-add-a-Java-macro-to-my-Simulation-Operation-pipeline
Sample Java Codes for STAR-CCM+ collected from open web: STAR-CCM+ has large number of modules named inline with their GUI counterparts. Some of them are summarized below.
import star.base.neo.*; where * represents DoubleVector; NamedObject; NeoObjectVector;]
import star.base.report.*; where * represents Monitor; Report; ReportMonitor;
import star.cadmodeler.Body; import star.cadmodeler.CadModel; import star.cadmodeler.SolidModelPart;import star.common.*; * represents modules named "AutoSave; Boundary; BoundaryType; BoundaryInterface; ColumnDescriptor; Comment; CommentManager; CompositePart; CoordinateSystem; DeltaMonitorUpdateEvent; Dimensions; ExpertInitManager; ExpertInitOption; FieldFunction; FreeStreamBoundary; FrequencyMonitorUpdateEvent; GeometryObject; GeometryPart; GridSequencingInit; ImplicitUnsteadyModel; InletBoundary; Interface; Model; MonitorNormalizeOption; LabCoordinateSystem; LogicUpdateEvent; MonitorPlot; PartCurve; PartSurface; PhysicsContinuum; PisoUnsteadyModel; PressureBoundary; RangeMonitorUpdateEvent; Region; RegionManager; ResidualMonitor; ScalarGlobalParameter; ScalarProfile; Simulation; Solution; SolutionView; SolverStoppingCriterion; StarPlot; SteadyModel; StepStoppingCriterion; SymmetryBoundary; Table; Tag; Units; UpdateEvent; VectorGlobalParameter; VectorProfile; WallBoundary; XyzTabularScalarProfileMethod;"
import star.energy.WallThermalOption; import star.flow.WallShearStressOption;import star.meshing.*; where * represents "AutoMeshOperation; CadPart; CustomMeshControl; LeafMeshPart; MeshOperation; MeshOperationPart; MeshPart; MeshPipelineController; PartCustomMeshControl; SimpleBlockPart; SimpleCylinderPart; SimpleSpherePart; SurfaceCustomMeshControl; TessellationDensityOption;" import star.metrics.CellQualityRemediationModel;
import star.prismmesher.* where * represents PartsCustomPrismsOption; PartsCustomizePrismMesh;
import star.solidmesher.* where * represents PartsCustomThinOption; and solidmesher.PartsCustomizeThinMesh;
import star.trimmer.* where * represents PartsGrowthRateOption; PartsTrimmerWakeRefinementOption; PartsTrimmerWakeRefinementSet; WRTrimmerAnisotropicSize;
import star.post .RecordedSolutionView; import star.post .SolutionHistory; import star.post .SolutionRepresentation;
import star.surfacewrapper.SurfaceWrapperAutoMeshOperation;import star.vis.*; where * represents [Annotation; AnnotationManager; SceneManager; CellSurfacePart; Displayer; LinePart; LookupTable; PlaneSection; PointPart; Scene; VisView;]
package macro; import java.util.*; import star.common.*; import star.base.neo.*; // Import modules related to material, viscous models, energy import star.material.*; import star.vis.*; import star.flow.*; import star.energy.*; import star.segregatedenergy.*; // Import modules related to S2S Radiation modeling import star.viewfactors.*; import star.radiation.s2s.*; import star.radiation.common.*; // The file name of this JAVA macro should be radiationHT.java public class radiationHT extends StarMacro { public void execute() { execute0(); } private void execute0 () { Simulation sim_1 = getActiveSimulation(); // Import Volume Mesh ImportManager im_1 = sim_1.getImportManager(); im_1.importMeshFiles(new StringVector(new String[] {resolvePath("D:\\testMacro.msh")}), NeoProperty.fromString("{\'FileOptions\': [{\'Sequence\': 43}]}")); // Create Scene to show import volume mesh FvRepresentation fvRep_2 = (FvRepresentation) sim_1.getRepresentationManager().getObject("Volume Mesh"); // Retrieve zone named 'mesh_solid' created after importing the mesh Region domain_1 = sim_1.getRegionManager().getRegion("mesh_solid"); // Create Geometry Scene fvRep_2.generateCompactMeshReport(new NeoObjectVector(new Object[] {domain_1})); sim_1.getSceneManager().createGeometryScene("Geometry Scene", "Outline", "Surface", 1); Scene scene_1 = sim_1.getSceneManager().getScene("Geometry Scene 1"); scene_1.initializeAndWait(); SceneUpdate sceneUpdate_1 = scene_1.getSceneUpdate() ; HardcopyProperties hcProp_1 = sceneUpdate_1.getHardcopyProperties(); // Scale mesh by factors 0.001 to convert [mm] into [m] fvRep_2.generateCompactMeshReport(new NeoObjectVector(new Object[] {domain_1})); LabCoordinateSystem labCS_1 = sim_1.getCoordinateSystemManager().getLabCoordinateSystem (); sim_1.getRepresentationManager().scaleMesh(new NeoObjectVector(new Object[] {domain_1}), new DoubleVector(new double[] {0.001, 0.001, 0.001}), labCS_1); // Fit screen scene_1.resetCamera(); hcProp_1.setCurrentResolutionWidth(1600); hcProp_1.setCurrentResolutionHeight(900); // Select continuum PhysicsContinuum pc_1 = (PhysicsContinuum) sim_1.getContinuumManager().getContinuum("Physics 1"); // Select Physics Models: sub-models are context based -- order is important pc_1.enable(ThreeDimensionalModel.class); pc_1.enable(SolidModel.class); pc_1.enable(RadiationModel.class); pc_1.enable(SteadyModel.class); pc_1.enable(SegregatedSolidEnergyModel.class); pc_1.enable(ConstantDensityModel.class); pc_1.enable(S2sModel.class); pc_1.enable(ViewfactorsCalculatorModel.class); pc_1.enable(GrayThermalRadiationModel.class); // Set wall temperatures: zone name 'wall_1' Boundary bz_1 = domain_1.getBoundaryManager().getBoundary("wall_1"); bz_1.getConditions().get(WallThermalOption.class).setSelected(WallThermalOption.Type.TEMPERATURE); StaticTemperatureProfile bcFixedT_1 = bz_1.getValues().get(StaticTemperatureProfile.class); bcFixedT_1.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(300.0); Units units_1 = (Units) sim_1.getUnitsManager().getObject("K"); bcFixedT_1.getMethod(ConstantScalarProfileMethod.class).getQuantity().setUnits(units_1); // Set wall temperatures: zone name 'wall_2' Boundary bz_2 = domain_1.getBoundaryManager().getBoundary("wall_2"); bz_2.getConditions().get(WallThermalOption.class) .setSelected(WallThermalOption.Type.TEMPERATURE) ; StaticTemperatureProfile bcFixedT_2 = bz_2.getValues() .get(StaticTemperatureProfile.class) ; bcFixedT_2.getMethod(ConstantScalarProfileMethod.class) .getQuantity() .setValue(500.0); bcFixedT_2.getMethod(ConstantScalarProfileMethod.class) .getQuantity() .setUnits(units_1); } }
package macro; import java.util.*; import star.common.*; import star.base.neo.*; public class macroToUpdatePlots extends StarMacro { public void execute() { execute0(); } private void execute0() { Simulation sim_0 = getActiveSimulation(); XYPlot xYPlot_0 = (XYPlot) sim_0.getPlotManager().getPlot("Cp plot"); Region region_0 = sim_0.getRegionManager().getRegion("Airfoil"); Boundary bz_0 = region_0.getBoundaryManager().getBoundary("Airfoil_TE"); Boundary bz_1 = region_0.getBoundaryManager().getBoundary("FF_TE"); Boundary bz_2 = region_0.getBoundaryManager().getBoundary("RF_TE"); Boundary bz_3 = region_0.getBoundaryManager().getBoundary("Default"); xYPlot_0.getParts().setObjects(bz_0, bz_1, bz_2, bz_3); XYPlot xYPlot_1 = (XYPlot) sim_0.getPlotManager().getPlot("Y+ plot"); xYPlot_1.getParts().setObjects(bz_0, bz_1, bz_2, bz_3); } }
Transfer information (field functions, coordinate systems, physics continua ...) from a 'source' simulation to several destination simulations: All the simulation files should be open in same STAR-CCM+ GUI Client.
Context menu is the pop-up window that appears on the right-click on the item in the simulation tree. However a Java macro in STAR-CCM+ cannot be run with a right click context menu.
Print names of the selected objects
//Create highlight manager from the scene manager HighlightManager hiLiteMan = sim_1.getSceneManager().getHighlightManager(); // Get the collection of highlighted objects Collection<NamedObject> colHiLite = (List) hiLiteMan.getCurrentHighlights(); if (colHiLite.isEmpty()) { sim.println(“Warning: No parts are selected.”); } else { for (NamedObject sel_obj : colHiLite) { sim_1.println(sel_obj + " : " + sel_obj.getPresentationName()); } }
Java macro to write report values to a CSV for multiple *.sim files --from cfd-online.com/Forums/star-ccm/213223-macro-generate-csv-reading-report-values.html
String out_file = "reportOutput.txt"; try { sim_1.println("Writing report values to file " + resolvePath(out_file)); PrintWriter out = new PrintWriter( new FileWriter( new File(resolvePath(out_file)) ) ); // for each 'report' variable of type 'Report' in sim_1.getReportManager().getObjects() for (Report report : sim_1.getReportManager().getObjects()) { String reportName = report.getPresentationName(); double reportValue = report.getReportMonitorValue(); String reportUnits = report.getUnits().getPresentationName(); out.println(reportName + " = " + reportValue + " " + reportUnits); } out.close(); } catch (IOException ex) { sim_1.println(ex); }
Another solution from community.sw.siemens.com: this code outputs all reports to a csv file without a priori knowledge of the report names.
package macro; import java.util.*; import star.common.*; import star.base.report.*; public class runAllReports extends StarMacro { public void execute() { Simulation sim_1 = getActiveSimulation(); Collection<Object> reports = sim_1.getReportManager().getChildren(); Iterator repIt = reports.iterator(); while ( repIt.hasNext() ) { Report rep = (Report) repIt.next(); rep.printReport(); } } }
There is an interesting macro on community.sw.siemens.com to create probe points along the axis of a pipe or duct. The "axis" is automatically calculated by the macro based on the geometry of the duct though not applicable to pipes with sharp direction changes and U-bends.
Given a report configuration: Reports > group_1 > group_2 > rep_name, rep_name.getParent() returns Reports (with the class ReportsManager). There is a Java Macro to get the direct parent group (in this case group_2) available at community.sw.siemens.com/s/question/. ./how-to-get-the-group-of-an-object-with-java-api
A Java macro to run multiple cases by changing rotation speeds can be found at community.sw.siemens.com/s/article/Java-macro-to-run-multiple-rotational-speeds-and-save-multiple-sim-files-in-a-single-run
Java macro that removes all reports: community.sw.siemens.com/s/article/How-to-remove-all-the-reports-in-a-sim-file-with-minimal-number-of-clicks-using-a-java-macro
Report number of geometry parts, regions, boundaries and interfaces in a sim file: community.sw.siemens.com/s/article/How-to-find-number-of-parts-regions-boundaries-and-interfaces-using-macro-and-save-the-info-as-text-file
Set mass-flow-inlet type boundary condition by reading strings and double values from each row in a .csv file: community.sw.siemens.com/s/article/Set-Boundary-Condition-for-multiple-boundaries-using-a-Java-Macro
Create Sphere and Mesh It:
MeshPartFactory meshPartSphere = sim_1.get(MeshPartFactory.class); SimpleSpherePart spherePart = meshPartSphere.createNewSpherePart(sim_1.get(SimulationPartManager.class)); spherePart.setDoNotRetessellate(true); LabCoordinateSystem labCS_sph = sim_1.getCoordinateSystemManager().getLabCoordinateSystem(); spherePart.setCoordinateSystem(labCS_sph); Coordinate origin_sph = spherePart.getOrigin(); origin_sph.setCoordinateSystem(labCS_sph); origin_sph.setCoordinate(units_sph, units_sph, units_sph, new DoubleVector(new double[] {0.0, 0.0, 0.0})); // Set location of sphere center (x0, y0, z0) in units defined by units_sph origin_sph.setValue(new DoubleVector(new double[] {sph_x0, sph_y0, sph_z0})); spherePart.getRadius().setUnits(units_sph); // Set sphere radius in units defined by units_sph spherePart.getRadius().setValue(sph_r); spherePart.getTessellationDensityOption().setSelected(TessellationDensityOption.MEDIUM); spherePart.rebuildSimpleShapePart(); spherePart.setDoNotRetessellate(false);
Import STL Mesh and Generate Volume Mesh
Units un_mm = (Units) sim_1.getUnitsManager().getObject("mm")); un_mm.setPreferred(true); PartImportManager partImportManager_0 = sim_1.get(PartImportManager.class); partImportManager_0.importStlPart(resolvePath(STL_File_Name), "OneSurfacePerPatch", units_1, true, 1.0E-5); Region region_0 = sim_1.getRegionManager().createEmptyRegion(); region_0.setPresentationName("Fluid_Region"); Boundary boundary_0 = region_0.getBoundaryManager().getBoundary("Default"); region_0.getBoundaryManager().removeBoundaries(new NeoObjectVector(new Object[] {boundary_0})); FeatureCurve featureCurve_0 = (FeatureCurve) region_0.getFeatureCurveManager() .getObject("Default"); region_0.getFeatureCurveManager().removeObjects(featureCurve_0); FeatureCurve featureCurve_1 = region_0.getFeatureCurveManager() .createEmptyFeatureCurveWithName("Feature Curve"); MeshPart meshPart_0 = (MeshPart) sim_1.get(SimulationPartManager.class) .getPart("Fluid_Domain"); sim_1.getRegionManager().newRegionsFromParts(new NeoObjectVector(new Object[] {meshPart_0, spherePart}), "OneRegion", region_0, "OneBoundaryPerPartSurface", null, "OneFeatureCurve", featureCurve_1, false); MeshContinuum mshCon = sim_1.getContinuumManager().createContinuum(MeshContinuum.class); PhysicsContinuum pc_1 = sim_1.getContinuumManager().createContinuum(PhysicsContinuum.class); mshCon.enable(ResurfacerMeshingModel.class); mshCon.enable(DualMesherModel.class); mshCon.enable(GenCylModel.class); // Use trimmer (Cartesian or Cut-cell) mesh mshCon.enable(TrimmerMeshingModel.class); mshCon.enable(PrismMesherModel.class); // Set base size mshCon.getReferenceValues().get(BaseSize.class).setValue(baseSize); ResurfacerMeshingModel resurfMesh = mshCon.getModelManager() .getModel(ResurfacerMeshingModel.class); resurfMesh.setDoCompatibilityRefinement(true); resurfMesh.setDoAutomaticSurfaceRepair(false); MaxTrimmerSizeToPrismThicknessRatio trimmerToPrismRatio = mshCon.getReferenceValues() .get(MaxTrimmerSizeToPrismThicknessRatio.class); trimmerToPrismRatio.setLimitCellSizeByPrismThickness(true); SizeThicknessRatio sizeThicknessRatio_0 = trimmerToPrismRatio.getSizeThicknessRatio(); // Prism to field thickness ratio and Number of boundary layers sizeThicknessRatio_0.setNeighboringThicknessMultiplier(prism_field_ratio); NumPrismLayers numBL = mshCon.getReferenceValues().get(NumPrismLayers.class); numBL.setNumLayers(n_BL); PrismThickness prismHt = mshCon.getReferenceValues() .get(PrismThickness.class); prismHt.getRelativeOrAbsoluteOption().setSelected(RelativeOrAbsoluteOption.ABSOLUTE); GenericAbsoluteSize genAbsSize = (GenericAbsoluteSize) prismHt.getAbsoluteSize(); // Set relative size GenericRelativeSize rel_size_prism = (GenericRelativeSize) prismHt.getRelativeSize(); rel_size_prism.setPercentage(50.0); Units un_inch = (Units) sim_1.getUnitsManager().getObject("in"); genAbsSize.getValue().setUnits(un_inch); genAbsSize.getValue().setValue(h_BL); PrismLayerStretching prism_stretch = mshCon.getReferenceValues() .get(PrismLayerStretching .class); prism_stretch.setStretching(1.5); // Specify curvature refinement number of points around a circle SurfaceCurvature refineCurvature = mshCon.getReferenceValues().get(SurfaceCurvature.class); SurfaceCurvatureNumPts n_refineCurvature = refineCurvature.getSurfaceCurvatureNumPts(); n_refineCurvature.setNumPointsAroundCircle(n_curve_refine); // Surface growth rate (ratio of triangle sizes) SurfaceGrowthRate surfaceGrowthRate_0 = mshCon.getReferenceValues() .get(SurfaceGrowthRate.class); surfaceGrowthRate_0.setGrowthRate(rate_surf_growth); SurfaceSize surfaceSize_0 = mshCon.getReferenceValues().get(SurfaceSize.class); RelativeMinimumSize relMinSize = surfaceSize_0.getRelativeMinimumSize(); // Set triangle minimum size percentage relMinSize.setPercentage(miz_size_perc); SimpleTemplateGrowthRate growthRate = mshCon.getReferenceValues() .get(SimpleTemplateGrowthRate.class); // Set volume mesh and nearfield growth rates (FAST, MEDIUM, SLOW, VERYSLOW) growthRate.getGrowthRateOption().setSelected(GrowthRateOption.SLOW); growthRate.getSurfaceGrowthRateOption() .setSelected(SurfaceGrowthRateOption.VERYSLOW); // Remove existing feature curves region_0.getFeatureCurveManager().removeObjects(featureCurve_1); MeshPipelineController meshPipelineController = sim_1.get(MeshPipelineController.class); meshPipelineController.initializeMeshPipeline(); SurfaceRep surfaceRep_0 = (SurfaceRep) sim_1.getRepresentationManager() .getObject("Initial Surface"); Boundary boundary_1 = region_0.getBoundaryManager().getBoundary("bnd_name_1"); Boundary boundary_2 = region_0.getBoundaryManager().getBoundary("bnd_name_2"); Boundary boundary_3 = region_0.getBoundaryManager().getBoundary("bnd_name_3"); boundary_3.setBoundaryType(FreeStreamBoundary.class); // Identify feature curves using angle criteria 'feature_angle' FeatureCurve featureCurve_2 = surfaceRep_0.createFeatureEdgesOnBoundaries( new NeoObjectVector(new Object[] {bnd_name_1, bnd_name_2, bnd_name_3}), true, true, true, true, true, true, feature_angle, false); SurfaceSizeOption surfaceSizeOption_2 = featureCurve_2.get(MeshConditionManager.class) .get(SurfaceSizeOption.class); surfaceSizeOption_2.setSurfaceSizeOption(true); SurfaceSize surfaceSize_2 = featureCurve_2.get(MeshValueManager.class).get(SurfaceSize.class); RelativeMinimumSize relativeMinimumSize_2 = surfaceSize_2.getRelativeMinimumSize(); // Set feature curve minimum size relativeMinimumSize_2.setPercentage(min_mesh_perc); RelativeTargetSize relativeTargetSize_2 = surfaceSize_2.getRelativeTargetSize(); relativeTargetSize_2.setPercentage(edge_tgt_perc); SurfaceSizeOption surfaceSizeOption_3 = boundary_3.get(MeshConditionManager.class) .get(SurfaceSizeOption.class); surfaceSizeOption_3.setSurfaceSizeOption(true); SurfaceSize surfaceSize_3 = boundary_3.get(MeshValueManager.class).get(SurfaceSize.class); surfaceSize_3.getRelativeOrAbsoluteOption().setSelected(RelativeOrAbsoluteOption.ABSOLUTE); AbsoluteMinimumSize absoluteMinimumSize_3 = surfaceSize_3.getAbsoluteMinimumSize(); // Set triangle size absoluteMinimumSize_3.getValue().setValue(min_tria_size); AbsoluteTargetSize absoluteTargetSize_3 = surfaceSize_3.getAbsoluteTargetSize(); absoluteTargetSize_3.getValue().setValue(tria_size); // Generate mesh and save SIM file if (bool_surf_mesh) { meshPipelineController.generateSurfaceMesh(); sim1.getSceneManager().createGeometryScene("Mesh Scene", "Outline", "Mesh", 3); Scene scene_surf_mesh = sim_1.getSceneManager().getScene("Mesh Scene 1"); scene_surf_mesh.initializeAndWait(); } if (bool_volm_mesh) meshPipelineController.generateVolumeMesh(); if (bool_save_mesh) sim_1.saveState(resolvePath(sim_file_name));
Check and Look-ups
Check if a physics continuum already existsPhysicsContinuum pc_lookup = lookupObject(PhysicsContinuum.class); if (pc_lookup != null) { notifyUser("Continuum " + pc_lookup.getPresentationName + " already exits"); return; } else { notifyUser("A physics continuum is required to proceed."); return; } Region region_x = lookupObject(Region.class); region_x.setContinumm(pc_lookup); // Add the continuum to loopup list addToTaskLookup(pc_lookup);SingleComponentLiquidModel liquid_mat = pc_1.getModelManager() .hasModel(SingleComponentLiquidModel .class);
if (liquid_mat == null) { return false; }Material water = liquid_mat.getMaterial();
if (! (water instanceOf Liquid)) { return false; } MaterialProperty mat_prop = (Liquid) water).getMaterialProperties() .hasObjectOfClass(PolynomialDensityProperty .class .getName(); if (mat_prop == null) { notifyUser("Material property is not a polynomial function."); return false; }MaterialPropertyMethod mat_prop_method = mat_prop.getMethod();
if (!(mat_prop_method instanceOf TemperaturePolynomial)) { notifyUser("Material property is not a function of temperature"); return false; }
Check if a boundary name is defined or not
public boolean CheckBoundaryNames(GeometryPart part) { partFound = false; for (PartSurface surf : part.getSurfaces()) { if("inlet".equals(surf.getPresentationName())) { partFound = true; } } }
Arrays: Range of Variables
RangeMultiValue range_start_end = planesection.getRangeMultiValue(); range_start_end.setNValues(4); range_start_end.getStartQuantity(10.0); range_start_end.getStartQuantity().setUnits(un_mm); range_start_end.getEndQuantity(20.0); range_start_end.getEndQuantity().setUnits(un_mm); DeltaMultiValue range_delta = planesection.getDeltaMultiValue(); range_delta.setNValues(4); range_delta.getStartQuantity(10.0); range_delta.getStartQuantity().setUnits(un_mm); range_delta.getDeltaQuantity.setValue(5.0); range_delta.getDeltaQuantity().setUnits(un_mm);
Specify parameters using an input file
Use an *.ini file which can contain several command line options, one option per row. Rows starting with the "#" symbol are treated as comments. The parameter names in the command line option must match the parameter names in the simulation set-up *.sim file. For example:#Specify geometry -param geomStep .\Projects\Manifold.stp # Specify Boundary Conditions -param mass_flow_rate 1.5kg/s -param inlet_temperature 300C -param wallFlux 250.0W/m^2 -param HTC 10.0W/m^2/K -param TREF 40.0C
Scene currentScene = sim_1.getSceneManager().getScene("Outlets"); sim_1.println(currentScene.getDrawableScene().computeVisibleBounds().toString());Alternatively, the two corners of boundaing box can be accessed using:
SimpleBlockPart simpleBP = (SimpleBlockPart) sim_1.get(SimulationPartManager.class).getPart("Block"); DoubleVector Corner_1 = simpleBP.getCorner1().getSIValue(); DoubleVector Corner_2 = simpleBP.getCorner2().getSIValue();
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