• CFD, Fluid Flow, FEA, Heat/Mass Transfer

Cross-learning: FLUENT / CFX / STAR / COMSOL

Same concepts - different approaches!

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


CFD Simulation steps in STAR-CCM+ including Java Macros and Field Functions

  • Root ObjectThe root object within each simulation object tree is known as the simulation node. This node has its own properties and pop-up menu.
  • Parts: There are three different types of part that can be used in a STAR-CCM+ simulation. In 3D case, a part should represent either a solid or fluid volume and not surfaces.
    • Geometry parts (model geometry)
    • Model parts (including regions, boundaries, and interfaces contained within the Regions, Boundaries, and Interfaces manager nodes - representing the discretized portions of the geometry to be analyzed, on which physics models are applied.
    • Derived parts (parts used in the definition of analysis reports and for visualizing solution data in scalar and vector scenes.
  • Continuum: Continuum is used to contain selections of physics or meshing models that are subsequently applied to one or more regions. Continuum have no geometric definition associated with it.
  • Mesh Continuum: A mesh continuum contains a selection of meshing models, such as the surface remesher, the prism layer mesher and the polyhedral mesher. When a mesh continuum is applied to a region, the region is discretized according to the meshing models selected for the mesh continuum. While using "Automated Mesh operation" to generate volume mesh, 'parts' must be assigned to 'regions'.
  • Physics Continuum: A physics continuum contains a selection of physics models, such as a chosen flow solver, material models, steady or transient time model, a turbulence model and so on. Each physics continuum represents a single substance that is present in all regions to which the physics continuum applies. Fluid Continuum and Solid Continuum are used to designate Fluid and Solid materials respectively.

    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.
  • Model: Model nodes in the simulation object tree represent simulation features that are active in the current case. Model nodes are contained within the meshing and physics continua to control the construction of surface and volume meshes and physics models to define the behavior of the specified material.
  • Regions: Regions are volume domains (or areas in a two-dimensional case) in space that are completely surrounded by boundaries. They are not necessarily contiguous and can be linked to each other through interface type boundaries. Regions are created either when a volume mesh is imported or when a surface is imported without using geometry parts. Each region is given a unique name during the import process which can be renamed as per user's convenience.
  • Boundaries: Boundaries are surfaces (or lines in a two-dimensional case) that completely surround and define a region. Boundaries are never shared between regions - a boundary can belong to only one region.
  • Scene: A scene facilitate visual representation of the model. Under a scene, Displayers handle the actual visible objects. Default setups are: Geometry, Mesh, Scalar, Vector and Empty though any scene can use any type of displayer or any mix of displayers. The default scenes just automatically load useful displayers in upon creation. Parts can be added in the properties window after selecting it under the displayer.
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.

IdentifierSTAR-CCM+FLUENTCFXOpenFOAM / ParaView
SolversPhysics ContinuaViscous Model-Application
PartsMesh Continua Zones Boundary
RegionsContinuaCell Zones, Face ZonesCell Zones, Face ZonesBlocks
DomainsContinuaCell Zones, Face ZonesCell Zones, Face ZonesBlocks
BoundariesCell Zones, Face ZonesFace Zones, Edge ZonesBoundary
Zones Regions, boundariesBoundary, Patch
CaseModelCaseDefinitionFolder
ScenesSeparate for Geometry, Mesh, Scalar, VectorCommon for Scalar and Vectors, PlanesCommon 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.


Defining the Simulation Topology

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.


Difference in Descriptions

Tree structure in STAR-CCM+


Note that there is no UNDO option in general. For example, if you delete a part from model tree, you cannot recover by UNDO operation. There are some UNDO and REDO operations though such as surface repair operations. Most of the programs has keyboard short-cuts like famous control-c and control-v in MS-Windows OS. These are sometimes also called hot-keys. A summary of such keyboard features available in STAR-CCM+ are as follows:
  • To align with the X-Y plane, press the 'T' key. Remember 'T' as initial of TOP view
  • To align with the Y-Z plane, press the 'F' key. Remember 'F as initial of FRONT view
  • To align with the Z-X plane, press the 'S' key. Remember 'S' as initial of SIDE view
  • To rotate the model about x-axis, press 'x' key. It will rotate 10° for every press of the 'x' key. Same if true for 'y' and'z' keys
  • To fit the view within the Graphics window, press the 'R' key
  • To rotate about the selected point, hold down the left mouse button and drag
  • To zoom in or out, hold down the middle mouse button and drag
  • To translate or pan, hold down the right mouse button and drag
  • To rotate around an axis perpendicular to the screen, press the 'Ctrl' key and hold down the left mouse button while dragging
  • Double click on an edge and it will attempt to create a closed loop.
STAR-CCM+ Views

STAR-CCM+ Views Options

STAR-CCM+ Toolbars

STAR-CCM+ Toolbar Settings

STAR-CCM+ Tools and Scenes

STAR-CCM+ Tools and Scenes


STAR-CCM+ Geometry Import

STAR-CCM+ Geometry Import Options

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.


Manual Surface Preparation
An imported geometry cab be of poor quality to properly mesh and achieve a useful simulation result. The geometry may be self-intersecting, it may have gaps, there may be free edges or non-manifold vertices. The manual surface preparation tools contained within STAR-CCM+ allow you to:
  • diagnose and locate each surface issue
  • delete faces and edges and create new ones
  • collapse and smooth vertices
  • fill and patch holes
  • split and swap edges
  • locally zip edges
  • locally remesh faces (with or without feature retention)
  • isolate connected surfaces and delete them if necessary
  • inflate thin shell/baffle surfaces so that they have thickness
  • translate a surface
Two defeature modes [accessed by right-clicking the body] are available in STAR.
  1. Automatic mode is applicable to Bodies and automatically defeatures fillets, chamfers and holes based on a user-defined criterion.
  2. Manual defeature mode is applicable on Faces and is used to delete and heal user-selected faces. From V2020.2 onwards, the feature Delete Interior Faces deletes all faces that exist between the two faces selected by the user.

Delete Interior Faces STAR-CCM+

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.

Surface repair in STAR-CCM+

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.

conditions Search Criteria

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.

STAR surface Feature Repair

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.


Non-conformal Imprinting
During the process of non-conformal imprinting, pairs of split surfaces are created on contacting parts without altering the individual parts or creating shared faces. To achieve a non-conformal mesh when imprinting these surfaces, before you imprint the parts, activate Show Advanced Parameters and set Resulting Mesh Type to Non-Conformal. After imprinting the parts, the resultant surfaces are non-conformal, which means that the surface discretization on the imprinted surfaces does not match. Each part remains separate and there is no shared surface between each part. However, the original discretized surfaces are cut and a pair of split part surfaces are created which represent an in-place part contact between the surfaces.
Mesh Generation in STAR-CCM+
Excerpts from user manuals and tutorials for STAR-CCM+

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 in STAR-CCM+

Operations – utilities that perform actions on 'Parts', Certain operations such as "extract volume", "surface wrapper" ... create new parts.

Surface Repair options in STAR-CCM+

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.

Directed Meshing

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".

Surface Wrapping in STAR-CCM

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:

  1. Global surface wrap at part / component level: Right-click the Geometry > Operations node and select New >> Surface Wrapper. In the Create Surface Wrapper Auto Mesh Operation dialog, select appropriate part/assembly. Expand the Surface Wrapper > Default Controls node and set Base Size, Minimum Surface Size and Volume of Interest.
  2. Refining the Mesh on Part Curves: To make sure that you capture the detailed features in the surface mesh, apply mesh refinement to all the part curves. To apply refinement to all part curves: Right-click the Surface Wrapper > Custom Controls node and select Ne>> Curve Control. STAR-CCM+ adds a curve control node within the Custom Controls node.
  3. Preventing Contact between Close Surfaces: To make sure that these two surfaces do not touch each other in the wrapped surface, apply a contact prevention between the nose and main body. To apply contact prevention: Right-click the Operations > Surface Wrapper > Contact Prevention node and select New > One Group Contact Prevention Set. Contact prevention for small clearances -> One Group Contact Prevention Set / Two Group Contact Prevention Set
  4. Local refinements neas gaps using "Surface Control"
  5. Perform "partial wrapping" to capture local features like baffles, channels...[Split surface by patches, Preserved Input Surfaces-> Select "Excluded Surfaces"]
  6. Creating the Fluid Volume: The fluid simulation requires a volume mesh between the walls of the simulation domain. To create the part that defines the outer surface of the volume mesh, subtract the output of the surface wrapper operation from the bounding box. Right-click the Geometry > Operations node and select New > Subtract. In the Create Subtract Operation dialog, select Bounding Box and Surface Wrapper, then click OK. A Subtract node appears beneath the Operations node, and a Subtract part appears beneath the Parts node.

Contact Prevention
When the clearance between two surfaces is less than the target surface size, use a contact prevention to tell the wrapper not to join the two boundaries. 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 is smaller than the gap size (typically one half or one quarter of the distance). You can still join the surfaces even though a Minimum Size value is set. The Minimum Size value is simply a stopping size for the surface wrapper refinement, which results in the two surfaces being separated. The value also has to be greater than zero.
Mesh Interfaces

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.

  1. between boundary faces: this include contact interfaces between solid and fluid regions, internal interfaces between fluid regions and baffle interfaces representing thin-walled separators. There are two categories for interfaces between boundaries:
    • Direct Interface - boundary faces are intersected or imprinted resulting in conformal mesh: Baffle, Porous-baffle, Contact, Fa, Fluid Film, Fully developed, Internal
    • Indirect Interface - boundary faces are coupled using mapping or mixing: Mapped Contact, Mixing Plane Interface, Blower Interface
  2. between region volumes: Interfaces are created between region volumes to set up an overset mesh or to model heat transfer in a dual stream heat exchanger. To create an interface between regions ➛ Select the two regions that define the interface (press and hold the Ctrl key to select the second node) ➛ Right-click and select the Create Interface pop-up menu item, and make a selection from one of the options in the submenu.

create Interfaces in STAR-CCM+

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 toTopologyConnectivity
BaffleBoundariesDirect InterfaceImprinted
Porous BaffleBoundariesDirect InterfaceImprinted
ContactBoundariesDirect InterfaceImprinted
FanBoundariesDirect InterfaceImprinted
Fluid FilmBoundariesDirect InterfaceImprinted
Fully DevelopedBoundariesDirect InterfaceImprinted
InternalBoundariesDirect InterfaceImprinted
Mapped ContactBoundariesIndirect InterfaceMapped
Mixing Plane BoundariesIndirect Interface Connect Average
BlowerBoundaries Indirect Interface Connect Average
Heat ExchangerRegions Heat Exchanger Topology Modeled
Overset MeshRegionsOverset 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.

create Boundary Interfaces in STAR-CCM+

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:

  • a conformal interface is not necessary to achieve solution accuracy
  • there are many contacting parts
  • each part is within many pairs
  • there are gaps between the CAD parts

STAR-CCM+ Mesh Checker
When a mesh created in external application is imported into STAR, by default unit of [m] is assigned to the dimensions of the mesh. Hence, the imported mesh needs to be scaled appropriately. Mesh > Diagnostics... menu option can be used to generate Compact and Full report summarizing the entity count, mesh extents and mesh quality.
Mesh Diagnostics: Compact

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.

Mesh Diagnostics: Full

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.


Mesh Quality Checks in STAR-CCM+

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.

  • Polyhedral quality: This value refers to the cell quality of the polyhedral cells.
  • Cell face validity: This value refers to the face validity of the cells.
  • Cell orthogonality: This value refers to the angle between the normals of two faces in a cell that share an edge. The closer the cell edge angles are to 90 degrees, the more orthogonal the cell is.
  • Cell skewness angle: This skewness measure is designed to reflect whether the cells on either side of a face are formed in such a way as to permit diffusion of quantities without these quantities becoming unbounded. The skewness angle the angle between the face area vector (face normal) and the vector connecting the two cell centroids. Skewness angle = 0 indicates a perfectly orthogonal mesh. Variables that are stored at interior faces in STAR-CCM+ cannot be displayed and hence the worst skewness angle for all the faces of a cell are stored in that cell. Thus, two cells often have the same skewness angle corresponding to the face that they share. To reduce the impact on robustness, avoid skewness angles greater than 85° as reported in themesh diagnostics full report.
  • Cell Quality: It describes relative geometric distribution of the cell centroids of the face neighbor cells and of the orientation of the cell faces which is specified as 'Orthogonality' in some programs such as ANSYS FLUENT. Generally, flat cells with highly non-orthogonal faces have a low cell quality. A cell with a quality of 1.0 is considered perfect.
  • Cell volume ratio: This value refers to the volume change between neighboring cells.
  • Boundary Skewness Angle: it is defined as the angle between the area vector and the vector connecting the cell centroid and the boundary face centroid. This angle is important since the dot product of these two vectors appears in a denominator in a component of the equation for diffusive fluxes at a boundary face. In turbulent flows where wall functions are used, the equation for diffusive fluxes at a boundary is not used to compute diffusion fluxes at walls, so boundary face skewness become less important. However, it is important for laminar flows and for heat transfer in solids. To reduce the impact on robustness, avoid boundary skewness angles greater than 85° as reported in the mesh diagnostics full report.
  • Face Validity Cell Metric: It is an area-weighted measure of the correctness of the face normals relative to their attached cell centroid. A face validity of 1.0 means that all face normals are correctly pointing away from the cell centroid. Values < 1.0 mean that some of the cell faces have normals pointing inward towards the cell centroid indicating some form of concavity. Values < 0.5 signify a negative volume cell.
  • Volume change metric: It describes the ratio of the volume of a cell to that of its largest neighbor. A value of 1.0 indicates that the cell has a volume equal to or higher than its neighbors. A large jump in volume from one cell to another can cause potential inaccuracies and instability in the solvers. Consider cells with a volume change value < 10-5 to be suspect and investigate these cells further.

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.


  • pierced faces: A pierced face is one that has one or more edges of another surface cell piercing it.

    pierced Faces

  • close proximity faces (surface folds and overlaps):
  • free edges (holes and mismatched edges): Free edges refer to cell faces that are not connected to a neighboring face. free edges can be fixed by using the hole filler, the edge zipper, or the manual fixing tools, depending the nature of the problem. To repair click on the number on the Count list and all the problematic part would appear in pink. Then if it is for example problematic faces (that are overcreated) select them one by one or with ctrl or with the Zone selection tool and delete them. Then you will have to fill the holes you created with this action or the ones made by the software when importing the geometry.
  • non-manifold edges: A non-manifold edge refers to a cell face edge that is connected to two (or more) other edges. A non-manifold edge is sometimes valid depending on whether the surface cells causing the problem are supposed to be a part of the geometry or not. For example, consider a geometry that contains a baffle surface that is joined to the exterior surface. This geometry is not a problem as long as the surface is converted to an interface before proceeding with the volume meshing. If the non-manifold edge is not expected, then you can delete the faces that are causing the problem.
  • non-manifold vertices: Typically vertices connected to a surface instead of two or more edges.

    non-Manifold Vertex

  • holes or leaks: Leaks are not desired because they cause an inversion in the wrapping process, which results in the incorrect volumes being wrapped. Run the leak detection tool to identify less obvious gaps and holes. The hole filler can be used to close any closed loop (both single and multiple loops) planar hole within a surface. The edge zipper can be used to join two mismatched surface edges that are within close proximity to one another, so that a closed surface is formed. Two different tools are available to help close off holes, namely the polygonal patch fill and the hole filler.

    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.

  • The hole filler is a more exact method of filling well-defined holes by using a closed loop feature edge definition around the hole.
  • missing faces: This refers to open cells where 1 or more faces are missing and elements need to be created to make a valid 3D cell

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.


Filters
Six basic repair filter types (or predicates) available to use are listed below. Filter predicates can be used individually to search for parts or pieces of geometry and/or can be compounded within a filter, using logical operators (AND, OR or PIPE) to provide additional control.
  • Part Name: Search for parts based on the presentation name
  • Part Surface Name: Search for part surfaces based on the presentation name
  • Area: Search for faces/surfaces based on the area
  • Volume: Search for closed surfaces based on the volume
  • Area/Volume Ratio: Search for closed surfaces based on the area/volume ratio
  • Face Count: Search for faces/surfaces based on the face count

Continua: Solver Setting

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.

STAR-CCM+ Solution Type and Material

STAR-CCM+ Solution: Coupled vs. Segregated

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.

STAR-CCM+ Multiphase Selection

STAR-CCM+ Equation of State and Viscous Regime

Set Boundary Conditions

STAR-CCM+ 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.

STAR CCM+ Auto Save

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.

Stopping Criteria in STAR-CCM+

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.

Monitor-based Stopping Criteria

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.
Save images on remote HPC cluster/server: Under the 'Scene' tab, there is option Update. Activate save picture to save the Scene at specified iterations or intervals.
Transient Tables in STAR: The variable name can contain a units specification. The units are specified within a set of parentheses () as part of the variable name:
"Time (s), "Temperature (C)"
0, 25
2, 50
5, 75

STAR-CCM+ Read CSV

Read .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.
  1. The name of field functions can contain few special characters: For example 'Split@X=0.50[m]' is a valid name.
  2. If the name contains any non-alphanumeric characters other than underscore '_', enclose the field function name in curly braces, '{...}' such as ${Split@X=0.50[m]} or ${test-Temperature}.
  3. Creating Field Function Expressions: color code to guide the editing process
    • Green indicates a syntactically correct reference to an existing field function
    • Parentheses appear in yellow to indicate the matching parenthesis
    • Red indicates an incorrect entry
    • If a field function reference has red text (but no black text or red background) the color represents a syntactically correct reference to a field function that does not yet exist
    • Field function definitions are always done in SI units, independent of the units that you use for input or display.
  4. Scalars are defined with single $ such as $Pressure or $Time and vectors with $$ such as $$Position and $$Velocity
  5. Field function names are case-sensitive. Thus, $Time and $time or $Radius and $radius are not same. Since the names are case-sensitive, they must be entered in the field function definition exactly as they are shown in the function name.
  6. Field functions access data on specific parts that are defined in the simulation
  7. Field functions used to define expressions cannot be a function of space that is (x, y, z). They must evaluate to a single number as the expressions are constants in space. Variables such as $Time, $TimeStep, and $Iteration are valid where as variables such as $Temperature or $Pressure are not valid as they have different values at every point in space and hence cannot be used in expressions.
  8. Literal constants can have a unit specification in a different system and are parsed at run time. The syntax for the units is <number units>. For example: <0.001 kg/m/s>, <10 psi>, <0.05 lb/ft^3> The character hyphen "-" binds tighter than "/", so kg/m-s^2 equals (kg)/(m-s^2) not (kg/m)*(s^2).
  9. When defining an expression or a field function that reference other field functions within it, prefixed that Field Function with $, such as $vol_flow_rate.
  10. Components of vectors are retrieved by adding additional $ such $$Velocity[0], $$Velocity[1] and $$Velocity[2] refer to X-, Y- and Z-components of the velocity vector. Subscript operator [] is appended to access components of the vector with indices of [0], [1], or [2].
  11. $$Position(@CoordinateSystem("CylCS"))[0] - The components of a local cylindrical coordinate system is defined by @CoordinateSystem(<Name of Coordinate System>) where <Name of Coordiante System> = "CylCS" in this example. Note that $$Position[0], $$Position[1] and $$Position[2] refer to r, θ and z axes respectively.
  12. When field functions are accessed on boundary parts, following rules by default: 1) If the data is stored on the boundary, the boundary data are accessed. For example "wall velocity" values stored in wall boundaries. 2)If the data is not stored on the boundary, the cell data from the cells in the region adjacent to selecte boundary are accessed. For example, wall-adjacent fluid velocity are stored in the cells.
  13. When Ignore Boundary Values option is switched ON, the field function is evaluated from the data stored for cell next to the boundary.
  14. To define a vector, array or position field function in terms of its components, specify the 3 components inside square brackets separated by commas: [($$Centroid[0] <= 1.0) ? 2.5 : 0.0, 0.0, 5.0]
  15. Initialize a particular volume: $${Position}[0] >= 0.50 && $${Position}[1] <= 1.00 && $${Position}[0] <= 2.50 && $${Position}[1] >= 0.25 ? 300 : 323 - this sets temperature in a cuboid to 323 [K]. To initialize a field variable in spherical volume: $$Position( @CoordinateSystem( "Laboratory.spheric" ) ) <= 0.50 ? 323 : 300. This is equivalent to: if($$Position( @CoordinateSystem( "Laboratory.spheric" ) ) <= 0.50, 323, 300).
  16. Set transient boundary condition where temperature ramps up linearly from 300K to a value of 500 [K] at a time of 5 [s]. ($Time >= 5.0) ? 500 : 300 + (500 - 300)/5.0*$Time. This is short form of conditional IF-ELSE statement. Ternary operator "? :" defines a condition operation similar to the C language.
  17. Divergence of velocity ∇.v = div($$Velocity), Divergence of density, velocity ∇.ρv is specified as: div($Density * $$Velocity), Gradient of pressure ∇p is specified as: grad($Pressure), Curl of velocity ∇×v is specified as: curl($$Velocity).
  18. Pressure ratio to get pressure in atmosphere [atm] unit: ${AbsolutePressure}/101325.0. Note that the default pressure option in Star CCM+ is given as absolute pressure rather than the relative presure.
  19. User field functions can be previewed by without actually running the simulation. The output values for the dependent variable is calculated by substituting the values of each of the independent variables and sweeping through the specified range.
  20. The dot product can be used to find components of a vector where unit($$Area))*unit($$Area) is used to define unit vector for area. For example, normal component of wall shear stress: sN = dot($$WallShearStress, unit($$Area)) * unit($$Area). Since, $WallShearStress is a vector sum of normal and tangential shear stresses, sT = $$WallShearStress - $$sT
  21. Multiple if conditions - Split a region (Split Regions by Function dialog) into 3 parts: ($$)Position[1] <= 2.5) ? 1 : (($$Position[1] >= 0.5) ? 2 : 0). In this case, after the split: The cells where 0.5 < y < 2.5 belong to Region 1, as the field function does not affect them. The cells where y ≤ 0.5 belong to Region 1 2, as it is the created region with the least cells. The cells where y ≥ 2.5 belong to Region 1 3, as it is the created region with the most cells.
  22. stepFun = ($$Centroid[2] <= 50) ? 0 : 1 - this creates a step function at the global z-coordinate of centroids of cell ≤ 50
  23. Field function for temperature dependent thermal conductivity: thCondAir = 1.52e-11 * pow($Temperature,3) - 4.86e-8 * pow($Temperature,2) + 1.02e-4 * $Temperature - 3.93e-4 where T is in [K]. As per the formulat, thCondAir = 0.0262 [W/m-K] at T = 300 [K].

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:
  1. Single stream option: in this case only one of the fluid streams (usually the cold stream) is modeled explicitly - by specifying the heat exchanger enthalpy source, while the second stream is assumed to have a uniform temperature that user specifies. This is activated by using option Heat Exchanger for Energy Source Option for the individual Region node.
    • Heat Exchanger Exit Temperature Specification is used to choose between specifying the heat transfer rate and predicting the outlet temperature or vice versa.
    • Here V denotes volume of the cells, u the the velocity and NC refers to total number of cells. Note that there are 3 unknowns: local velocity, local temeperature and local heat transfer rate.

      Single Stream heat transfer rate calculation

    • When this condition is choosen to be 'Inferred', the heat transfer rate can be specified by accessing the Heat Exchanger Energy Transfer physics value node.
    • For a heater, the hot stream [e.g. coolant path in automotive radiator] is assumed to have an infinite thermal capacitance and the specified heat exchanger temperature TH refers to the constant temperature of the hot stream.
    • For specified heat exchanger energy transfer rate Q, the inlet cold stream [e.g. air in automotive radiators] temperature TCI, and the cold stream specific heat CpC, an energy balance could be used to predict the cold stream exit temperature TCO as TCO = TCI + Q / CpC / mC where mC is mass flow rate of the cold fluid.
    • Heat Exchanger First Iteration: This node specifies the iteration from which the heat exchanger enthalpy source is active and begins its contribution to the source term of the energy equation.
    • It is recommended to active the source term when the flow is beginning to conform to its expected pattern, at least in terms of direction. As per user manual, 50 iterations is a good estimate to get a reasonable conformity.
  2. Dual stream option: here both the streams are modeled explicitly by defining two overlapping regions and creating a heat exchanger interface between them. This model supports
    1. fluid-solid interface where the heat exchange occurs between a solid region and a fluid region and
    2. As seen in the expression, the heat transfer rate is calculate after dividing by average volume of the cells - it is recommended to keep the volume of the cells as uniform as possible.

      Dual Stream heat transfer rate calculation

    3. fluid-fluid interface where the heat exchange takes place between two fluid regions. For a fluid-fluid type heat exchanger, following options are available for specifying heat transfer rate in the heat exchanger:
      • UAL Polynomial [UAL is function of cold flow velocity], UAL Table [UAL is a table of the cold flow velocity], UAL Map [map of curves to specify the UAL directly when multiple heat exchanger curves]: UA refers to the product of the Overall heat transfer coefficient (U) and the Area of the heat exchanger (A). UAL refers to the local (or cell value of) heat transfer coefficient (in W/K), with L referring to local.
      • UAG [U.A Global] Table
      • Q Table [table of the cold stream mass flow rate for one value of hot stream mass flow rate], Q Map [series of curves from which it calculates UAL].
    4. Basic option: This option solves for a simpler version of the energy equation using only the convective term and the source term to yield a solution. Heat Exchanger Topology:
      • When using the basic option, ensure that the core mesh is constructed of uniform cells.
      • In other words, all the cells in the heat exchanger region must be of comparable cell volume, as the cell volumes do not enter the calculation of the UAL table in the basic model.
      • The accuracy of results that the actual dual stream heat exchanger predicts does not depend on the uniformity of the mesh.
      • The topology must contain two identical regions with a different continuum associated with each region.
        • Both the regions [hot and cold streams] should be created from the same mesh continuum. To ensure this, copy the [core region of the radiator] region after the volume mesh has been generated.
        • Once the two overlapping regions exist, the heat exchanger interface can then be created by selecting the two regions and choosing Create Interface from the right-click menu. While selecting the two regions, select the region representing the cold stream before the region representing the hot stream.
        • The mesh alignment option should be activated so that a conformal match is obtained across mesh interfaces. STAR-CCM+ does not automatically generate a conformal mesh across interfaces for the trimmed cell mesh type. Operations > Automated Mesh > Meshers > Trimmed Cell Mesher node and activate Perform Mesh Alignment.
        • Create a block shape part around the core which required for the volumetric controls that define mesh refinement. Geometry > Parts node and select New Shape Part > Block.
    5. Actual option: UAL Map method is available with the actual dual stream heat exchanger option only.
  3. In both the options, heat is added or removed from the core cells as a source or sink term in the corresponding fluid energy equation. It is assumed in this section that both the streams exist only in a single phase (liquid or gas) and no phase change occurs inside the heat exchangers.

