Professional Documents
Culture Documents
ConverterV5 3FinalVersion
ConverterV5 3FinalVersion
Computational Meshes
Gambit Meshfile (*.msh) in 2- and 3-D
LPPD-Project Report
Chicago, 4/11/2008
1
Update by Grant Hartung
Addition of
Chapter 1: mm Header Files for Mesh
Chapter 5: Three Dimensional Mesh (Hexahedrons)
Chapter 6: cs31/nwk Files
4/1/2016
Version 2
Update by Guoren Xu
Addition of
Chapter 10: Raw Image Formats
10/10/2016
Version 3
Version 4
Version 5
2
Table of contents
1 Summary......................................................................................................................7
2 CHAPTER 1: mm Header Files for Mesh Files (.mm)...............................................8
3 CHAPTER 2: Two Dimensional Meshes (Quads)....................................................11
3.1 The Points Section: (0 "Dimension:").....................................................11
3.2 The Faces Section: (0 "Faces:")....................................................................12
3.3 The Cells Section: (0 "Cells:")......................................................................12
3.3.1 Interior with no subdivisions - Default-Interior.............................................12
3.3.2 Interior with several subdivisions..................................................................12
3.4 The Zones Section: (0 "Zones:")....................................................................13
3.4.1 Boundaries no subdivisions – default wall....................................................13
3.4.2 Implementation of Zones:..............................................................................14
3.4.3 Interior with several subdivisions..................................................................14
4 CHAPTER 3: Two Dimensional Mesh (Triangles)...................................................15
4.1 The Points Section: (0 "Dimension:")...................................................15
4.2..................................................................................................................................16
4.3 The Faces Section: (0 "Faces:")...............................................................16
4.4 The Cells Section: (0 "Cells:")...............................................................17
4.5 The Zones Section: (0 "Zones:").............................................................17
5 CHAPTER 4: Three Dimensional Mesh (Tetrahedrons)...........................................19
5.1 The Points Section: (0 "Dimension:").....................................................19
5.2 The Faces Section: (0 "Faces:")...............................................................19
5.3 The Cells Section: (0 "Cells:")................................................................21
5.4 The Zones Section: (0 "Zones:")..............................................................21
6 CHAPTER 5: Three Dimensional Mesh (Hexahedrons)...........................................23
6.1 The Points Section: (0 "Dimension:").....................................................24
6.2 The Faces Section: (0 "Faces:")...............................................................24
6.3 The Cells Section: (0 "Cells:")................................................................28
6.4 The Zones Section: (0 "Zones:")..............................................................28
7 CHAPTER 6: cs31/nwk Files....................................................................................29
7.1 The Case File Section: (.cs31).....................................................................29
7.2 The NWK File Section: (.nwk)......................................................................30
8 CHAPTER 7: – Neutral Files....................................................................................30
3
9 CHAPTER 8: – Nastran Files....................................................................................32
9.1 The NASTRAN File..........................................................................................33
10 CHAPTER 8 – Conversion of msh to Nastran..........................................................35
11 CHAPTER 9 – Extraction of JPEG, TIFF and STL Files.........................................36
12.......................................................................................................................................37
13 CHAPTER 10 – Raw Image Formats........................................................................38
13.1 DICOM..............................................................................................................38
13.2 JPEG..................................................................................................................39
13.3 TIFF...................................................................................................................39
13.4 PNG...................................................................................................................42
13.5 BMP...................................................................................................................42
14 CHAPTER 11 – FLUENT Data Formats..................................................................43
14.1 Mesh File Format...............................................................................................43
14.1.1 Mesh Converter.........................................................................................43
14.1.1.1 Step 1: Modify the Header.................................................................43
14.1.1.2 Step 2: Reading the point coordinate matrix.....................................44
14.1.1.3 Step 3: Reorder the face matrix.........................................................44
14.1.1.4 Step 4: Minimize the Zone Section...................................................44
14.2 Data File Format................................................................................................45
14.2.1 Writing a Walk-In Brain Case File From FLUENT..................................45
Summary..............................................................................................................45
Step 1:...................................................................................................................45
Step 2:...................................................................................................................45
Step 3:...................................................................................................................45
Step 4:...................................................................................................................46
Step 5:...................................................................................................................47
15 References..................................................................................................................48
16 Appendix....................................................................................................................48
16.1 CTRIA3 Format.................................................................................................53
16.2 CQUAD4 Format...............................................................................................54
17 Delphi converter application......................................................................................59
17.1 Summary............................................................................................................59
17.2 Main functions...................................................................................................60
17.2.1 Convert NWK Files to Splines..................................................................60
4
17.2.2 Convert CaseFiles To Splines....................................................................61
17.2.3 Convert Splined to Even2ptmesh..............................................................63
17.2.4 Editing and Movement..............................................................................65
17.2.5 CleanSplinedNW.......................................................................................66
17.3 Additional functions for visualization and statistics..........................................68
17.3.1 DisplayNWK.............................................................................................68
17.3.2 SplineNWKStatistics.................................................................................68
17.3.3 NWKStatistics...........................................................................................69
18 Converting among mesh and stl................................................................................69
18.1 Converter from mesh to stl................................................................................71
18.2 Case Study A: Tetrahedral Tube Mesh..............................................................72
18.3 Converter from stl to msh..................................................................................72
18.4 Walk through of viewer application for visualizing mesh files.........................73
19 Registration of two objects........................................................................................74
19.1 Walk through of viewer application for visualizing mesh files.........................75
20 Documentation of ICEM/GAMBIT mesh converter.................................................78
20.1 Converting ICEM mesh file to GAMBIT mesh file:.........................................79
20.2 Instructions for converting from GAMBIT to ICEM:.......................................81
21 Documentation of Delphi “.cs31” and “.casx” converter..........................................83
21.1 Converting .cs31 file to .casx file:.....................................................................84
21.2 Instructions for converting from .casx to .cs31:................................................87
22 Reading and Visualizing casx files in Matlab...........................................................89
Table of figures
Figure 1. The grid consisted of triangles as described in this report................................19
Figure 2. A tetrahedral volume of the mshFile example given herein..............................24
Figure 3.3: Volume numbering scheme for hexahedral meshes......................................29
Figure 4. ADINA mesh created by a Nastran file. The force is applied at node 5 (in
center). Element numbers are located in the center of each cell (in purple)......................34
Figure 5. A mesh extracted in VTK by applying the Delaunay Triangulation...........38
Figure 6. Converter software GUI.....................................................................................60
Figure 7. Accessing converter from the Viewer application.............................................60
Figure 8. Main tabs in the converter..................................................................................61
Figure 9. Procedure to convert 2-point networks to spline networks................................61
Figure 10. Conversion of 2-point network to spline network............................................62
Figure 11. Procedure to convert 2-point networks to spline networks..............................63
Figure 12. Two sample results of the linear fitting of diameter in each spline. The red plot
is the original spline network diameter and the green plot is the linear fit........................63
Figure 13. Conversion of 2-point case and network to spline case and network. The
original 2-point network is on the left and the spline network on the right.......................64
5
Figure 14. Procedure to convert spline networks to 2-point networks..............................65
Figure 15. Conversion of spline case and network to 2-point case and network. The
original spline network is on the left and the 2-point network is on the right. The face
(edge) indices are also represented in both networks........................................................65
Figure 16. Procedure to convert spline network point properties to 2-point format.........66
Figure 17. Conversion of spline network point property (pressure in this case) to 2-point
format. ...............................................................................................................................66
Figure 18. Procedure to convert 2-point networks to spline networks..............................67
Figure 19. Conversion of spline case and network to 2-point case and network. The
original spline network is on the left and the 2-point network is on the right. The face
(edge) indices are also represented in both networks........................................................67
Figure 20. Procedure to clean spline networks with dangling vessels..............................68
Figure 21. Removal of dangling splines. The original spline network is on the left and the
2-point network is on the right. The face (edge) indices are also represented in both
networks.............................................................................................................................69
Figure 22. Generating a simple mesh in ICEM. Make surface for generating mesh. (d).
Save it as ANSYS Fluent mesh or STL. (E). Simple mesh. (F). Coordinates shown on the
mesh. (G). STL format of same geometry. (H). Gambit format of same geometry. ........71
Figure 23. STL and mesh files comparison. (A). STL file of format for the shown
geometry in Figure 24. (B). Gambit file of same geometry..............................................72
Figure 26. Visualization of converted stl to mesh and original mesh in
ViewerApplication. (A). original sled mouse msh file. (B). Converted to STL and back to
msh. Note that the anatomical grouping is lost during the conversion process.................72
Figure 25. Visualization of converted mesh to stl and original stl in Cerebroview. (B)
Converted Mesh to stl. (C) original stl..............................................................................73
Figure 26. Visualization of converted stl to mesh and original mesh in
ViewerApplication. (A). original sled mouse msh file. (B). Converted msh ...................73
Figure 27. Viewer application form used for visualizing mesh file. (A). Red box shows
the bottom for loading msh file. (B). Visualizng the mesh in viewer application.............75
Figure 28. Registration form. (A). the general view of the registration form. (B). Red box
shows where user needs to insert four points of object one and two, and the bottom for
computing the transformation information. (C). Red boxes show the transformation
matrix, offset vector and eligned second object on object one. (D). visualization of the
eligned points.....................................................................................................................78
Figure 29. Applying transformation matrix on the network in viewer application. Two
misaligned objects, Object 2. The last picture is object two that is aligned with object1. 79
Figure 29. Original ICEM mesh file visualized in ICEM. This is a monkey spine. This
mesh was found amongst the data received from a collaborator. At the time, it was not
able to be loaded by any visualization tools or Delphi programs for processing, a perfect
case to be used within the confines of our converter.........................................................80
Figure 29. The ICEM mesh file has been converted to GAMBIT format and visualized
using ViewerApplication.exe.............................................................................................82
Figure 29. Visualization of the GAMBIT file generated using the converter in Section
22.1. This file is named M1V3.GAMBIT.msh and is located in
S:\__temp\grantConverters................................................................................................82
6
Figure 29. Visualization of the ICEM file generated from the coversion process. This file
is named M1V3.GAMBIT.icem.msh and is located in S:\__temp\grantConverters. Loaded
into ICEM using ImportMeshFromFluent.....................................................................84
Figure 29. Visualization of the original cs31 and nwk file created from grant’s artificial
network generation code (version 1), Project_KFGenAndSolvingApp.exe.......................85
Figure 29. Visualization of the .casx file after being converted from .cs31......................88
Figure 29. Visualization of the .casx file after being read by the casx file reader in Step 2.
...........................................................................................................................................89
Figure 29. Visualization of the converted file (V2) in viewer application........................90
Figure 30: Main workflow of the Matlab code..................................................................90
Figure 31: (A) Arteries and vein fused structure (B) Simple bifurcation..........................91
Figure 32: Matlab compiler used to convert an .m file into a stand-alone executable......91
Figure 33: Running the stand-alone executable from the command prompt.....................92
7
1 Summary
This report presents an overview of the structure of *.msh and Nastran (*.nas) files.
These files are extracted via the well-known mesh generator Gambit. The extracted *.msh
files are subsequently used for Fluent solver to perform CFD simulations. The main
features of the msh files are addressed herein. These are the information given about the
points, faces and volumes that are used for the development of computational domain. As
we will see in the following chapters, the *.msh files follow a specific format in both 2D
and 3D coordinates in order to be readable from Fluent or any other solver.
In Chapter 1, an overview of the mesh structure for two-dimensional grids formed by
quadrilaterals is given. In Chapter 2, an example of two-dimensional grid formed by
triangles is thoroughly discussed. The main features of three-dimensional meshes are
analyzed in Chapter 3. Along with this, we also address the differences between three-
and two dimensional meshes generated by Gambit. In Chapters 4 and 5, two type of files
used in Finite Element Methods, namely Neutral (*.neu) and nastran (*.nas) files are
described. Finally, we describe the use of a converter from *.msh to *.nas files and in
Chapter 7, an overview of how different type of image files (*jpeg, *tiff and *Stl) are
extracted through the VTK is given.
2 CHAPTER 1: mm Header Files for Mesh Files (.mm)
This report describes the format of mm header files *.mm which are supported by the
Gambit mesh format. Mm files are ASCII files that can be used to hold simulation
parameters and data applied to a mesh file. It will include imported simulation parameters
such as constants and boundary conditions. Once a mesh (2D or 3D) is generated in the
Gambit format, a header mm file is used to hold simulation output data correlating to the
mesh.
<model header= gives a header to display to the user and initiates the section on
simulation parameters.
problemtype= tells the simulation what type of problem to solve, in this case it is a
diffusion problem.
The mesh that is to be simulated on needs to be linked to the simulation. This is done in
the header file in a section entitled “meshfile” where a link to the mesh file is presented.
<meshfile>
meshfile=C:\andi\MG.V1\PurePascalMGV78_Ian_PhD\Data\msh\grid2_2D_2096.GAMBIT.
v2.msh
</meshfile>
<meshfile> opens the section linking the mesh file to the current simulation.
Meshfile= tells the simulation the full path and name of the file containing the mesh to
be simulated.
<meshfile> ends the mesh file section.
<BoundaryConditions>
bc0=<SubSection VarId=1 ID=17 type=Dirichlet value=10/>
bc1=<SubSection VarId=1 ID=18 type=Dirichlet value=10/>
bc2=<SubSection VarId=1 ID=19 type=Dirichlet value=10/>
bc3=<SubSection VarId=1 ID=20 type=Dirichlet value=0/>
</BoundaryConditions>
(vector=metabolism cell) The data in this section is set by the user to be “metabolism
cell” data.
(N=324 This section has 324 volumes and each volume is of type=variable) type,
meaning that it is not a constant input to the simulation but rather a calculated output of
the simulation.
(12 Volumes
(0 1 144 0 0)( Group “0” of volumes starting at volume “1” ending at volume “144” data
will follow.
2.0905428004 The value corresponding to the cell metabolism of volume 1 from the mesh file.
2.2701978308 The value corresponding to the cell metabolism of volume 2 from the mesh file.
2.448617957 The value corresponding to the cell metabolism of volume 3 from the mesh file.
2.6426070344 The value corresponding to the cell metabolism of volume 4 from the mesh file.
) Closes the vector of data.
After this line, another vector of data can begin (like “Pressure” for instance). If there is
more than one simulation variable, they can be listed after the previous simulation
variable. The second, third (and so forth) variable is listed in the exact same manner as
the first simulation vector:
(vector=pressure)
(N=324 type=variable)
(12 (0 1 144 0 0)(
...
)
(vector=pressure) The data in this section is set by the user to be “pressure” data.
(N=324 This section has 324 volumes and each volume is of type=variable) type,
meaning that it is not a constant input to the simulation but rather a calculated output of
the simulation.
(12 Volumes
(0 1 144 0 0)( Group “0” of volumes starting at volume “1” ending at volume “144” data
will follow.
... The value corresponding to the cell metabolism of the volumes in the mesh file.
) Closes the vector of data.
In the case that there are multiple time steps in a data section, the first vector cannot be a
time-variant variable. The time-variant variable (such as pressure simulated dynamically)
must begin with the second vector and has no limit to how many time points can be
saved. The header for the time data is as follows:
(vector=vorticity|1 cell)
(N=324 type=variable)
(12 (0 1 144 0 0)(
2.0905428004
2.2701978308
2.448617957
2.6426070344
2.837910575
3.0007178796
3.2883297019
3.983310066
...
)
(vector=vorticity|1 cell) The data in this section is set by the user to be “vorticity”
data for timepoint “1” and is designated by each “cell”. In this way, timepoint 2 would
read “(vector=vorticity|2 cell)”.
(N=324 This section has 324 volumes and each volume is of type=variable) type,
meaning that it is not a constant input to the simulation but rather a calculated output of
the simulation.
(12 Volumes
(0 1 144 0 0)( Group “0” of volumes starting at volume “1” ending at volume “144” data
will follow.
2.0905428004 The value corresponding to the cell metabolism of volume 1 from the mesh file.
2.2701978308 The value corresponding to the cell metabolism of volume 2 from the mesh file.
2.448617957 The value corresponding to the cell metabolism of volume 3 from the mesh file.
2.6426070344 The value corresponding to the cell metabolism of volume 4 from the mesh file.
) Closes the vector of data.
In this part the numbers of points constitute the computational domain as well as their
coordinates is explicitly given.
(10 (0 1 9 1 2)) “(10 stands for points (0, 1: First index of points, 9: last index of
points, 1: x-coordinate, 2: y-coordinate))”
(10 (0 1 9 1 2)(
1.000000000e+00 1.000000000e+00
2.000000000e+00 0.000000000e+00
…
))
In this part, the faces that in 2D are consisted of two points as well as information about
the cells that such faces belong are given (see Chapter 2 for more details)
The cell sections specify the indices of cells belonging to interior domains. Each domain
must have contiguously numbered cell indices for this method to work (I guess Gambit
just makes sure that this is the case).
Example:
(12 (0 1 4 0))
Strangely the index ‘0’ is used here, while in the zones section an ‘8’ or sometimes a ‘6’
is used. This requires further research. It appears to be always the last index of a zone or
boundary plus 2.
Zeroth integer:
A leading ‘(12’ is a constant specifier for all zones.
The zones section specifies identifies for different groupings of cell divisions between
zones. Each grouping is associated with a particular integer that is also used in the face
definitions.
Example:
(0 "Faces:")
(13(0 1 18 0))
(13(3 1 c 3 0)(
2 5 6 9 0
…
))
In the lower sections of the file, there are two special sections:
The cells section (0 "Cells:") and the zones section (0 "Zones:")
…..
(0 "Cells:")
(12 (0 1 4 0))
(12 (2 1 2 1 3))
(12 (3 3 4 1 3))
(0 "Zones:")
(45 (2 fluid bottom)())
(45 (3 fluid top)())
(45 (4 wall wall3)())
(45 (5 wall wall2)())
(45 (6 wall wall1)())
(45 (8 interior default-interior)())
Example:
(0 "Cells:")
(12 (0 1 4 0))
(12 (2 1 2 1 3))
(12 (3 3 4 1 3))
(45 (2 fluid bottom)())
(45 (3 fluid top)())
(45 (4 wall wall3)())
(45 (5 wall wall2)())
(45 (6 wall wall1)())
(45 (8 interior default-interior)())
Zeroth integer:
A leading ‘(45’ is a constant specifier for all cells.
In this chapter, the format of a two-dimensional *.msh file consisted of triangular faces is
analyzed. Such type of files can be exported by the commercial Mesh Generator Gambit.
These files are subsequently used by the well-known Solver, Fluent. We use Courier for
the Grid Structure and Times New Roman for the comments embedded in the file. The
following sections are discussed herein. Firstly, we analyze the Msh File format by
adding comments in order to explain the most important parts of the file. A two-
dimensional, unstructured grid, generated through Gambit, is given as an example for
subsequent analysis (Figure 1). Such grid is consisted of triangles that are formed by
three points joined together in a counterclockwise fashion. Finally we refer to the form of
the file that can be used directly in Fluent in order to instantiate a grid also shown in
Figure 1.
Header: Any changes made in this section, do not influence the reader in Fluent.
(0 "GAMBIT to Fluent File") All brackets starting with “0” do not affect the reader.
In this part the numbers of points as well as their coordinates are explicitly given.
(10 (0 1 D 1 2)) “(10 stands for points (0, 1: First index of points, D: last index of
points, 1: x-coordinate, 2: y-coordinate))”
(10 (1 1 D 1 2)(
2.0000000000e+000 0.0000000000e+000
2.0000000000e+000 1.0000000000e+000
2.0000000000e+000 5.0000000000e-001
0.0000000000e+000 0.0000000000e+000
6.6666666667e-001 0.0000000000e+000
1.3333333333e+000 0.0000000000e+000
0.0000000000e+000 1.0000000000e+000
1.3333333333e+000 1.0000000000e+000
6.6666666667e-001 1.0000000000e+000
0.0000000000e+000 5.0000000000e-001
3.9306883226e-001 5.0000000272e-001
1.0000001220e+000 5.0000000017e-001
1.6069312862e+000 5.0000000119e-001
))
4.2
In this part, the faces that in 2D are consisted of two points as well as information about
the cells that such faces belong is given.
(13 (5 b 1a 2 0)( “(13 stands for faces ( 5: interior faces, b: first index of interior
faces, 1a: last index of interior faces, 2, 0))
2 4 b 1 2
“(2: number of points consist a face, 4: first point, b: second point, 1: first volume, 2:
second volume)
In the same fashion, we read the other interior faces shown below…
2 b a 1 4
2 5 b 2 e
2 7 b 3 4
2 b 9 3 c
2 8 d 5 9
2 d 2 5 6
2 d 3 6 7
2 d 1 7 8
2 d 6 8 b
2 8 c 9 a
2 c d 9 b
2 9 c a c
2 c 6 b d
2 b c c e
2 c 5 d e
))
In this section, information of the total number of cells in the domain is given.
(0 "Cells:") Header
(12 (0 1 e 0)) “(12 stands for cells (0, 1: first index of cells, e: last index of cells, 0))
(12 (2 1 e 1 1))
(0 "Zones:") Header
(45 (2 fluid fluid)()) (45 stands for boundary conditions or interior (2: interior,
fluid:fluid or solid: here is fluid, fluid: the name is fluid))
(45 (3 wall wall)()) “(45 stands for boundary conditions or interior (3: wall, wall: it
is a wall, wall: the name is wall))
(45 (5 interior default-interior)()) (45 stands for zones (5 is interior and
describes the volumes)
By performing the above analysis, we get information about the way that a Gambit msh
File is constructed. The point coordinates are given in the first section. The faces,
consisted of two points, are distinguished into boundary and interior faces. The numbers
of volume cells (in this case are consisted of three faces) are extracted by first and second
volume numbers that are seen in Faces section. It should also be noted that the volume
cells are always constructed following counter-clockwise direction, i.e. the cell 10 (V10)
in Figure 1 is given by the points 8, 9, 12.
V3 V10 V5
F-9 F-14 F-23 F-16 F-17 F-5
F-15 F-21 V9
V4 V12 V6
11 12 13
10 F-25 F-22 F-18 3
F-12
V14 V11
V1 F-26 V7
F-13 F-20 F-4
F-10 F-11 F-24 F-19
V2 V13 V8
4
F-1 5 F-2 6 F-3 1
Figure 1. The grid consisted of triangles as described in this report.
Note: The numbers in the Gambit *.msh File is written in hexadecimal notation.
This is because hexadecimal numbers request less space than decimal.
5 CHAPTER 4: Three Dimensional Mesh (Tetrahedrons)
In this part, the dimensions of the domain, the total number of points as well as the point
coordinates are given. The “Dimensions” part begins with the header (0
"Dimension:"). In the next line the type of medium used (solid or fluid) as well as the
dimensions of the domain are given, (2 3). The number “2” stands for fluid as
continuum and “3” for the dimensions of the domain (3D). This line is used as an
identifier of the dimensionality of msh File. It is important to note that in three-
dimensions the second digit in this line is 3, while in two-dimensional domains it is given
as 2. The total number of points and the number of coordinates to where these refer is
given in the next line:
(10 (0 1 9 1 3))
The points numbering starts from “1” and ends at “9” and three space coordinates (x, y,
z) shown as “1 3” are subsequently given. The point coordinates are given in following
lines starting from “1” as:
(10 (1 1 9 1 3)(
5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
3.3882497385e-003 -3.2219810665e-006 4.9988601721e-004
))
The first column refers to x-coordinates while the second and third column give the y-
and z-coordinates of the points, respectively.
5.2 The Faces Section: (0 "Faces:")
This section describes the connectivity of faces (i.e. which points are connected to form a
face), the type of faces (i.e. interior or exterior) as well as the volumes in which such
faces are belong to. The section begins with the header (0 "Faces:"). The next line
(13 (0 1 1e 0)) gives information for the total number of faces used in the domain.
In this line, “1” stands for the first index of faces and “1e” for tha last index. Thus, the
total number of faces in this particular domain is “1e”. The header “13” refers to faces. In
the following lines, the faces are subdivided into different parts, each of those references
the various boundary sections created by the user of Gambit.
The first subdivision, in this particular example is as follows:
(13 (3 1 2 3 0)(
3 6 1 8 3 0
3 4 1 6 4 0
))
Where the first line is analyzed as (13 : stands for faces (3: boundary given by the user
1: first index of faces 2: second index of faces 3: wall-boundary type 0)(
It should be noted that the “boundary given by the user” argument is read in conjuction
with the last section of mshFile, namely “Zones”.
In the next line, the number and the indices of points forming a face, as well as the
volume numbers to which these faces are adjusted, can be seen. For example,
3 6 1 8 3 0
3: stands for the number of points forming a face
6: First Point Index
1: Second Point Index
8: Third Point Index
3: First Volume Index
0: Second Volume Index (0 stands for boundary)
In the same fashion, the reader identifies the subsequent subdivisions of boundary faces.
After the boundary subdivisions, the interior faces are specified. The header (13 (a d
1e 2 0)( is analyzed as follows:
13: stands for faces
a : stands for interior (see zones section)
d : first index of interior faces
1e: last index of interior faces
2 : default-interior
In the following lines the same information discussed for the aforementioned boundary
faces are given. For example, the next line is:
3 8 9 7 2 1
where:
3: stands for total number of points
8: First Index of Points
9: Second Index of Points
7: Third Index of Points
2: First Index of Volumes
1: Second Index of Volumes
It should be noted that in two-dimensions the first argument is “2” followed by just two
point indices. This is because in 2D a face is formed from just two points while in 3D a
face (or surface) is consisted from three different points.
Likewise, we read the subsequent lines below.
In this section, the total number of cells of the domain are given. The following lines are
seen:
(0 "Cells:")
(12 (0 1 c 0))
(12 (2 1 c 1 2))
In this section, the type and the name of continuum, the types of boundary as well as the
interior conditions are specified. In this particular example, the last section of the mshFile
is as follows:
(0 "Zones:")
(45 (2 fluid fluid)())
(45 (3 wall w6)())
(45 (4 wall w5)())
(45 (5 wall w4)())
(45 (6 wall w3)())
(45 (7 wall w2)())
(45 (8 wall wall1)())
(45 (10 interior default-interior)())
In the first line, a header is shown. The next lines are referred to the types and names of
boundary conditions created by the user.
In Figure 2 the first volume (1) of the domain described above is depicted.
2
8
Figure 2. A tetrahedral volume of the mshFile example given herein.
From the analysis of the mshFile, it is obvious that the first tetrahedron is consisted of the
following four faces:
From the above lines, we also retrieve the information that faces 2, 3 and 4 of Volume 1
are also adjacent to volumes 2, 9 and c, respectively. It means that in a computational
domain consisted of tetrahedrons (four faces in total), there are interior faces (belongs
also to adjacent volumes) and boundary faces. The number of the boundary and interior
faces depends on the position of tetrahedron in the domain.
Note that the numbers in *.msh File are written in hexadecimal notation.
In this part, the dimensions of the domain, the total number of points as well as the point
coordinates are given. The “Dimensions” part begins with the header (0
"Dimension:"). In the next line the type of medium used (solid or fluid) as well as the
dimensions of the domain are given, (2 3). The number “2” stands for fluid as
continuum and “3” for the dimensions of the domain (3D). This line is used as an
identifier of the dimensionality of msh File. It is important to note that in three-
dimensions the second digit in this line is 3, while in two-dimensional domains it is given
as 2. The total number of points and the number of coordinates to where these refer is
given in the next line:
(10 (0 1 9 1 3))
The points numbering starts from “1” and ends at “9” and three space coordinates (x, y,
z) shown as “1 3” are subsequently given. The point coordinates are given in following
lines starting from “1” as:
(2 3)
(10 (1 1 9 1 3)(
5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
3.3882497385e-003 -3.2219810665e-006 4.9988601721e-004
))
The first column refers to x-coordinates while the second and third column give the y-
and z-coordinates of the points, respectively.
(13 (3 1 6 0 0)(
4 0 1 2 3 1 0 //(Face 1)
4 4 5 6 7 1 0 //(Face 2)
4 4 0 1 5 1 0 //(Face 3)
4 4 7 3 0 1 0 //(Face 4)
4 1 2 6 5 1 0 //(Face 5)
4 2 6 7 3 1 0 //(Face 6)
))
Where the first line is analyzed as (13 : stands for faces (3: boundary given by the user
1: first index of faces (index of first face in group) 6: second index of faces (index of last face
in group) 0 0)(. It should be noted that the “boundary given by the user” argument
is read in conjunction with the last section of msh file, namely “Zones”. This number
represents the corresponding zone in the “Zones” section.
The point ordering in a face matrix for a hexahedral mesh are as follows. The first face
from is comprised of points 0, 1, 2 and 3 (Figure 5.1). The points must be listed in a
counter-clockwise fashion. The second face must begin with the point opposing the first
point from the first face (point 4 in this case as it opposes point 0). The second face must
be written in the same direction as the first face (in this case the point order needs to be 4-
5-6-7). The rest of the faces will be listed in the order shown in Figure 5.2.
3 7 s
2
4 s
0 5 5 a
1
Figure 5.1: An example hexahedron to be generated in GAMBIT mesh format. The
numbers correspond to the point numbering scheme in the sample code above.
In the next line, the number and the indices of points forming a face, as well as the
volume numbers to which these faces are adjusted, can be seen. For example,
4 0 1 2 3 1 0
4: stands for the number of points forming a face
0: First Point Index
1: Second Point Index
2: Third Point Index
3: Fourth Point Index
1: First Volume Index
0: Second Volume Index (0 stands for exterior boundary)
2
4
1 5
3
Figure 5.2: An example hexahedron to be generated in GAMBIT mesh format below.
The numbers correspond to the face ordering scheme.
In the same fashion, the reader identifies the subsequent subdivisions of boundary faces.
The face format of a hexahedral structure must follow that the first face is a face of the
user’s choice. The second face needs to be the opposing face.
After the exterior faces section, the interior faces are specified. The header (13 (a d 1e
2 0)( is analyzed as follows:
13: stands for faces
a : stands for interior (see zones section)
d : first index of interior faces
1e: last index of interior faces
2 : default-interior
0)(
In the following lines the same information discussed for the aforementioned interior
faces are given. For example, the hexahedral mesh from Figure 5.3 can be written as:
4 8 9 6 7 2 1
where:
4: stands for total number of points
8: First Index of Points
9: Second Index of Points
6: Third Index of Points
7: Fourth Index of Points
2: First Index of Volumes
1: Second Index of Volumes
8 s Volume 1
2 . 7
Volume 2
1 d
9
33s . 6
0 .
Figure 3.3: Volume numbering scheme for hexahedral meshes.
The correct face matrix for the object in Figure 3 can be seen below.
(0 “Faces:”) //(Faces section)
(13(0 1 B 0)) //(All faces (faces 1-B)
(13(1 1 8 0 0)( //(first face group, Exterior Faces, faces 1-10)
4 0 1 2 3 1 0 //(Face 1)
. //(Face 2)
. //(Face 3)
. //(Face 4)
))
(13(1 1 6 0 0)( //(second face group, Interior Faces, Face 9)
4 6 7 8 9 1 2
))
In this section, the total number of cells of the domain are given. The following lines are
seen:
(0 "Cells:")
(12 (0 1 c 0))
(12 (2 1 c 1 2))
(0 "Zones:")
(45 (2 fluid fluid)())
(45 (3 wall w6)())
(45 (4 wall w5)())
(45 (5 wall w4)())
(45 (6 wall w3)())
(45 (7 wall w2)())
(45 (8 wall wall1)())
(45 (10 interior default-interior)())
In the first line, a header is shown. The next lines are referred to the types and names of
boundary conditions created by the user.
(45 (3 wall w6)()) 45: stands for zones, 3: section 3 (see faces section) wall: type of
BCs w6: name of BC
(45 (4 wall w5)())
(45 (5 wall w4)())
(45 (6 wall w3)())
(45 (7 wall w2)())
(45 (8 wall wall1)())
This report describes the format of neutral files *.neu which are supported by the Gambit
mesh generator. The neutral files are ASCII type files that can be used to import or export
mesh data, including mesh point coordinates, cell-connectivity information and boundary
condition data. Once the mesh (2D or 3D) is generated through Gambit, from the Solver
(Command Tools) the option Generic is selected. Then the mesh is exported through the
option Export > Mesh under the File Bar. The exported file is seen as *.neu at the end
(i.e. Filename.neu).
The following sections describe the format of a two-dimensional Gambit Neutral File.
The first line : [CONTROL INFO 2.2.30] provides information about the version of
Gambit used to generate the *.neu file. It follows the Header for Neutral Files: [**
GAMBIT NEUTRAL FILE]
The following lines are also given information about the Program’s Version, the date and
the dimensions of the grid.
default_id2520
PROGRAM: Gambit VERSION: 2.2.30
Jan 2008
NUMNP NELEM NGRPS NBSETS NDFCD NDFVL
18 22 1 0 2 2
The NUMNP stands for the total number of nodal points in the mesh.
The NELEM stands for the total number of elements.
The NGRPS stands for the number of element groups.
The NBSETS stands for the number of boundary conditions set.
The NDFCD stands for the number of coordinates
The NDFVL stands for the number of velocity components.
The ENDOFSECTION string signifies the end of introductory section.
The next section gives information about the nodal point coordinates in the mesh.
NODAL COORDINATES 2.2.30 Header
1: First Point 0.00000000000e+000: x-coord. 4.00000000000e+000: y-coord.
1 0.00000000000e+000 4.00000000000e+000
2 0.00000000000e+000 0.00000000000e+000
3 0.00000000000e+000 2.66666666667e+000
4 0.00000000000e+000 1.33333333333e+000
5 3.00000000000e+000 0.00000000000e+000
6 1.00000000000e+000 0.00000000000e+000
7 2.00000000000e+000 0.00000000000e+000
8 3.00000000000e+000 4.00000000000e+000
9 3.00000000000e+000 1.33333333333e+000
10 3.00000000000e+000 2.66666666667e+000
11 2.00000000000e+000 4.00000000000e+000
12 1.00000000000e+000 4.00000000000e+000
13 7.66518491352e-001 3.19604214921e+000
14 1.96341923329e+000 1.85175317966e+000
15 1.84167491184e+000 3.11659564726e+000
16 9.76065872390e-001 1.00453448902e+000
17 1.99571175745e+000 7.10540275021e-001
18 9.40906865090e-001 2.17994810933e+000
ENDOFSECTION Header
The cells connectivity of the elements in the mesh is given in the following section:
1 First Cell 3 Element Type Geometry (3 for triangles) 3 Number of points consist the
first Cell element 12 First Nodal Point 1 Second Nodal Point 13 Third Nodal Point
The same for the subsequent elements/cells below:
1 3 3 12 1 13
2 3 3 13 1 3
3 3 3 8 11 15
4 3 3 8 15 10
5 3 3 4 2 16
6 3 3 16 2 6
7 3 3 16 6 17
8 3 3 17 6 7
9 3 3 5 9 17
10 3 3 5 17 7
11 3 3 15 11 12
12 3 3 4 16 18
13 3 3 4 18 3
14 3 3 17 9 14
15 3 3 14 9 10
16 3 3 3 18 13
17 3 3 12 13 15
18 3 3 10 15 14
19 3 3 16 17 14
20 3 3 16 14 18
21 3 3 18 14 15
22 3 3 15 13 18 Last Element/Cell
ENDOFSECTION Header
The last section described below provides general information of the mesh
fluid
0
1 2 3 4 5 6 7 8 9
10
11 12 13 14 15 16 17 18 19
20
21 22
ENDOFSECTION Header
This section analyzes the format of nastran files imported by the commercial FEM (finite
element method) software package, ADINA. We analyze the *.nas file format, noting its
structure and logic.
The *.nas file is a common file imported into finite element solvers. We will analyze a
two-dimensional, structured grid, plane strain model generated in ADINA. The grid
consists of uniformly sized quadrilaterals.
The NASTRAN file format contains mesh information and can be directly imported into
ADINA maintaining the mesh generated from a different program. Parasolid and IGES
file formats contain only geometric information, not mesh information. ADINA does not
import files of type *.msh generated by GAMBIT, which contains geometric and
meshing information.
Figure 4. ADINA mesh created by a Nastran file. The force is applied at node 5 (in
center). Element numbers are located in the center of each cell (in purple).
SOL 101 (analysis type)
CEND
$*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$*
$* CASE CONTROL
$*
$*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
SPC=10 (constraint)
LOAD=20 (loading condition; matches Force below)
DISP=ALL (print displacement of all nodes)
$*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$*
$* BULK DATA
$*
$*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
BEGIN BULK
GRID,1,,0.,0.,0.
GRID: 1-9=node numbers; i, j, k=nodal
GRID,2,,5.,0.,0. coordinates
GRID,3,,10.,0.,0. CQUAD: 4 node quadrilateral elements;
GRID,4,,0.,5.,0. 10=EGrp # 1-4=element numbers;
GRID,5,,5.,5.,0.
GRID,6,,10.,5.,0.
GRID,7,,0.,10.,0.
GRID,8,,5.,10.,0.
PSHELL: 10=group number;
GRID,9,,10.,10.,0.
CQUAD4,1,10,1,2,5,4 30=material number; 0.25=shell
CQUAD4,2,10,2,3,6,5 thickness, 30=material number
CQUAD4,3,10,4,5,8,7 MAT1: homogenous & isotropic;
CQUAD4,4,10,5,6,9,8 30=material number; 3.E7=value of
Young’s modulus; 0.33=Poisson Ratio;
$define element properties (thickness : 0.25)
PSHELL,10,30,0.25,30 2=density; 3=coefThermExp
35
$the end of input file
ENDDATA
Box 1. Sample Nastran file
We note that the first line of text in the Nastran file is SOL. Box 2 shows some available
commands for different types of analyses.
More information regarding the construct of the Nastran file can be found in the appendix.
36
In this chapter, the conversion of mesh file from .msh to Nastran file is display. Firstly, it will be
helpful to know that the structure of nastran file is simple. The major categories that a Nastran
file consist are the points and the faces connections. The points are in the format of X-, Y-, and
Z- Coordinates. However, there are key words needed to form the face connection in Nastran
file. For instance, if the face category in the .msh file which is usually denoted by “13” has three
(3) points of connection, to convert the face to Nastran format, it will require the keyword
“CTRIA3”. If it is four (4), it will require the keyword “CQUAD4” as explained below. Because
we are aware that there are usually a lot of point and face grids in a mesh file, we have developed
a MATLAB code to ensure that this conversion is done easily. This section showcase the
MATLAB code for the conversion of .msh to Nastran file and its usage.
8.2 MATLAB code for the Conversion of .msh to Nastran File.
8.2.1 Conversion of .msh points to Nastran Points
Consider the points coordinates below, to convert these coordinates to Nastran points
(2 3)
(10 (1 1 9 1 3)(
5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
3.3882497385e-003 -3.2219810665e-006 4.9988601721e-004
))
coordinates, the format is explained in Chapter 8 of this report. This can be achieved by
following the steps below:
Step 1: Open a new notepad++ file and name it Human_Spine_Points (If you are working on a
Human Spine Mesh). Note: Feel free to give the file any name.
Step 2: Open the .msh file to be converted.
Step 3: Extract the points coordinates from the .msh file to be converted as shown
37
Note: You only need to copy the x-,y- and z- coordinates in the .msh file.
Step 4: Paste the copied coordinates to the Human_Spine_Points notepad++ file and save it by
pressing Ctrl + S
Step 5: Open the MATLAB application and paste the code below in the MATLAB Editor.
38
Note: This code is presented at the appendix.
Step 6: Change the file name at line 2 of the code from ‘Human_New_Vol’ to the file name of
the notepad++ (in this case, ‘Human_Spine_Points.txt’)
Step 7: Name the points coordinates of the Nastran file you are about to write at line 7 by
changing the ‘Human_New_Vol_Points.nas’ to say ‘Human_Spine_Points.nas’
Step 8: Click the ‘Run’ button on the MATLAB.
This will write a new Nastran file for the points which will be in form as shown below:
39
40
8.2.2 Conversion of .msh faces coordinates to Nastran faces coordinates.
Before we proceed with the demonstration of the conversion, it must be noted that:
1. The faces coordinates in .msh file are usually written in hexadecimal. There is a
need to convert it to decimal (This is not an issue though as the code can take
care of the conversion)
2. The format for the faces coordinate in ICEM is different from that of GAMBIT.
Before conversion is done, there is a need to know the source of the file to be
converted.
3. The faces are also in groups
Step 1: Search for the number of groups the faces are arranged in the .msh file. This can be done
by pressing Ctrl + F. Then type ‘(13’, then click ‘Find All in Current Document’. This will
display all the group categories in the file as shown below:
Step 2: Count the number of points that make a face. In this case, 3 points make a face
Step 3: Open a new notepad++ and name it ‘Group 7’. Note: You are free to name the group as
desire.
Step 4: Copy all the coordinates under this group and paste it in the new notepad++ file you just
named.
41
Note: Only copy the coordinates as shown above.
Step 5: Open the MATLAB application and paste the code below on the editor
42
Step 6: Change the file name on line 2 to ‘Group 7.txt’. Also change the name of the file to be
written to ‘Group_7.nas’ or as desire.
Step 7: Check the number of columns the file to be converted has. In this case, the file has five
columns. That is why we have matrix a-e in line 9-13. If the number of columns is more than
five, you can uncomment the matrix g and h as required.
Step 8: Check the number of points that make a face. In our case, we have three (3) points that
make a face. That is why we have like 21 of the code active. If we have four (4) points, we
uncomment line 20 and comment out line 21.
Step 9: Change the ‘10’ on line 21 after %d to the group number you are working on. The same
is applicable to line 20 if in use.
Step 10: Change the ‘Start_Connection_Number’ to the first number of the face in each group.
Since we are starting with the first group which is group 7, this variable takes 1. Let’s say the
group 7 stops at the face number 12500, to do for group 8, the variable will take 12501.
Step 11: Click ‘Run’ button on MATLAB to write the .nas file.
43
Step 11: Repeat the steps for other groups on different notepad++
44
Now that we have converted all the points and faces to .nas file, we need to combine the points
together.
Step 1: Open a notepad++ and name it ‘Human_Spine’. (Again, fell free to name it as you desire.
Step 2: On the file, write BEGIN BULK follow by $ Grid data section on the next line.
Step 3: Copy all the converted points coordinates and paste them below the $Grid data line
Step 4: Copy all the converted faces by groups and paste them on the file starting from the line
after the line where the points coordinates end. Add other converted faces in all the groups to the
new file.
Step 5: After all the points and faces has been added to the ‘Human_Spine’ file, type
‘ENDDATA’ at the end of the file.
Step 6: Save the file by pressing Ctrl + S and change the saving format to .nas.
It must be noted that that there are other categories that are present in Nastran file other than
points and faces (As explained in chapter 8), however these categories are not necessarily needed
to read .nas file.
45
CHAPTER 9 – Extraction of JPEG, TIFF and STL Files
The computational grids developed by Gambit mesh generator are read and subsequently
visualized using a code, written in Python, that was developed in our lab. The computational
meshes visualized in Visualization Tool Kit (VTK) are transformed into images (JPEG or TIFF)
and/or STL files by using the vtkWriter class
(http://www.vtk.org/doc/release/4.2/html/classvtkWriter.html). For the extraction of JPEG
images the following class is used: vtk.vtkJPEGWriter(), for TIFF images, the
vtk.vtkTIFFWriter() and for STL files, the vtk.vtkSTLWriter(). The code for the extraction of
STL files is given below:
w2image = vtk.vtkWindowToImageFilter()
writer = vtk.vtkSTLWriter()
w2image.SetInput(renWin)
w2image.Update()
writer.SetInputConnection(w2image.GetOutputPort())
writer.SetFileName("gam_2.stl") # extract stl file
renWin.Render()
writer.Write()
In the above code, the vtk.vtkWindowToImageFilter() class is used to transform the data
structure into image and subsequently the vtk.vtkSTLWriter() class takes as input the
“WindowToImageFilter” to extract (output) the STL file.
An example of this process is given in the Appendix describes the creation of grid with Delaunay
triangulation. The jpeg image extracted is shown in Figure 4.
46
Figure 5. A mesh extracted in VTK by applying the Delaunay Triangulation
10.1 DICOM
File extension: .dcm or none
IMPORTANT: A DICOM stack is not only one file, but a collection of files, one for each
image in the stack.
DICOM files are the most common datatype for image stacks in this lab. They are common
because DICOMs are one of the only data types that allows for tags which contain useful
information about the image stack such as the dimensions of each voxel, the name of the patient,
and the data structure used to house the actual color data. DICOM files can be much smaller than
other imaging file formats because it is possible for DICOMs to hold only 8 or 16 bits of data for
each pixel, compared to 24 or 32 which is typical for BMP or PNG images.
Since DICOM stacks contain multiple files, it is possible that the actual names of the file does
not provide any information on how the stack is supposed to be arranged. Do not assume that just
because “1.dcm” is more “on top” of the list means that it is supposed to be positioned on top of
“2.dcm”. The information on how to arrange the stack is given in a tag in the DICOM tag section
of the file. This section is readable with most DICOM readers. An open-source 2D Dicom
reading software entitled “RadiAnt” can be downloaded and installed on your local desktop to
open a DICOM file if you want to manually inspect the tag section. A few critical tags that must
be set properly in order to read a DICOM dataset in Walk-In Brain are listed below:
47
grayscale or color
(0020,0012) Acquisition Number Gives information about
whether the image is
grayscale or color
(0020,0013) Instance Number Same as above
10.2 JPEG
File extension: .jpg or .jpeg
A JPEG image is a very compressed lossy image. It holds a large amount of graphical data in a
very small amount of disk space using lossy compression algorithms. Lossy means that data is
lost when JPEGs are created.
JPEG images vary greatly in quality. Some JPEGs are very compressed but they are very lossy
(this will cause them to look kind of grainy or blurry if you examine the image carefully). Some
are almost lossless but are nearly as large as PNG images.
Generally, JPEG images are great for viewing purposes, especially on mobile devices or for
storing ultra-large images. However, their lossy nature and the way that they are compressed
suggests that this data format is not optimal for analysis or segmentation since it is difficult to
accurately retrieve the original pixel information.
10.3 TIFF
File extension: .tif or .tiff
A TIFF file is a versatile image file type used by a wide variety of industries. It can carry
compressed or uncompressed image data. An image being compressed means that the fewer
colors/shades the image contains, the smaller the image can be. This is likely a reason it is used
in medical/scientific imaging since many of the images in this industry has only grayscale colors
in few shades (usually 256). TIFF images can be lossy or lossless. TIFF files come in two forms.
The first is a single-frame image. These images can be opened with most Windows image
readers and can be displayed like PNGs, BMPs, or JPEGs.
48
The second is a multi-frame image. Basically, it is a single image file which contains the data for
multiple images. For example, a DICOM image stack could be stored as a multi-frame TIFF
image. A few select image readers can open this, including updated versions of Windows image
gallery.
Multi-frame TIFF files are common in scientific visualization and use in general. Multiple data
sets that have been given to our lab were originally multi-frame TIFFs and a few tools such as
Dr. Kleinfeld’s mouse vasculature vectorization software also use multi-frame TIFFs as the
source data type.
It is important to note that unlike DICOM files, TIFF files do not contain tags that provide
information about the image besides from basic information such as time taken, much like PNGs
and JPEGs. David has written a program that can convert PNG and DICOM images into TIFFs.
49
X direction
Figure 1: The X and Y directions set in the TIFF to DICOM converter as they appear on
the image. The dimensions are irrespective of whether the images are axial, saggital or
coronal, they only apply to the dimensions of the TIFF images themselves.
Once these 4 pieces of information are collected, move the converter script entitled
“TIFF_to_DICOM_converter.m” and “info.m” located in “Z:\20_Software\Data Converters\tiff
to DICOM converter” to the local directory where all of the TIFF images are stored. Then open
MatLab and open the script within the editor. Now the changes need to be made to the
highlighted region in Box 10.1.
Box 10.1
50
10.4 PNG
File extension: .png
A PNG image is one of the basic compressed image types. This means that the fewer
colors/shades the image contains, the smaller the image can be. PNGs, like TIFF images, only
contain pixel information and do not store information about the scanner or the size of the
voxels.
PNG images is the preferred data type for image data since it is highly compressed, modern, and
supports 32-bit data storage per pixel.
PNGs are lossless, meaning that they do not lose any of the original data, unlike JPEGs. This
does not mean that it is not compressed however. They are compressed, just in an efficient way
that does not cause loss of data.
10.5 BMP
File extension: .bmp
A BMP image is the most basic image type. It is basic since it is uncompressed, has very little
metadata attached to it. Basically, it is just bits of color data next to each other forming an image.
51
Since it is uncompressed, it is lossless. However, in the modern day, there are few reasons to use
BMP files. PNGs are capable of doing the same thing, except the image can be much smaller due
to compression. Compressed PNGs can be lossless, so they are better than BMPs in almost every
way.
We currently possess 2 tools to accomplish this goal; the “ooMeshEditor” tool has a capability of
converting this file or the “MeshConverter.exe” tool located in S:\20_Software\Data Converters.
11.1.1.1 Step 1: Modify the Header
The header of the FLUENT mesh can be seen in Box 11.1. In order to read this file into the
converters, the FLUENT version must be altered to “v14.0.3” as seen in Box 11.2.
Box 11.1
52
Box 11.2
(0 " Created by : Fluent_V6 Interface Vers. 14.0.3")
11.1.1.2 Step 2: Reading the point coordinate matrix
The point coordinate matrix from the FLUENT version and the GAMBIT version of the mesh
file both have 3 columns, corresponding to the x, y and z coordinate of each point. Each row of
the point coordinate matrix corresponds to the point number (used in the face matrix).
11.1.1.3 Step 3: Reorder the face matrix
In the FLUENT and the GAMBIT mesh files, the face matrix is broken into multiple groups,
each with its own header. In the FLUENT file format, however, the exterior faces are put at the
end of the face matrix groups. The GAMBIT converter reads in all the faces in the face matrix
and then reorders the groups such that the exterior faces come first in the face matrix.
11.1.1.4 Step 4: Minimize the Zone Section
In the FLUENT format, the cells do not have their own header and the zones correspond to
different materials. Whereas this is useful for the FLUENT simulation engine, for our
visualization purpose, we can simplify all zones to being fluid zones. In this way, the zone
section seen in Box 11.3 is converted to the cells section and zone section in Box 11.4.
Box 11.3
(0 "Zone Sections")
(39 (6 fluid BRAIN_TISSUE)())
(39 (7 fluid TUMOR_MASS)())
(39 (8 interior int_BRAIN_TISSUE)())
(39 (9 interior int_TUMOR_MASS)())
(39 (10 wall TUMOR)())
(39 (11 wall BRAIN)())
Box 11.4
(0 "Cells:")
(12 (0 1 49722 1 2))
(12 (4 1 49722 1 2))
(0 "Zones:")
(45 (2 fluid fluid) ())
53
11.2 Data File Format
FLUENT naturally uses a .cas file that is written in a proprietary binary format and allows
FLUENT to read the data from file very efficiently. In order to visualize this data, we will need
to convert it to our GAMBIT format and write it into a “.mm” file.
Step 1:
Set up simulation by loading mesh file and defining solution parameters or by loading existing
case file using the command found in: File Read Case.
Step 2:
Create .mm file with header and save in local file where FLUENT simulation is located. This file
should follow the format in Box 11.5 where the bolded items should be replaced with your
personalized data.
Box 11.5
<<model header>
//comments author=Your Name date=>
problemtype = ANSYS CFD Data
<meshfile>
meshfile=Mesh.GAMBIT.msh
Step 3:
Create a list of information to be inserted into the new “mm” file following the template in Table
11.1.
Table 11.1
Information Description Example
Number of cell zones # of cell zone groups in the mesh {1,2,…,n}
ID number of cell zone Fluent specific ID# of each zone {1=7,2=8,…,n=12}
Number of mesh cells # of total cells in mesh; all zones (dec//hex) 7363422 // 705B5E
*
Variable of interest Parameter to export for each cell pressure, species, etc.
.mm file name Name of file (Step 3) to write data vector to “WriteVectorFile.mm”
*List of UDF specific variable syntax is in Appendix A.1
Step 4:
Now we must set up a user defined function (UDF) in FLUENT format to be ready by FLUENT
during the simulation and that will write our “.mm” file. To configure the UDF file, open
“WriteVectorTemplate.c” and modify it as need be for your simulation. The details of what need
to be modified are as follows:
The process for user input of information to the UDF file is demonstrated in Box 11.6. These
sections are necessary to properly configure the UDF code to write data specific to each scenario
and write a unique .mm file.
Box 11.6: Template UDF file for writing a data vector for cell centers from an ANSYS Fluent
simulation. Locations (i) – (viii) are necessary to update for each simulation to ensure the
variable data written directly to .mm file is unique and properly configured.
55
Step 5:
Compile UDF into Fluent as shown in Figure 2:
Define User-defined Functions Compile
In the pop up window “Compiled UDFs” click ‘Add’… and navigate to the folder
location where the modified UDF from Step 5 is located.
Change the Library Name to a unique name and click ‘Build ‘.
After successful build, the following text (or similar will appear in the text interface)
Copied K:\03_Papers\2016\NW_BrainTumor\KT work\Real Head/K:\03_Papers\2016\NW_BrainTumor\KT work\Real
Head\WriteVectorBrain.c to libudfwritevector2\src
Creating user_nt.udf file for 3ddp ...
(…multiple lines of udf specific text will be written…)
Creating library libudf.lib and object libudf.exp
Done.
Click ‘Load’ to load the UDF into Fluent; following text will appear if successful:
Opening library "K:\03_Papers\2016\NW_BrainTumor\KT work\Real Head\libudfwritevector2"...
Library "K:\03_Papers\2016\NW_BrainTumor\KT work\Real Head\libudfwritevector2\win64\3ddp\libudf.dll" opened
write_vector
Done.
Once UDF if loaded into Fluent it must be activated as a ‘function hook’
Define User-defined Function Hooks
56
Click the ‘Edit’ available for ‘Execute at End’
Select your UDF that was loaded and click ‘Add’, then Ok
Figure 2: The steps necessary to compile and activate the UDF to write data to an .mm file at
the end of every time step. (Left) Define and compile the UDF which loads the code into
ANSYS Fluent. (Right) Links the UDF to the workflow so the code is executed each time step
to write data to file.
The UDF is now loaded and active in the Fluent module and will be execute at the end of every
time step to write vector(s) of data to the specified .mm file.
12 References
1. http://www.adina.com
2. http://www.fluent.com/
3. http://www.fluent.com/software/gambit/
4. http://www.mscsoftware.com/support/online_ex/Scenario/Manual/man2.pdf
5. Bathe, K.: Finite Element Procedures. New Jersey, Prentice-Hall, Inc., 199
13 Appendix
57
(0 "GAMBIT to Fluent File")
(0 "Dimension:")
(2 2)
(10 (0 1 D 1 2))
(10 (1 1 D 1 2)(
2.0000000000e+000 0.0000000000e+000
2.0000000000e+000 1.0000000000e+000
2.0000000000e+000 5.0000000000e-001
0.0000000000e+000 0.0000000000e+000
6.6666666667e-001 0.0000000000e+000
1.3333333333e+000 0.0000000000e+000
0.0000000000e+000 1.0000000000e+000
1.3333333333e+000 1.0000000000e+000
6.6666666667e-001 1.0000000000e+000
0.0000000000e+000 5.0000000000e-001
3.9306883226e-001 5.0000000272e-001
1.0000001220e+000 5.0000000017e-001
1.6069312862e+000 5.0000000119e-001
))
(0 "Faces:")
(13 (0 1 1a 0))
(13 (3 1 a 3 0)(
2 4 5 2 0
2 5 6 d 0
2 6 1 8 0
2 1 3 7 0
2 3 2 6 0
2 2 8 5 0
2 8 9 a 0
2 9 7 3 0
2 7 a 4 0
2 a 4 1 0
))
(13 (5 b 1a 2 0)(
2 4 b 1 2
2 b a 1 4
2 5 b 2 e
2 7 b 3 4
2 b 9 3 c
2 8 d 5 9
2 d 2 5 6
2 d 3 6 7
2 d 1 7 8
2 d 6 8 b
2 8 c 9 a
2 c d 9 b
2 9 c a c
2 c 6 b d
2 b c c e
2 c 5 d e
))
(0 "Cells:")
(12 (0 1 e 0))
(12 (2 1 e 1 1))
(0 "Zones:")
58
I.2 : Three-dimensional *.msh File consisted of tetrahedral cells
(0 "GAMBIT to Fluent File")
(0 "Dimension:")
(2 3)
(10 (0 1 9 1 3))
(10 (1 1 9 1 3)(
5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 5.0000000000e-001 5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 -5.0000000000e-001
-5.0000000000e-001 -5.0000000000e-001 5.0000000000e-001
3.3882497385e-003 -3.2219810665e-006 4.9988601721e-004
))
(0 "Faces:")
(13 (0 1 1e 0))
(13 (3 1 2 3 0)(
3 6 1 8 3 0
3 4 1 6 4 0
))
(13 (4 3 4 3 0)(
3 3 1 4 a 0
3 2 1 3 b 0
))
(13 (5 5 6 3 0)(
3 5 4 6 6 0
3 3 4 5 8 0
))
(13 (6 7 8 3 0)(
3 7 6 8 2 0
3 5 6 7 5 0
))
(13 (7 9 a 3 0)(
3 7 3 5 7 0
3 2 3 7 c 0
))
(13 (8 b c 3 0)(
3 2 8 1 9 0
3 7 8 2 1 0
))
(13 (a d 1e 2 0)(
59
3 8 9 7 2 1
3 9 8 2 9 1
3 7 9 2 c 1
3 6 9 7 5 2
3 9 6 8 3 2
3 1 9 6 4 3
3 9 1 8 9 3
3 1 9 4 a 4
3 4 9 6 6 4
3 6 9 5 6 5
3 5 9 7 7 5
3 4 9 5 8 6
3 3 9 7 c 7
3 9 3 5 8 7
3 4 9 3 a 8
3 2 9 1 b 9
3 1 9 3 b a
3 2 9 3 c b
))
(0 "Cells:")
(12 (0 1 c 0))
(12 (2 1 c 1 2))
(0 "Zones:")
(45 (2 fluid fluid)())
(45 (3 wall w6)())
(45 (4 wall w5)())
(45 (5 wall w4)())
(45 (6 wall w3)())
(45 (7 wall w2)())
(45 (8 wall wall1)())
(45 (10 interior default-interior)())
60
2 0.00000000000e+000 0.00000000000e+000
3 0.00000000000e+000 2.66666666667e+000
4 0.00000000000e+000 1.33333333333e+000
5 3.00000000000e+000 0.00000000000e+000
6 1.00000000000e+000 0.00000000000e+000
7 2.00000000000e+000 0.00000000000e+000
8 3.00000000000e+000 4.00000000000e+000
9 3.00000000000e+000 1.33333333333e+000
10 3.00000000000e+000 2.66666666667e+000
11 2.00000000000e+000 4.00000000000e+000
12 1.00000000000e+000 4.00000000000e+000
13 7.66518491352e-001 3.19604214921e+000
14 1.96341923329e+000 1.85175317966e+000
15 1.84167491184e+000 3.11659564726e+000
16 9.76065872390e-001 1.00453448902e+000
17 1.99571175745e+000 7.10540275021e-001
18 9.40906865090e-001 2.17994810933e+000
ENDOFSECTION
ELEMENTS/CELLS 2.2.30
1 3 3 12 1 13
2 3 3 13 1 3
3 3 3 8 11 15
4 3 3 8 15 10
5 3 3 4 2 16
6 3 3 16 2 6
7 3 3 16 6 17
8 3 3 17 6 7
9 3 3 5 9 17
10 3 3 5 17 7
11 3 3 15 11 12
12 3 3 4 16 18
13 3 3 4 18 3
14 3 3 17 9 14
15 3 3 14 9 10
16 3 3 3 18 13
17 3 3 12 13 15
18 3 3 10 15 14
19 3 3 16 17 14
20 3 3 16 14 18
21 3 3 18 14 15
22 3 3 15 13 18
ENDOFSECTION
ELEMENT GROUP 2.2.30
GROUP: 1 ELEMENTS: 22 MATERIAL: 2 NFLAGS:
1
fluid
61
0
1 2 3 4 5 6 7 8 9
10
11 12 13 14 15 16 17 18 19
20
21 22
ENDOFSECTION
I.4: A closer look at the different types of element formats: CTRIA3, CQUAD4
1 2 3 4 5 6 7 8 9 10
THETA
CTRIA3 EID PID G1 G2 G3 ZOFFS
or MCID
T1 T2 T3
Field Contents
If you don’t supply values for Ti, then the software sets the element’s corner thicknesses T1
through T3 equal to the value of T on the PSHELL entry.
62
THETA
CQUAD4 EID PID G1 G2 G3 G4 ZOFFS
or MCID
T1 T2 T3 T4
Field Contents
EID Element identification number.
PID Property identification number of a PSHELL or PCOMP entry.
Gi Grid point identification numbers of connection points.
THETA Material property orientation angle in degrees.
MCID Material coordinate system identification number.
ZOFFS Offset from the surface of grid points to the element reference plane.
Ti Membrane thickness of element at grid points G1 through G4.
Grid points G1 through G4 must be ordered consecutively around the perimeter of the element.
THETA and MCID are not required for homogenous, isotropic materials. ZOFFS is used when
offsetting the element from its connection point. The continuation entry is optional. If you don’t
supply values for T1 to T4, the software sets them equal to the value of T (plate thickness) you
define on the PSHELL entry. Finally, all interior angles of the CQUAD4 element must be less
than 180°.
In general, there are four sections in the Nastran file:
63
SPC = 10 <-----define the constraint identified as 10 in BDS
LOAD = 10 <-----define the load identified as 10 in BDS
DISP= ALL <-----print the displacements of all nodes
STRESS = ALL <-----print stresses of all elements
SUBCASE 2 <===the second analysis condition
SPC = 10 <-----define the constraint identified as 10 in BDS
LOAD= 20 <-----define the load identified as 20 in BDS
DISP= ALL <-----print the displacements of all nodes
STRESS = ALL <-----print stresses of all elements
64
MAT2 : Anisotropic material for two-dimensional elements, plates or shells. In-plane, transverse
shear material
65
deci = vtk.vtkDecimatePro()
deci.SetInput(delny.GetOutput())
deci.SetTargetReduction(0.0)
deci.PreserveTopologyOn
smoother = vtk.vtkSmoothPolyDataFilter()
smoother.SetInput(deci.GetOutput())
smoother.SetNumberOfIterations(50)
normals = vtk.vtkPolyDataNormals()
normals.SetInput(smoother.GetOutput())
normals.FlipNormalsOn
mapmesh=vtk.vtkPolyDataMapper()
mapmesh.SetInput(normals.GetOutput())
meshActor = vtk.vtkActor()
meshActor.SetMapper(mapmesh)
meshActor.GetProperty() .SetColor(0.38, 0.7, 0.16)
meshActor.GetProperty().SetRepresentationToWireframe()
; # the exported image is set to wireframe
writer = vtk.vtkSTLWriter()
writer.SetInput(normals.GetOutput())
writer.SetFileName('delny_smooth.ascii.stl')
#writer.SetFileTypeToBinary()
writer.Write()
ren = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
renWin.SetSize(800, 450)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
ren.SetBackground(1., 1., 1.)
ren.AddActor(meshActor)
ren.ResetCamera()
ren.GetActiveCamera().Azimuth(10)
ren.GetActiveCamera().Elevation(20)
ren.GetActiveCamera().Dolly(1.5)
ren.ResetCameraClippingRange()
w2image = vtk.vtkWindowToImageFilter()
#writer = vtk.vtkSTLWriter()
#writer = vtk.vtkTIFFWriter()
writer = vtk.vtkJPEGWriter()
w2image.SetInput(renWin)
w2image.Update()
writer.SetInputConnection(w2image.GetOutputPort())
#writer.SetFileName("image1.tif")
#writer.SetFileName("image4.stl")
writer.SetFileName("Delaunay_pic.jpg")
66
renWin.Render()
writer.Write()
# Render the scene and start interaction.
iren.Initialize()
renWin.Render()
iren.Start()
14.1 Summary
The converter application (Figure 6) converts from 2-point networks to spline networks and vice
versa.
The software can be accessed either from the converter application or from the Viewer
application (Figure 7).
67
Figure 7. Accessing converter from the Viewer application.
Three additional function tabs can be found below the main tabs that display the networks loaded
and the statistics of the spline and 2-point networks:
1. DisplayNWK.
2. SplineNWKStatistics.
3. NWKStatistics.
The test case file considered in this section can be found in:
Share\19_ImageInventory\Converter\TestFiles\testCoW.cs31
Share\19_ImageInventory\Converter\TestFiles\testCoW.nwk
68
2. Convert to spline network (*.snwk) using “convertButton”.
3. Save the spline network using “saveButton”. Note that the extension needs to be added to
the file name when saving the newly created spline network.
The reset button, “reset”, will clear the display and the loaded network.
Only lines are shown in the display as there is no diameter information. Thus, the
ToggleCylinderView in the DisplayNWK tab will not perform anything.
69
14.2.2 Convert CaseFiles To Splines
This function converts case files (*.cs31) linked to 2-point network files (*.nwk) to spline case
(*.cs4) and network files (*.snwk). The case file contains the information of the diameter of the
network. The conversion procedure is:
1. Load case file (*.cs31) using “loadCSButton”. The corresponding network file (*.nwk)
will be loaded automatically, with the information being stored in the case file.
2. Convert to spline case (*.cs4) and network (*.snwk) using “ConvertCase”.
3. Save the spline case (*.cs4) and network files (*.snwk) using “saveCase”. The extensions
are automatically added during the saving procedure.
The reset button, “reset2” will clear the display and the loaded case and network.
During the conversion, the diameter information is also converted and is followed by a linear
fitting using a least-square deviation approach (Figure 12).
70
Figure 12. Two sample results of the linear fitting of diameter in each spline. The red plot is the original spline
network diameter and the green plot is the linear fit.
Figure 13. Conversion of 2-point case and network to spline case and network. The original 2-point network is on
the left and the spline network on the right.
71
14.2.3 Convert Splined to Even2ptmesh
This function converts spline case (*.cs4) and network files (*.snwk) to 2-point case (*.cs31) and
network files (*.nwk). The case file contains the information of the properties that are being
converted. For example, it contains inlet diameter and its slope along each spline in the network.
The procedure to convert the splined network diameters to a 2-point format is:
1. Determine the number of subdivisions along each spline in the box labelled “Number of
Subdivisions”. The base value is currently set at 10. The used can change this number.
2. Load and convert case file (*.cs4) using “loadSplinedNW_Convert”. The corresponding
spline network file (*.snwk) will be loaded automatically and converted.
3. Save the 2-point case (*.cs31) and network (*.nwk) files using “save2DNWK”. The
extensions are automatically added during the saving procedure.
Although there is no reset button in this tab, it is possible to clear the display and the loaded case
and network using any of the reset buttons in the other tabs.
72
Figure 15. Conversion of spline case and network to 2-point case and network. The original spline network is on
the left and the 2-point network is on the right. The face (edge) indices are also represented in both networks.
It is also possible to convert point properties in the splined network to 2-point format by linear
interpolation. This is achieved by:
1. Determine the number of subdivisions along each spline in the box labelled “Number of
Subdivisions”. The base value is currently set at 10. The used can change this number.
2. Load and convert case file (*.cs4) using “convertAndReadProperty”. The corresponding
spline network file (*.snwk) will be loaded automatically and converted.
3. Save the 2-point case (*.cs31) and network (*.nwk) files using “save2DNWK”. The
extensions are automatically added during the saving procedure.
Figure 16. Procedure to convert spline network point properties to 2-point format.
73
Figure 17. Conversion of spline network point property (pressure in this case) to 2-point format.
The offset is performed on the original image and moves either left (negative offset) or right
(positive offset). Figure 18 shows the original image and Figure 19 shows the offset with an
offset index of 0.5. The original image has moved towards the right.
74
Figure 19. Conversion of spline case and network to 2-point case and network. The original spline network is on
the left and the 2-point network is on the right. The face (edge) indices are also represented in both networks.
14.2.5 CleanSplinedNW
This function finds and removes dangling splines in spline case and network (*.snwk) files. The
finding and removing procedure is as follows:
1. Load the case file (*.cs4) using “loadSplinedNW”. The corresponding spline network file
(*.snwk) will be loaded automatically.
2. Determine the dangling splines using “showAllDanglingSplines”. This will show a list of
splines that are dangling on the “RemoveSplines” box.
3. Remove the dangling splines by clicking the “DoIt” button next to the “RemoveSplines”
box.
4. Save the cleaned spline case (*.cs4) and network (*.snwk) files using “saveSplinedNW”.
The extensions are automatically added during the saving procedure.
75
Figure 20. Procedure to clean spline networks with dangling vessels
The reset button, “reset” in this tab, will clear the display and the loaded case and network. The
user can remove any spline manually by adding the spline numbers that one wants to remove in
the “RemoveSplines” box and then click the “DoIt” button. Note that multiple splines can be
removed at once by inserting a list of splines to be removed in ascending order.
Figure 21. Removal of dangling splines. The original spline network is on the left and the 2-point network is on
the right. The face (edge) indices are also represented in both networks.
14.3.1 DisplayNWK
This function changes the visualization of the network display. There are five options:
76
1. ToggleCylinderView – it changes visualisation from line to cylindrical view of the
diameter, when the information is available.
2. ToggleGroupview – shows the different groups.
3. PointLabels – shows the node (vertex) indices.
4. FaceLabels – shows the face (edge) indices.
5. Direction – shows the direction in which the face was labelled.
14.3.2 SplineNWKStatistics
This function provides statistical information of the spline networks. There are four options:
1. reportSNWKBtn – it provides information of the network.
2. meshFileBtn – [Currently does nothing].
3. PointMx – shows the connection between the node (vertex) indices.
4. ptCoordMx – shows the co-ordinates of the nodes (vertices).
14.3.3 NWKStatistics
This function provides statistical information of the 2-point networks. There are four options:
1. nwkLength – [Currently does nothing].
2. BitBtn2 – [Currently does nothing].
3. BitBtn3 – [Currently does nothing].
4. BitBtn4 – [Currently does nothing].
77
C
E F
Figure 22. Generating a simple mesh in ICEM. Make surface for generating mesh. (d). Save it
as ANSYS Fluent mesh or STL. (E). Simple mesh. (F). Coordinates shown on the mesh. (G).
STL format of same geometry. (H). Gambit format of same geometry.
An STL file shows a normal and three point coordinates for each triangle in the mesh as seen
below:
78
Figure 23. STL and mesh files comparison. (A). STL file of format for the shown geometry in
Figure 24. (B) Gambit file of same geometry.
Note: The resulting STL file does not currently maintain any face grouping. This can be
implemented but is currently not implemented. For more information see Grant Hartung.
Figure 25. Visualization of converted stl to mesh and original mesh in ViewerApplication. (A).
original sled mouse msh file. (B). Converted to STL and back to msh. Note that the anatomical
grouping is lost during the conversion process.
79
15.2 Converter from mesh to stl
The STL format is useful for passing data between softwares, yet it is not used in the model
generation libraries used by the LPPD. As such, the STL converter must only write an STL file,
not make an STL object. Figure 23B displays point coordinate matrix and face matrix
information in addition to headers and number of points, faces, volume and dimensions in the
mesh file. However, the STL file stores each triangle as three vertices and a face normal for each
triangle in the mesh. Thus, the program iterates over each row of the face matrix to retrieve the
indices of connected points on each triangle. This data is formatted in the STL format (Figure
23A) and written to file. The obtained file is called an STL file.
In order to compare the converters, it is important to use one case study among all mesh
converters. To do this, a tetrahedral mesh of a simple tube was created in ICEM by Homai
Rashidisabet. This tube was cut to a very small length in order to expose jagged edges for easy
comparison of point coordinate accuracy and to identify missing mesh elements. The original file
is converted to GAMBIT format using the tool delineated in Section 18.1. The source file to
begin this demonstration is CutCylindetWithVolume.msh located in Z:\__temp\Converter\.
The steps for converting between GAMBIT mesh format and STL are explained below. The
application for the conversion is ViewerApplication_updatedConverter.exe located in
Z:\__temp\Converter\ or is available by Grant. The source codes for the converters are given in
Z:\__temp\Converter\sourceCodes\ or are available via Grant. The source code for building and
compiling the converter are on Grant’s computer. For reference, the original mesh file (in
GAMBIT format) is viewed in Viewer Application below:
Figure 26. Visualization of original GAMBIT mesh file of the cut tube used in this case study.
The coloration is for anatomical grouping, with red being Group Exterior and blue being
Group Interior.
Step 1: Launch the Viewer Application and select the “Converter” button
80
Step 2: select the “mesh/STL converter” tab on the far right
81
Step 3: Load a triangulated (triangulated surface mesh or tetrahedral volumetric mesh) mesh
file by selecting the “Load Triangulated Mesh” button
Step 4: Load your mesh and observe that the display shows the mesh you expected to see:
82
Step 5: Save the file as an STL file by selecting “Save as STL” and choose a new file name:
Verify that the new STL file works by opening it in Windows 10 STL viewer tool:
To exemplify this conveter on a larger scale, the conversion from GAMBIT mesh to STL for
a mouse brain file was performed. The results are offered in Cerebroview in Figure 27. The
visualization of both files are exactly the same.
Figure 27. Visualization of converted mesh to stl and original stl in Cerebroview. (B)
Converted Mesh to stl. (C) original stl.
83
15.3 Converter from stl to msh
In order to convert the stl to mesh, we need to extract point coordinate matrix and face matrix
information to write in the msh file. As it is shown in Figure 23A, an STL file groups every three
vertices together to represent one triangle. This can be extracted while looping across all
traingles in the mesh. In order to avoid repeating points, which does occur in STL format,
duplicate points are identified during the reading process and replaced with the index of the
currently existing point in the ptCoordMx. A walkthrough is offered for converting the tube
mesh from STL format back to GAMBIT mesh format using the
ViewerApplication_updatedConverter.exe located in Z:\__temp\Converter\ or is available by
Grant.
Note: The STL to GAMBIT converter assumes all faces in the STL file are boundary faces.
There is currently no method for extracting interior mesh volumes from an STL file. For more
information, see Grant.
Step 1: Launch the Viewer Application and select the “Converter” button
84
Step 3: Load an STL mesh by selecting the “Load STL” button
Step 4: Select STL file for converting and ensure the visualization is acceptable:
Step 5: Save as GAMBIT file by selecting “Save as GAMBIT Mesh” button and choosing a
suitable file name:
85
16 Walk through of viewer application for visualizing mesh files
We can visualize msh files in the viewer application by just loading them. In Figure 20, we show
step by step guidance for how and where we can visualize the msh files.
86
Figure 28. Viewer application form used for visualizing mesh file. (A). Red box shows the
bottom for loading msh file. (B). Visualizng the mesh in viewer application.
87
cubes. Thus, we manually choose four points with indices of {1,4,8,2} from one cube and find
their correspondence points in another cube which in this identical case is again point indices of
{1,4,8,2}. The coordinate of four points that we have used for first and second cubes are given in
Error: Reference source not found
Table 1. Coordinates of points on both cubes used for alignment.
COW 1 COW 2
X Y Z X Y Z
1.8900 0.1080 -0.0117 -0.0540 -0.0039 -0.0985
1.8500 -0.0758 -0.0188 0.0379 -0.0063 -0.0879
1.8900 0.0094 -0.0018 -0.0047 -0.0006 -0.0974
1.4000 0.0005 -0.2640 -0.0002 -0.0881 0.0254
(2)
88
89
Figure 29. Registration form. (A). the general view of the registration form. (B). Red box shows
where user needs to insert four points of object one and two, and the bottom for computing the
transformation information. (C). Red boxes show the transformation matrix, offset vector and
eligned second object on object one. (D). visualization of the eligned points.
After getting the transformation matrix and offset vector, we can insert this information in the
viewer application and apply it on the object 2 to align it by object 1.
90
Figure 30. Applying transformation matrix on the network in viewer application. Two misaligned
objects, Object 2. The last picture is object two that is aligned with object1.
Sometimes it is convenient to produce a mesh in one tool (Delphi in some cases, ICEM in
others) and want to operate on the mesh in another tool. This could be the case when volumizing
a surface STL mesh, which can only be performed in ICEM (code not written in Delphi for this),
yet the volumetric mesh is simulatable in Delphi where much more control over the
mathematical model generation can occur. The same is true when a parametric mesh is generated
in the Delphi language and is to be simulated in FLUENT for any reason. These two
computational domains use differently organized files and look for different tags, so a converter
is necessary to transpose the information between these two media. Such a tool has been built by
GH in Delphi and is described below using the MeshConverter project in the grantTests folder
(when compiled, this is known as MeshConverter.exe):
91
as in Figure 31 and converted using the converter in the
ViewerApplication_updatedConverter.exe located in Z:\__temp\Converter\ or is available by
Grant.
Figure 31. Original ICEM mesh file visualized in ICEM. This is a monkey spine. This mesh
was found amongst the data received from a collaborator. At the time, it was not able to be
loaded by any visualization tools or Delphi programs for processing, a perfect case to be used
within the confines of our converter.
Step 1: Launch the Viewer Application and select the “Converter” button
92
Step 3: Open an icem-compatible mesh file using the “Load ICEM Mesh” button and validate
that the visualization matches your mesh:
This will create a ooANSYSReader object that has a mesh property that houses the ICEM mesh in memory.
Step 4: Save the mesh in GAMBIT format using the “Save as GAMBIT Mesh” button and
select a suitable mesh file name:
93
Step 5: Validate that the new mesh file is the same as the original mesh file by loading it in
ViewerApplication.exe:
94
Figure 32. Visualization of the GAMBIT file generated using the converter in Section 18.1.
This file is named M1V3.convertedFromIcem.msh and is located in S:\__temp\Converter\.
Step 1: Launch the Viewer Application and select the “Converter” button
95
Step 3: Open a GAMBIT mesh file by selecting the “Load GAMBIT Mesh” button:
Step 4: Identify the GAMBIT mesh file to choose and Verify that the mesh file visualization
matches the expected mesh file:
96
Step 5: Save the mesh in ICEM format by selecting “Save as ICEM mesh” button
Step 6: Validate that the ICEM mesh loads and looks correct in the ICEM program:
Figure 33. Visualization of the ICEM file generated from the coversion process. This file is
named M1V3.convertedFromIcem.icem.msh and is located in S:\__temp\Converter. Loaded
into ICEM using ImportMeshFromFluent. If nothing appears on the screen, deselect and
select (uncheck and check the checkboxes) for the parts on the left side of the screen to reveal
the loaded mesh.
All conversions between a cs31 file (case file), with corresponding .nwk file (network file),
and .casx file format can be accomplished with the converter in the
97
ViewerApplication_updatedConverter.exe located in Z:\__temp\Converter\ also available by
request from Grant. This tool allows the user to select a case file, which instantiates a mesh
object from that case file, and save as a .casx file. Also included is an option to read a .casx (case
X file), which also instantiates a tubeMesh object, which can be saved in .cs31/.nwk format.
The option to write a casx file from the mesh is available with a button. This button first
instantiates a ghCaseXFileWriter object and passes the mesh and the file name in. The
ghCaseXFileWriter object located in ghCaseXFileSource.pas writes the header, the point
section, the face section, and the diameter vector section. This button then goes back to the case
(.cs31) file and finds any data that may be contained within it. The button then passes the data it
found previously from the file into the ghCaseXFileWriter. The button then instructs the writer
to save the file. Note, the casx file does not preserve group indexing.
The option to save the mesh as a .cs31 file is available by a single button. This button
instantiates a ooCaseFileWriter object and passes the mesh and the case file name into it. Source
code is available at Z:\__temp\Converter\sourceCodes\ ghCaseXFileSource.pas.
Figure 34. Visualization of the original cs31 and nwk file created from grant’s artificial
network generation code (version 1), Project_KFGenAndSolvingApp.exe.
Step 1: Launch the Viewer Application and select the “Converter” button
98
Step 2: select the “ICEM GAMBIT Mesh Converter” tab
Step 4: Select an appropriate case file and verify the visualization matches the expectated
network:
99
Step 5: Save the network in the .casx file format by selecting “Convert and Save As .casx”
button. NOTE: If you wish the casx file to include any data vectors from the cs31 file (aside
from diameter, which is automatically included), the option of “Load data from .cs31 file” must
be selected inside the “Save with data vectors” radiobox (automatically selected). If you do not
wish to save the network with any data aside from a diameter vector, change the selection to
“do not load data”:
Step 7: Open the new casX file to validate that the file has the correct date:
100
Note, there are currently no visualization tools for validating the .casx file except for the option
in the converter to load a .casx file. It is recommended to validate using this button as follows:
101
Step 8: Validate the visualization of the .casx network by clearing the form:
And opening the casx file by selecting “Choose .casx file” button”
102
19.2 Instructions for converting from .casx to .cs31:
Step 1: Launch the Viewer Application and select the “Converter” button
Step 3: Open a case file (.cs31) using the “Choose .casx file” button:
Step 4: Select an appropriate case file and verify the visualization matches the expectated
network:
Step 5: Save the network in the .cs31/.nwk format by selecting “save as .cs31 file” button:
103
Step 6: Choose a suitable file name to save the file as:
Step 7: Open the new .cs31/.nwk file in viewerApplication.exe to verify it converted properly:
104
20 Reading and Visualizing casx files in Matlab
The general logic of the code is given in Figure xx where the only user input is a 1 or 0 to
indicate the presence of labels.
The code was used for .casx and .cas files of two simple bifurcations and a simplified structure
of the arteries and veins fused.
A
B
P1
P2
P3
P6
P4 P5
Figure 36: (A) Arteries and vein fused structure (B) Simple bifurcation
105
The code was converted into a stand-alone executable called casxReadVisualize_labels that can
be ran without Matlab using the Matlab Compiler application (Figure xx).
Figure 37: Matlab compiler used to convert an .m file into a stand-alone executable
By installing the application using the default settings, the application will be installed in the
following path: C:\Program Files\casxReadVisualize_labels\application. Using the command
line, the directory should be reached using the cd and cd .. commands and then the application
should be ran using 1 or 0 as an input.
Figure 38: Running the stand-alone executable from the command prompt
Appendix A:
Points_Converter: (Conversion of .Msh Fie to Nastran File.)
106
clear all; close all; clc;
fileID =fopen('Sample.txt','r'); j = 1;
while ~feof(fileID)
line = fgetl(fileID);
PointsMx(j,:) = sscanf(line, '%f %f %f')';
j = j+1;
end
fclose(fileID);
x = PointsMx(:,1);
y = PointsMx(:,2);
z = PointsMx(:,3);
f = fopen('Sample.nas','w+');
for i = 1:length(x)
point=sprintf('GRID,%d,,%d,%d,%d\n',i,x(i),y(i),z(i));
fwrite(f,point);
end
fclose(f);
Face_Converter:
f = fopen('Sample 7.nas','w+');
Start_Connection_Number = 1;
for j = 1:length(a)
% point=sprintf('CQUAD4,%d,10,%d,%d,%d\n',j+(Start_Connection_Number-
1),a(j),b(j),c(j));
107
point=sprintf('CTRIA3,%d,7,%d,%d,%d\n',j+(Start_Connection_Number-
1),a(j),b(j),c(j));
fwrite(f,point);
end
fclose(f);
function casxReadVisualize_labels(labelChoice)
% casxReader and visualizer -- Case file must be chosen by the user
% Author: Claudia Vesel, CSP
%% Select file
[filename,pathname] = uigetfile('*.casx');
%% Plot Network
casxVisualizer(nwk.ptCoord,nwk.faceMx,nwk.Dia,labelChoice)
end
function nwk = casxRead(filename)
fid = fopen(filename);
state = none;
while ~feof(fid)
line = fgetl(fid);
if strncmpi(line,'//diameter',9) == 1
state = dia;
line = fgetl(fid);
i = 0;
elseif strncmpi(line,'//point',7) == 1
state = pointMx;
fgetl(fid);
line = fgetl(fid);
i = 0;
elseif strncmpi(line,'//connectivity',14) == 1
state = faceMx;
fgetl(fid);
line = fgetl(fid);
i = 0;
elseif strncmpi(line,'//flow',6) == 1
state = flow;
line = fgetl(fid);
i = 0;
elseif strncmp(line,'//end',5) == 1
state = none;
end
switch state
108
case dia
i = i + 1;
myDiameter(i,1) = str2double(line); %#ok<AGROW>
case flow
i = i + 1;
myFlow(i,1) = str2double(line); %#ok<AGROW>
case pointMx
i = i + 1;
myPtCoord(i,1:3) = sscanf(line,'%f %f %f'); %#ok<AGROW>
case faceMx
i = i + 1;
% myFaceMx(i,1:2) = sscanf(line,'%i %i'); %#ok<AGROW>
myFaceMx(i,1:2) = (sscanf(line,'%x %x')); %#ok<AGROW>
otherwise
end
end
try
nwk.Dia = myDiameter; nwk.ptCoord=myPtCoord; nwk.faceMx=myFaceMx; nwk.flowVec=myFlow;
catch
end
fclose(fid);
end
function casxVisualizer(ptCoordMx,faceMx,diaVec,labelChoice)
figure; %Plot points,faces scaled by dia
sz=20;
scatter3(ptCoordMx(:,1),ptCoordMx(:,2),ptCoordMx(:,3),sz,...
'MarkerEdgeColor',[0 0 0],'MarkerFaceColor',[0.5 0.5 0.5]);hold on;
for i = 1:size(faceMx,1)
diamPlot = (diaVec(i)/max(diaVec))*3;
plot3([ptCoordMx(faceMx(i,1),1);ptCoordMx(faceMx(i,2),1)],...
[ptCoordMx(faceMx(i,1),2);ptCoordMx(faceMx(i,2),2)], ...
[ptCoordMx(faceMx(i,1),3);ptCoordMx(faceMx(i,2),3)],'r','linewidth',diamPlot);hold
on;
end
hold on; grid off; axis off;
109
mesh: ooMesh;
constructor createfromSTLFiletoMesh(aSTLFileName:string);
procedure loadSTLFile(aSTLFileName:String);
function addPtAtNewOrExistingIdx(var aPtCoordMx: PDblMatrix;p1: PDblArray):integer;
procedure addPoint(var ptCoordMx: PDblMatrix;aP: PDblArray);
class procedure test();
private
function clean(aLine:String):string;
end;
implementation
110
end;
end;
NFaces:=0;
iFacetLineIdx := 3;
while iFacetLineIdx < LinesInFile.count-1 do begin
Nfaces := NFaces+1;
setlength(faceMx,NFaces+1, 6); // add an index for zeroth element
aLine := clean(LinesInFile[iFacetLineIdx]);
p1 := ooCaseFileReader.parseLineForDouble(aLine, n);
p1Idx := addPtAtNewOrExistingIdx(ptCoordMx, p1);
aLine := clean(LinesInFile[iFacetLineIdx+1]);
p2 := ooCaseFileReader.parseLineForDouble(aLine, n);
p2Idx := addPtAtNewOrExistingIdx(ptCoordMx, p2);
aLine := clean(LinesInFile[iFacetLineIdx+2]);
p3 := ooCaseFileReader.parseLineForDouble(aLine, n);
p3Idx := addPtAtNewOrExistingIdx(ptCoordMx, p3);
// NFaces points to the last faceIDx
PintArray(faceMx[NFaces]) := iVector([grpId , P1idx, P2Idx, P3Idx, 0, 0 ]);
//
iFacetLineIdx := iFacetLineIdx + 7;
end;
// needsa work --- try tyo avoid mesh
mesh:= ooMesh.create;
mesh.ptCoordMx := ptCoordMx;
mesh.faceMx := faceMx;
mesh.makeGroupMxFromFaceMx(mesh.groupMx,mesh.faceMx);
ooGambitWriter.CreateFlat('MyFirstSTLFileConervetedHoMai.msh', mesh.ptCoordMx, mesh.faceMx, mesh.groupMx, 0);
end;
{ STLReader }
111
begin
STLReader.test();
end.
interface
procedure STLwriterFromMesh();
//function Add(const S: string): Integer;
//function AddObject(const S: string; AObject: TObject): Integer; override;
implementation
procedure STLwriterFromMesh();
var fileName,FirstLine,Directory:string; aMesh:ooMesh; facMx:PIntMatrix; aline : TStringlist;
i,_p1Idx,_p2Idx,_p3Idx: Integer; Point1,Point2,Point3,Vector1,Vector2,normalVec:PdblArray;
begin
//read the face matrix from the mesh file
_p1Idx:=1; _p2Idx:=2; _p3Idx:=3;
fileName:= ('C:\andi\MG.V1\PurePascalMGV88.1\Data\HomaiData\MySTLConervetedmsh_cube_10_10_10.msh');
Directory:= 'C:\Users\Homa\Desktop';
aMesh := ooMesh.Create(fileName);
aline:= TStringlist.create;
aline.add('solid MESH');
for i := 1 to aMesh.NFaces do begin
Point1:= PDblArray(aMesh.ptCoordMx[aMesh.faceMx[i,_p1Idx]]);
Point2:= PDblArray(aMesh.ptCoordMx[aMesh.faceMx[i,_p2Idx]]);
Point3:= PDblArray(aMesh.ptCoordMx[aMesh.faceMx[i,_p3Idx]]);
112
Vector1:= getAsVector(Point1,Point2);
Vector2:= getAsVector(Point2,Point3);
normalVec:= aXb3d(Vector1,Vector2);
aline.add(' facet normal '+ printvectorAsstring(normalVec));
aline.add(' outer loop');
aline.add(' vertex '+ printvectorAsstring(Point1));
aline.add(' vertex '+ printvectorAsstring(Point2));
aline.add(' vertex '+ printvectorAsstring(Point3));
aline.add(' end loop');
aline.add(' endfacet');
end;
aline.SaveToFile(Directory+'\HR.stl');
end;
begin
STLwriterFromMesh();
end.
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, Buttons,
type
TRegistrationForm = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
Splitter1: TSplitter;
TabSheet2: TTabSheet;
BitBtn1: TBitBtn;
GroupBox1: TGroupBox;
Memo1: TMemo;
Memo2: TMemo;
GroupBox2: TGroupBox;
Memo3: TMemo;
SpeedButton1: TSpeedButton;
GroupBox3: TGroupBox;
Memo5: TMemo;
Memo4: TMemo;
PageControl2: TPageControl;
113
TabSheet3: TTabSheet;
Panel1: TPanel;
TabSheet4: TTabSheet;
procedure FormCreate(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
procedure testviews();
//Homai-- 10/22/2018
procedure SpeedButton1Click(Sender: TObject);
function VectorToSquerMatrix(A:PdblArray;N:integer):PdblMatrix;
function OffsetVector(a:PdblArray):PdblArray;
procedure transFormObject(JJ:PDblMatrix; b: PDblArray);
//function TransformedObj(b:pdblArray):PdblMatrix;
function MatrixMultiplication(A,B:PDblMatrix):PdblMatrix;
//function hardcodedTranspose(A:PdblMatrix):PdblMatrix;
private
{ Private declarations }
ptsObj1, ptsObj2:PDblMatrix;
public
{ Public declarations }
myGLPanel: TGLPanelSimple;
end;
var
RegistrationForm: TRegistrationForm;
implementation
{$R *.dfm}
end;
function TRegistrationForm.VectorToSquerMatrix(A:PdblArray;n:integer):PdblMatrix;
var i,j,u:integer; B:Pdblmatrix;
begin
114
u:=0;
setlength(B,n,n);
for i := 0 to n-1 do begin
for j:=0 to n-1 do begin
u:=u+1;
B[i,j]:= A[u];
end;
end;
result:=B;
end;
function TRegistrationForm.OffsetVector(a:PdblArray):PdblArray;
begin
setlength(result,3);
result[0]:=a[10];
result[1]:=a[11];
result[2]:=a[12];
end;
function TRegistrationForm.MatrixMultiplication(A,B:PDblMatrix):PdblMatrix;
var i,j,k:integer; sum:double;
begin
sum:=0;
setlength(result,3,3);
for i:=1 to 3 do begin
for j:=1 to 3 do begin
for k:=1 to 4 do begin
sum:= ((A[i,k]*B[k,j])+sum);
end;
result[i,j]:=sum;
sum:=0;
end;
end;
end;
115
{procedure TRegistrationForm.testviewsHardCoded();
var aR:ooRenderer; myPanel: TGLPanelSimple;
pts, pts2:PDblMatrix; labels: TStringList; lines: PDBlMxArray;
begin
Setlength(pts,4,3);
/// object1
copyVectorContent(PdblArray(pts[0]), Vector([0 ,0 ,0]));
copyVectorContent(PdblArray(pts[1]), Vector([10 ,10 ,0]));
copyVectorContent(PdblArray(pts[2]), Vector([11 ,1 ,1]));
copyVectorContent(PdblArray(pts[3]), Vector([12 ,2 ,2]));
labels:=TStringList.create; labels.add('A');labels.add('B');labels.add('C');labels.add('D');
aR := ooLabelRenderer.create(pts, labels);
aR.setDefaultColor(0);
myGLPanel.addRenderer(aR);
/// object2
Setlength(pts2,4,3);
copyVectorContent(PdblArray(pts2[0]), Vector([1 ,1 ,0]));
copyVectorContent(PdblArray(pts2[1]), Vector([11 ,11 ,0]));
copyVectorContent(PdblArray(pts2[2]), Vector([12 ,1 ,1]));
copyVectorContent(PdblArray(pts2[3]), Vector([13 ,2 ,2]));
labels:=TStringList.create; labels.add('A"');labels.add('B"');labels.add('C"');labels.add('D"');
aR := ooLabelRenderer.create(pts2, labels);
aR.setDefaultColor(1);
myGLPanel.addRenderer(aR);
end; }
procedure TRegistrationForm.testviews();
var aR:ooRenderer; myPanel: TGLPanelSimple;
pts, pts2:PDblMatrix; labels: TStringList; lines: PDBlMxArray;
begin
labels:=TStringList.create; labels.add('A');labels.add('B');labels.add('C');labels.add('D');
aR := ooLabelRenderer.create(ptsObj1, labels);
aR.setDefaultColor(0);
myGLPanel.addRenderer(aR);
/// object2
labels:=TStringList.create; labels.add('__A"');labels.add('___B"');labels.add('___C"');labels.add('___D"');
aR := ooLabelRenderer.create(ptsObj2, labels);
aR.setDefaultColor(1);
myGLPanel.addRenderer(aR);
labels:=TStringList.create; labels.add('____A""');labels.add('____B""');labels.add('____C""');labels.add('____D""');
aR := ooLabelRenderer.create(ptsObj1, labels);
aR.setDefaultColor(11);
myGLPanel.addRenderer(aR);
end;
116
begin
b:=vector(0,12); Setlength(transformationMx,4,3);
Setlength(projectedOBj2,4,3); Setlength(transposeObj2,4,3);
OffsetVec:=vector(0,3);
Obj1Coord:= TStringlist.create;
Obj1Coord.addStrings(Memo1.lines); // this command reads the lines on the memo
p1:= parseLineForDouble(Obj1Coord[1]);
P2:= parseLineForDouble(Obj1Coord[2]);
p3:= parseLineForDouble(Obj1Coord[3]);
p4:= parseLineForDouble(Obj1Coord[4]);
Obj2Coord:=Tstringlist.create;
Obj2Coord.addStrings(Memo2.lines);
pprim1:= parseLineForDouble(Obj2Coord[1]);
pprim2:= parseLineForDouble(Obj2Coord[2]);
pprim3:= parseLineForDouble(Obj2Coord[3]);
pprim4:= parseLineForDouble(Obj2Coord[4]);
//b:=TransformationMx(p1,p2,p3,p4,pprim1,pprim2,pprim3,pprim4);
b:=ooXSolver.Homaitest(p1,p2,p3,p4,pprim1,pprim2,pprim3,pprim4);
//memo3.lines.addStrings(printVectorAsStringList(b)); // shows the whole transformation vector including offset as
vector
transformationMx:= VectorToSquerMatrix(b,3);
OffsetVec:= OffsetVector(b);
memo3.lines.addStrings(printMatrixDense(transformationMx));
memo4.lines.addStrings(printVectorAsStringList(OffsetVec));
transFormObject(transformationMx,OffsetVec);
end;
end.
117
if findDataInFile(aCaseFileName,mesh,aPropNameList,aPropMx) then begin
for i := Low(aPropMx) to High(aPropMx) do begin
if (aPropNameList[i] = 'flow') or (aPropNameList[i] = 'averagePressure') or (aPropNameList[i] = 'hematocrit') then
minimalistCaseFileWriter.writeVectorProperty(aPropNameList[i],PDBlArray(aPropMx[i]));
end;
end;
minimalistCaseFileWriter.saveToFile;
end;
Appendix E: Code for finding the data from the case file
This is a string of methods and procedures required to read data from file. The method first
searches the file for all events of the key “vector” and stores the names of the vector in a
tStringList. The dataMatrix is then filled using the
ooCaseFileReader.getTubeVectorPropertyForGroups procedure. This method does not currently
work for point property vectors and should be updated in the future.
Definitions:
Implementation:
aPropNameList := TStringList.Create;
for i := 1 to aTempList.Count-1 do begin
aPropNameList.add(aTempList[i]); aPropValueVector[i-1] := aPropValueVector[i];//remove the diameter vector
end;
setLength(aPropValueVector,aPropNameList.Count,nwk.NFaces+1);
if aPropNameList.Count > 0 then result := true
else result := false;
end;
118
key := 'vector=';
for i := 0 to LinesInFile.Count-1 do begin
aLine := LinesInFile[i];
if containsText(aLine,key) then begin
aStrL := TStringList.Create;
n := ExtractStrings([' '], [' '], Pchar(aLine), aStrL);
aPropName := StringReplace(aStrL[0], '(vector=','',[rfIgnoreCase]);
if aPropNameList.Count = 0 then aPropNameList.Add(aPropName)
else if not (aPropName = aPropNameList[aPropNameList.Count-1]) then aPropNameList.Add(aPropName);
end;
end;
end;
119
//GHartung 10/9/2018 -- a minimalist way of storing case and network files
//Derived from ooCaseFileWriterSource by ALinninger
//since our vascular generation code has become so popularized, people want our structures, but instead of sharing the whole
logic
//of the case/nwk/GAMBIT format with them, it is easier to make a minimalist format for them, this is such a writer and
reader.
//takes a network and writes a single .casx file
unit ghCaseXFileSource;
interface
uses
Classes, SysUtils, SAEInterfaces, Dialogs,
ooRoot, ooTubeMeshSource, ooGambitWriterSource, ooCaseFileReaderSource, ooGambitConstants,
ooUtilities.V2, ghCaseFileUtilitiesSource;
const
ooVectorId = 'vector';
ghMinimalistCaseFileExt= '.casx';
pathTag = 'path=';
caseFileExt = '.cs31';
nwkExt = '.nwk';
authorString = 'File format designed by GHartung and ALinninger 10/9/2018';
dateString = 'This file was created by LPPD in Chicago,US on: ';
copyrightString = 'copyright by LPPD in Chicago,US; not for use without expressed permissions by ALinninger';
instructionString = 'the header tags are, "point coordinates", "connectivity matrix", and "vector"';
NoteString = 'note, there may be more than one vector';
type
ghCaseXFileWriter = class
caseFileName:string;
LinesInFile: TStringList;
mesh: ooTubeMesh;
constructor create(aCaseFileName:String; aDvector: PDblArray; aMesh: ooTubeMesh; anExt:string=caseFileExt);
procedure writeHeader;
procedure addPointSection;
procedure addFaceSections;
function writeFace(aFaceInfo: PIntArray):string;
procedure writeVectorProperty(propName: string; anArray: PDblArray);
procedure saveToFile;
end;
120
ghCaseXFileReader = class
caseFileName:string;
LinesInFile: TStringList;
mesh: ooTubeMesh;
constructor create(matrixFileName:string);
procedure readPointCoordinates(var ptCoordMx: PDblMatrix; startIdx,endIdx:integer);
procedure readFaceMatrix(var faceMx: PIntMatrix; startIdx,endIdx:integer);
function parseLineForIntegersNew(aLine:string): PIntArray;
function parseLineForDoublesNew(aLine:string):PDblArray;
procedure readVector(var aVec:PDblArray; startIdx,endIdx:integer);
end;
ghTubeMesh = class(ooTubeMesh)
constructor createWithSize1;
end;
implementation
constructor ghTubeMesh.createWithSize1;
var i:integer;
begin
NPoints := 1; nFaces := 1; setLength(dia,1);
setLength(ptCoordMx,1,3); setLength(faceMx,1,6); setLength(groupMx,1,6);
setLength(pointMx,nPoints+1,maxPointCol); setLength(cellMx,nFaces+1,6);
end;
procedure ghCaseXFileWriter.saveToFile;
begin saveToFileFromSTringList(linesInFile,caseFileName); end; //use method from ghCaseFileUtilities to save to file
procedure ghCaseXFileWriter.writeHeader;
var nwkFileNameWithoutPath: string;
begin
LinesInFile.add(commentConstant+modelHeader);
LinesInFile.add(commentConstant+authorString);
121
LinesInFile.add(commentConstant+dateString+DateToStr(Now));
LinesInFile.add(commentConstant+copyrightString);
LinesInFile.add(commentConstant+instructionString);
LinesInFile.add(commentConstant+NoteString);
LinesInFile.add(GambitBlank);
end;
procedure ghCaseXFileWriter.addPointSection;
var i,j,I1, I2:integer; aLine: string;
begin
LinesInFile.add(commentConstant+ptCoordHeader+'; nPoints='+intToStr(mesh.nPoints));
for i := 1 to high(mesh.ptCoordMx) do begin
aLine := '';
for j := low(mesh.ptCoordMx[i]) to high(mesh.ptCoordMx[i]) do begin
aLine:= aLine + Format(' %15.10e' , [mesh.ptCoordMx[i,j]])+ ' '; end;
LinesInFile.add(aLine);
end;
LinesInFile.add(endSectionConstant+ptCoordHeader);
LinesInFile.add(GambitBlank);
LinesInFile.add(GambitBlank);
end;
procedure ghCaseXFileWriter.addFaceSections;
var iFace,Nfaces:integer; aLine:string;
begin
LinesInFile.add(commentConstant+connectivityHeader+'; nArcs='+intToStr(mesh.NFaces));
Nfaces := high(mesh.faceMx);
for iFace := 1 to Nfaces do begin
aLine := writeFace(PIntArray(mesh.faceMx[iFace]));
LinesInFile.add(aLine);
end;
LinesInFile.add(endSectionConstant+connectivityHeader);
LinesInFile.add(GambitBlank);
122
LinesInFile.add(GambitBlank);
end;
123
faceInfo := parseLineForIntegersNew(LinesInFile[i]);
for j := 0 to 4 do begin
case j of
0: faceMx[iFace,j] := 1;
1: faceMx[iFace,j] := faceInfo[0];
2: faceMx[iFace,j] := faceInfo[1];
3: faceMx[iFace,j] := 0;
4: faceMx[iFace,j] := 0;
end;
end;
iFace := iFace + 1;
end;
mesh.nFaces := iFace-1;
end;
function ghCaseXFileReader.parseLineForDoublesNew(aLine:string):PDblArray;
var i,n:integer; aStrL: TStringList;
begin
aStrL := TStringList.Create;
n := ExtractStrings([' '], [' '], Pchar(aLine), aStrL);
Setlength(result,n);
for i:= 0 to n-1 do begin result[i] := StrToFloat(aStrL[i]); end;
aStrL.destroy;
end;
end.
124
This is a callback procedure from an onClick action to a button on a Windows Form (TForm)
object. The procedure uses an openDialog function to allow the user to select a icem mesh file.
The global parameter mesh (type ooMesh).
This is the code that encompasses the ooANSYSreader and ooANSYSwriter objects. These
objects each have the global parameters linesInFile (TStringList) and mesh (ooMesh). To
retrieve the mesh from an icem mesh writer, the user can access the public global mesh object
within the ooANSYSreader directly. Note, original lines by IGG and AL are still included to
show history of the reader.
//GH 10/31/2018 -- fully inhereted the code, major rewrites to streamline and make more robust.
//also, cleanup of unused information and methods
//updated header tags, how the program searches for header tags, and how to store volumes
//Created 2/24/12 to read .msh files created by ANSYS in the fluent format
//and then writes the file in the necessary GAMBIT format
unit ghANSYSMeshFileSource;
125
interface
const
ANSYSDim = '(0 " Created by : FLUENT'; //GH 10/31/2018 -- shortened
ANSYSFaces = '(13 (0'; //GH 10/31/2018 -- updated, ansys switchis this tag all the time
ANSYSBoundaryFaces = '(0 "Faces of zone PART.1")';
ANSYSZones = '(0 "Zone Sections")';
ANSYSPtBegin = '(10 ('; // beginning of points Block
ANSYSCellBegin = '(12 ('; // beginning of Cell Block
ANSYSFaceBegin = '(13 ('; // beginning of face block
type
ooANSYSReader = Class(TObject)
IdxS1, IdxS2, IdxS3, IdxS4: integer;
mesh:ooMesh;
thefile: TextFile;
LinesInFile: TStringList;
aLine: String;
pointList:TList;
tempFMx: PIntMatrix;
bArray: array of boolean; //array of isBoundaryGroup
126
procedure allocateFaceMx(nrOfPointsPerFace: integer);
procedure readFaceSection(var faceMx: PIntMatrix; startIdx: integer; var endIdx, iFace: integer; var aGrMx: PIntMatrix);
procedure updateFaceInfo(var faceInfo: PIntArray; iFace: integer);
procedure swapBoundaryFaceValues(anArray: PIntArray);
//GH
function parseFaceMxForNVolumes:integer;
private
procedure arrangeFaceMx(var tempFMx, faceMx: PIntMatrix);
procedure addSectionToFaceMx(var tempFMx, faceMx: PIntMatrix;
var grpIdx, faceCount: integer);
procedure makeGroupMxFromFaceMx(var aGroupMx, aFaceMx: PIntMatrix);
end;
ooANSYSwriter = Class(TObject)
meshFileName:string;
LinesInFile: TStringList;
mesh: ooMesh;
sectionCounter:integer;
constructor createAndSave(aMeshFileName:String; aMesh: ooMesh);
procedure writeHeader;
procedure addPointSection;
procedure addVolumeSection;
procedure addFaceSections;
function writeFace(aFaceInfo: PIntArray):string;
procedure addZoneSection;
procedure saveToFile;
End;
//GH
ghMesh = class(ooMesh)
constructor createWithSize1;
end;
function IntToHexStr(i:integer):string;
function parseLineForIntegersNew(aLine:string):PIntArray;
function IsThisABoundarySection(aLine:string): boolean;
implementation
127
if not FileExists(Fname) then begin ShowMessage('The selected meshfile: ' + Fname + ' does not exist. Please check *.msh
file'); exit; end;
LinesInFile.LoadFromFile(Fname);
IDxS1 := findLineContainingKey(ANSYSDim); //GH 10/31/2018
IdxS2 := findLineContainingKey(ANSYSFaces);
IdxS3 := LinesInFile.IndexOf(ANSYSZones);
if (IdxS1 = -1) then begin ShowMessage(ANSYSDim + ' tag not found'); exit; end;
if (IdxS2 = -1) then begin ShowMessage(ANSYSFaces + ' tag not found'); exit; end; //GH 7/26/2018 -- wrong statement
in warning
if (IdxS3 = -1) then begin ShowMessage(ANSYSZones + ' tag not found'); exit; end;
LinesInFile.Delimiter := #0032;
LinesInFile.QuoteChar := #0032;
//need to instantiate mesh
mesh := ooMesh(ghMesh.createWithSize1); //GH method for making a mesh from nothing
// read points section
readPointSectionHeader(mesh.NPoints,fromIdx, toIdx, dimensions);
Setlength(mesh.ptCoordMx,mesh.NPoints+1, dimensions); // 2 or 3 dimensional Points section
readPointCoordinates(mesh.ptCoordMx, dimensions, fromIdx, toIdx);
// read face section
SetLength(mesh.groupMx , maxGroupRow, maxGroupCol);
readFaceMatrixAndGroups(mesh.faceMx, mesh.groupMx);
end;
//GH 10/31/2018 -- a method that allows finding idx of partial string in a line
function ooAnsysReader.findLineContainingKey(aKey:string):integer;
var i:integer;
begin
result := -1;
for i := 0 to LinesInFile.Count-1 do begin
aLine := LinesInFile[i];
if containsText(aLine,aKey) then begin result := i; break; end;
end;
end;
function ooANSYSReader.findStringBetweenLines(idx1,idx2:integer;aString:string):integer;
var i:integer;
128
begin
for i := idx1 to idx2 do begin;
if Pos(aString, LinesInFile[i]) <> 0 then begin result := i; exit; end;
end;
result := -1;
end;
function ooANSYSReader.parseLineForDoublesNew(aLine:string):PDblArray;
var i,n:integer; aStrL: TStringList;
begin
aStrL := TStringList.Create;
n := ExtractStrings([' '], [' '], Pchar(aLine), aStrL);
Setlength(result,n);
for i:= 0 to n-1 do begin result[i] := StrToFloat(aStrL[i]); end;
aStrL.destroy;
end;
grpCount := 0;
129
while (iFace < mesh.NFaces+1) do begin
SetLength(bArray,grpCount+1);
bArray[grpCount] := readFaceSectionFlat(tempFMx, fromIdx, toIdx, iFace, aGrMx);
fromIdx := toIdx; grpCount := grpCount +1;
end;
arrangeFaceMx(tempFMx, faceMx);
makeGroupMxFromFaceMx(aGrMx, faceMx);
mesh.iNVolumes := parseForNrOfVolumes; // changed IGG 2/28/12
end;
procedure ooANSYSReader.allocateFaceMx(nrOfPointsPerFace:integer);
begin
if nrOfPointsPerFace = 2 then SetLength(mesh.faceMx,mesh.NFaces+1, MaxFaceCol); // 2Pt faces
if nrOfPointsPerFace = 3 then SetLength(mesh.faceMx,mesh.NFaces+1, MaxFaceCol+1); // 3Pt faces
if nrOfPointsPerFace = 4 then SetLength(mesh.faceMx,mesh.NFaces+1, MaxFaceCol+2); // 4Pt faces
end;
130
ptArray := parseLineForIntegersNew(Clean(aLine));
result := ptArray[headerIndex];
end;
131
// write last group
ei := iFace -1;
faceInfo[_GroupID]:= pGrp; faceInfo[_b]:= bi; faceInfo[_e]:= ei;
StoreSectionInGroupMX(aGroupMx,faceInfo);
end;
procedure ooANSYSReader.readFaceSection(var faceMx: PIntMatrix;startIdx:integer; var endIdx, iFace: integer; var aGrMx:
PIntMatrix);
var i,j, toIdx, fromIdx:integer; faceInfo: PIntArray; aLine:string; isBoundary: boolean;SectionIdx: integer;
begin
// read section header
aLine := LinesInFile[startIdx];
faceInfo := parseLineForIntegersNew(Clean(aLine));
// Section Index;
sectionIdx := faceInfo[0];
StoreSectionInGroupMX(aGrMx, faceInfo);
fromIdx := startIdx + 1;
// Lin 5/10/2010 - read one line less
toIdx := fromIdx + (faceInfo[2] - faceInfo[1]) ; // number of new faces
//result := IsThisABoundarySection(fromIdx);
for i := fromIdx to toIdx do begin
faceInfo := parseLineForIntegersNew(LinesInFile[i]);
swapBoundaryFaceValues(faceInfo); // Lin 10/2/2005 - Swap if face starts with a zero
for j := low(faceInfo) to high(faceInfo) do
begin faceMx[iFace,j+1] := faceInfo[j]; end; //j+1 so store faces correctly IGG 2/24/12
// Lin 1/6/2008
//storeSectionIdxInCurrentFace(iFace,faceMx,sectionIdx);
faceMx[iFace,_GroupID]:=sectionIdx;
iFace := iFace + 1;
end;
endIdx := toIdx + 4; // push to new face and include two linefeeds for ');)' and header
end;
132
end;
function ooANSYSReader.parseForNrOfVolumes:integer;
var I1:integer; ptArray: PIntArray;
begin
I1 := findStringBetweenLines(0, LinesInFile.count-1, ANSYSCellBegin);
// if length(aLine) > 0 then begin //GH
if I1 > 0 then begin
aLine := LinesInFile[I1];
ptArray := parseLineForIntegersNew(Clean(aLine));
result := ptArray[2];
end
else result := parseFaceMxForNVolumes;
// else result := 0;
end;
//GH -- this method is time consuming and poorly written, but is a bandaid for an impressing deadline
function ooANSYSReader.parseFaceMxForNVolumes:integer;
var i,ptsInFace:integer; volumeList:PIntArray;
begin
mesh.iNFaces := 0; mesh.bNFaces := 0;
setLength(volumeList,mesh.NFaces+1); //dangerous assumption here - nVolumes is <= nFaces
ptsInFace := mesh.nrOfPtsInFaceMx;
for i := 1 to mesh.nFaces do begin
addIdxNoDuplicate(mesh.faceMx[i,1+ptsInFace],volumeList);
addIdxNoDuplicate(mesh.faceMx[i,1+ptsInFace+1],volumeList);
if (mesh.NFaces-howManyNonZeroElements(volumeList))<2 then
setLength(volumeList,howManyNonZeroElements(volumeList)+2);
if isIdxInArray(0,PIntArray(mesh.faceMx[i])) then mesh.bNFaces := mesh.bNFaces + 1
else mesh.iNFaces := mesh.iNFaces + 1
end;
removeTrailingZeros(volumeList); result := length(volumeList);
end;
133
meshFileName := stringReplace(aMeshFileName,'.msh','.icem.msh',[]);
mesh := aMesh;
sectionCounter := 1;
writeHeader;
addPointSection;
addVolumeSection;
sectionCounter := sectionCounter + 1;
addFaceSections;
sectionCounter := sectionCounter + 1;
addZoneSection;
saveToFile;
end;
procedure ooANSYSwriter.writeHeader;
begin
linesInFile.Add(ANSYSHeader);
linesInFile.Add(ANSYSDimensions);
linesInFile.Add(ANSYSPointHeader);
end;
procedure ooANSYSwriter.addVolumeSection;
var aLine:string;
begin
aLine := '(12 (0 1 '+ IntToHexStr(mesh.iNVolumes) + ' 0 3))'; LinesInFile.add(aLine);
aLine := '(12 (1 1 '+ IntToHexStr(mesh.iNVolumes) + ' 1 2))'; LinesInFile.add(aLine);
end;
procedure ooANSYSwriter.addPointSection;
var aLine:string; i,j:integer;
begin
aLine := '(10 (0 1 '+ IntToHexStr(mesh.nPoints)+' 0 0))'; LinesInFile.add(aLine);
aLine := '(10 (1 1 ' + IntToHexStr(mesh.nPoints) + ' ' + intToStr(sectionCounter) + ' 3)'; LinesInFile.add(aLine);
LinesInFile.add('(');
for i := 1 to high(mesh.ptCoordMx) do begin
aLine := '';
aLine:= aLine + floatToStr(mesh.ptCoordMx[i,_X])+ ' ';
aLine:= aLine + floatToStr(mesh.ptCoordMx[i,_Y])+ ' ';
aLine:= aLine + floatToStr(mesh.ptCoordMx[i,_Z]);
LinesInFile.add(aLine);
end;
LinesInFile.add('))');
end;
procedure ooANSYSwriter.addFaceSections;
var i,Nfaces,fromIdx, toIdx, sectionIdx:integer; aLine:string;iFace, iG, groupIdx:integer;
begin
Nfaces := high(mesh.faceMx);
aLine := '(13 (0 1 '+ IntToHexStr(NFaces) + ' 0 0))'; LinesInFile.add(aLine);
iFace := 1;
for iG := low(mesh.groupMx) to high(mesh.groupMx) do begin
134
groupIdx := mesh.groupMx[iG,_GroupID];
if groupIdx = 0 then break;
if mesh.groupMx[iG,1] > mesh.bnVolumes then aLine := '(0 "Interior faces of zone ' + IntToHexStr(groupIdx)+'")'
else aLine := '(0 "Faces of zone ' + IntToHexStr(groupIdx)+'")';
LinesInFile.add(aLine);
aLine := '(13 ('+IntToHexStr(groupIdx)+' ' + IntToHexStr(mesh.groupMx[iG,_b])+ ' '+
IntToHexStr(mesh.groupMx[iG,_e]) +
' ' + intToStr(sectionCounter)+' 3)(';
fromIdx := LinesInFile.add(aLine);
for iFace := mesh.groupMx[iG,_b] to mesh.groupMx[iG,_e] do begin
aLine := writeFace(PIntArray(mesh.faceMx[iFace]));
LinesInFile.add(aLine);
end;
LinesInFile.add(')'); LinesInFile.add(')');
end;
end;
135
LinesInFile.add('(39 (' + IntToStr(mesh.groupMx[i-2,0]) + ' wall ' + IntToHexStr(mesh.groupMx[i-2,0])+')())')
else LinesInFile.add('(39 (' + IntToStr(mesh.groupMx[i-2,0]) + ' interior int_' + IntToHexStr(mesh.groupMx[i-
2,0])+')())');
end;
end;
procedure ooANSYSwriter.saveToFile;
begin linesInFile.SaveToFile(meshFileName); end;
///////////////////////////////////// end writer //////////////////////////////////////////////////
function IsThisABoundarySection(aLine:string):boolean;
var firstFaceInfo: PIntArray;
begin
// firstFaceInfo := parseLineForIntegersNew(LinesInFile[firstLineIdx]);
firstFaceInfo := parseLineForIntegersNew(aLine);
if (firstFaceInfo[high(firstFaceInfo)] = 0) or ((firstFaceInfo[high(firstFaceInfo)-1] = 0)) then result := TRUE
else result := False;
end;
end.
136
Appendix I: Calling the Gambit Mesh Writer (already known, but included for
completeness)
procedure TForm2.Button2Click(Sender: TObject);
var aCaseFileWriter:ooCaseFileWriter; aGambitWriter:ooGambitWriter; aDiaVect:PDblArray;
begin // save mesh file button //GH 12/18/2017 -- add save mm file
aGambitWriter := ooGambitWriter.CreateFlat(aMeshFileName, aAR.mesh.ptCoordMx, aAR.mesh.faceMx,
aAR.mesh.groupMx, aAR.mesh.NVolumes);
writeMMFile(aMeshFileName);
end;
Calling the GAMBIT reader (already known, but included for completeness)
137
procedure TForm2.Button5Click(Sender: TObject);
begin
aCaseFileName := stringreplace(aCaseFileName, 'casx','',[]);
mesh.saveAsCaseAndNWKFile(aCaseFileName+'v2.cs31');
finishedLabel.Caption := 'finished';
end;
138