STAR Heat Exchanger Data

STAR Dual Stream


Solution

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.

Batch Runs on HPC Clusters

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:

STAR Meshing in Parallel

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.
Post-Processing

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.

Scalar Scene

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:
  • -a: Displays all information
  • -c license_files: Uses the specified license files
  • -f [feature]: Displays 'users' of feature. If feature is not specified, all features are displayed
  • -i [feature]: Displays information from the feature definition line for the specified feature, or all features if feature is not specified
  • -s [server]: Displays status of all license files listed in $VENDOR_LICENSE_FILE or $LM_LICENSE_FILE on server, or on all servers if server is not specified
  • -S [vendor]: Lists all users of vendor’s features
  • -t timeout_value: Sets connection timeout to timeout_value which limits the amount of time 'lmstat' spends attempting to connect to server.
On Windows machines, you can use: "<Installation-Folder>\lmstat.exe" -s licServer -i licFeature > licStatus.txt to print the output to a file. To know what are the name of features available in license file, use -a option, that is: "<Installation-Folder>\lmstat.exe" -s licServers -a > licStatus.txt. Alternatively, you can copy the lmutil.exe file from installation folder to any other local folder and use the command: c:/Users> lmutil.exe lmstat -s licServers -a. lmutil.exe is an independent executable supplied with different commercial tools such as ANSYS, ANSA, STAR-CCM+ and lmutil.exe supplied with STAR can be used to fetch licenses for ANSYS by supplying appropriate server names.

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.


Java Macros
Batch mode for macros is run from the command line using the -batch option: % starccm+ -batch sim_1.java sim_1.sim. Playing Macros Within Macros: it is allowed to create a macro that calls other macros. Setting values using a macro follows the same logical sequence as expanding nodes in the object tree. Each of the entities in STAR-CCM+ is an object and to locate an object, the hierarchy of the object tree should be followed. For example, the initial velocity object is contained in a physics continuum object, which is contained in a simulation object.

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.

Java Code Example

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.neo

Inheritance, 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 strings: charAt(), codePointAt(), codePointBefore(), codePointCount(), compareTo(), compareToIgnoreCase(), concat(), contains(), contentEquals(), copyValueOf(), endsWith(), equals(), equalsIgnoreCase(), format(), getBytes(), getChars(), getChildren(), hashCode(), indexOf(), intern(), isEmpty(), join(), lastIndexOf(), length(), matches(), offsetByCodePoints(), regionMatches(), replace(), replaceAll(), replaceFirst(), split(), startsWith(), subSequence(), substring(), toCharArray(), toLowerCase(), toString(), toUpperCase(), trim(), valueOf()

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 repTags = mfr_1.getTagGroup() .getObjects(); if (repTag.contains(tagText)) { ... } else { .... }

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:
  • Create a report class: e.g. MaxReport, SumReport, VolumeIntegralReport, AreaAverageReport...
  • Create a Primitive Field Function of desired variable such as Temperature, Volume, Density, Specific Heat...
  • Give a name fo field function using setFieldFunction
  • Get the region name and assign it to the report definition
  • Add loops as needed

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


User Code: User code allows STAR-CCM+ to be customized with functions written in a compiled language such as C, C++ or Fortran, available under the "Tools > User Code" node. User libraries are shared-object libraries (files with the platform-dependent extension .so , .sl or .dll ) containing one or more user functions and a library registration function. A user library that is compiled on one platform (say Windows) is not binary compatible with another platform (say Linux).


User Functions: User functions are functions or subroutines that are written in a compiled language such as C, C++ or Fortran.

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.

Java Macro to create axis


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 exists
PhysicsContinuum 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

Get the bounding box of visible object(s) where the computeVisibleBounds returns an array of (maxx, minx), (maxy, miny), (maxz, minz). You can return an Array by using .toArray() instead of .toString(). Ref: community.sw.siemens.com/how-to-get-a-parts-enclosing-box-vertices-using-a-macro
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();
Contact us
Disclaimers and Policies

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.