Template



File Formats for Unstructured Computational MeshesGambit Meshfile (*.msh) in 2- and 3-DLaboratory for Product and Process DesignDirector: Andreas A. LinningerLPPD-Project ReportAuthors: Argyris Politis, Brian Sweetman, and Andreas A. LinningerChicago, 4/11/2008Update by Grant HartungAddition of Chapter 1: mm Header Files for MeshChapter 5: Three Dimensional Mesh (Hexahedrons)Chapter 6: cs31/nwk Files4/1/2016Version 2Update by Guoren XuAddition of Chapter 10: Raw Image Formats10/10/2016Version 3Updated by Grant HartungAddition of Chapter 11: FLUENT Data Formats2/24/2017Version 4Updated by Chang Sub Park, Grant Hartung, Homa Rashidisabet, Claudia Vesel10/25/2018Version 5Table of contents TOC \o \h \z \u 1Summary PAGEREF _Toc529953961 \h 72CHAPTER 1: mm Header Files for Mesh Files (.mm) PAGEREF _Toc529953962 \h 83CHAPTER 2: Two Dimensional Meshes (Quads) PAGEREF _Toc529953963 \h 113.1The Points Section: (0 "Dimension:") PAGEREF _Toc529953964 \h 113.2The Faces Section: (0 "Faces:") PAGEREF _Toc529953965 \h 123.3The Cells Section: (0 "Cells:") PAGEREF _Toc529953966 \h 123.3.1Interior with no subdivisions - Default-Interior PAGEREF _Toc529953967 \h 123.3.2Interior with several subdivisions PAGEREF _Toc529953968 \h 123.4The Zones Section: (0 "Zones:") PAGEREF _Toc529953969 \h 133.4.1Boundaries no subdivisions – default wall PAGEREF _Toc529953970 \h 133.4.2Implementation of Zones: PAGEREF _Toc529953971 \h 143.4.3Interior with several subdivisions PAGEREF _Toc529953972 \h 144CHAPTER 3: Two Dimensional Mesh (Triangles) PAGEREF _Toc529953973 \h 154.1The Points Section: (0 "Dimension:") PAGEREF _Toc529953974 \h 154.2 PAGEREF _Toc529953975 \h 164.3The Faces Section: (0 "Faces:") PAGEREF _Toc529953976 \h 164.4The Cells Section: (0 "Cells:") PAGEREF _Toc529953977 \h 174.5The Zones Section: (0 "Zones:") PAGEREF _Toc529953978 \h 175CHAPTER 4: Three Dimensional Mesh (Tetrahedrons) PAGEREF _Toc529953979 \h 195.1The Points Section: (0 "Dimension:") PAGEREF _Toc529953980 \h 195.2The Faces Section: (0 "Faces:") PAGEREF _Toc529953981 \h 195.3The Cells Section: (0 "Cells:") PAGEREF _Toc529953982 \h 215.4The Zones Section: (0 "Zones:") PAGEREF _Toc529953983 \h 216CHAPTER 5: Three Dimensional Mesh (Hexahedrons) PAGEREF _Toc529953984 \h 236.1The Points Section: (0 "Dimension:") PAGEREF _Toc529953985 \h 246.2The Faces Section: (0 "Faces:") PAGEREF _Toc529953986 \h 246.3The Cells Section: (0 "Cells:") PAGEREF _Toc529953987 \h 286.4The Zones Section: (0 "Zones:") PAGEREF _Toc529953988 \h 287CHAPTER 6: cs31/nwk Files PAGEREF _Toc529953989 \h 297.1The Case File Section: (.cs31) PAGEREF _Toc529953990 \h 297.2The NWK File Section: (.nwk) PAGEREF _Toc529953991 \h 308CHAPTER 7: – Neutral Files PAGEREF _Toc529953992 \h 309CHAPTER 8: – Nastran Files PAGEREF _Toc529953993 \h 329.1The NASTRAN File PAGEREF _Toc529953994 \h 3310CHAPTER 8 – Conversion of msh to Nastran PAGEREF _Toc529953995 \h 3511CHAPTER 9 – Extraction of JPEG, TIFF and STL Files PAGEREF _Toc529953996 \h 3612 PAGEREF _Toc529953997 \h 3713CHAPTER 10 – Raw Image Formats PAGEREF _Toc529953998 \h 3813.1DICOM PAGEREF _Toc529953999 \h 3813.2JPEG PAGEREF _Toc529954000 \h 3913.3TIFF PAGEREF _Toc529954001 \h 3913.4PNG PAGEREF _Toc529954002 \h 4213.5BMP PAGEREF _Toc529954003 \h 4214CHAPTER 11 – FLUENT Data Formats PAGEREF _Toc529954004 \h 4314.1Mesh File Format PAGEREF _Toc529954005 \h 4314.1.1Mesh Converter PAGEREF _Toc529954006 \h 4314.1.1.1Step 1: Modify the Header PAGEREF _Toc529954007 \h 4314.1.1.2Step 2: Reading the point coordinate matrix PAGEREF _Toc529954008 \h 4414.1.1.3Step 3: Reorder the face matrix PAGEREF _Toc529954009 \h 4414.1.1.4Step 4: Minimize the Zone Section PAGEREF _Toc529954010 \h 4414.2Data File Format PAGEREF _Toc529954011 \h 4514.2.1Writing a Walk-In Brain Case File From FLUENT PAGEREF _Toc529954012 \h 45Summary PAGEREF _Toc529954013 \h 45Step 1: PAGEREF _Toc529954014 \h 45Step 2: PAGEREF _Toc529954015 \h 45Step 3: PAGEREF _Toc529954016 \h 45Step 4: PAGEREF _Toc529954017 \h 46Step 5: PAGEREF _Toc529954018 \h 4715References PAGEREF _Toc529954019 \h 4816Appendix PAGEREF _Toc529954020 \h 4816.1CTRIA3 Format PAGEREF _Toc529954021 \h 5316.2CQUAD4 Format PAGEREF _Toc529954022 \h 5417Delphi converter application PAGEREF _Toc529954023 \h 5917.1Summary PAGEREF _Toc529954024 \h 5917.2Main functions PAGEREF _Toc529954025 \h 6017.2.1Convert NWK Files to Splines PAGEREF _Toc529954026 \h 6017.2.2Convert CaseFiles To Splines PAGEREF _Toc529954027 \h 6117.2.3Convert Splined to Even2ptmesh PAGEREF _Toc529954028 \h 6317.2.4Editing and Movement PAGEREF _Toc529954029 \h 6517.2.5CleanSplinedNW PAGEREF _Toc529954030 \h 6617.3Additional functions for visualization and statistics PAGEREF _Toc529954031 \h 6817.3.1DisplayNWK PAGEREF _Toc529954032 \h 6817.3.2SplineNWKStatistics PAGEREF _Toc529954033 \h 6817.3.3NWKStatistics PAGEREF _Toc529954034 \h 6918Converting among mesh and stl PAGEREF _Toc529954035 \h 6918.1Converter from mesh to stl PAGEREF _Toc529954036 \h 7118.2Case Study A: Tetrahedral Tube Mesh PAGEREF _Toc529954037 \h 7218.3Converter from stl to msh PAGEREF _Toc529954038 \h 7218.4Walk through of viewer application for visualizing mesh files PAGEREF _Toc529954039 \h 7319Registration of two objects PAGEREF _Toc529954040 \h 7419.1Walk through of viewer application for visualizing mesh files PAGEREF _Toc529954041 \h 7520Documentation of ICEM/GAMBIT mesh converter. PAGEREF _Toc529954042 \h 7820.1Converting ICEM mesh file to GAMBIT mesh file: PAGEREF _Toc529954043 \h 7920.2Instructions for converting from GAMBIT to ICEM: PAGEREF _Toc529954044 \h 8121Documentation of Delphi “.cs31” and “.casx” converter. PAGEREF _Toc529954045 \h 8321.1Converting .cs31 file to .casx file: PAGEREF _Toc529954046 \h 8421.2Instructions for converting from .casx to .cs31: PAGEREF _Toc529954047 \h 8722Reading and Visualizing casx files in Matlab PAGEREF _Toc529954048 \h 89Table of figures TOC \h \z \c "Figure" Figure 1. The grid consisted of triangles as described in this report. PAGEREF _Toc529954049 \h 19Figure 2. A tetrahedral volume of the mshFile example given herein. PAGEREF _Toc529954050 \h 24Figure 3.3: Volume numbering scheme for hexahedral meshes. PAGEREF _Toc529954051 \h 29Figure 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). PAGEREF _Toc529954052 \h 34Figure 5. A mesh extracted in VTK by applying the Delaunay Triangulation PAGEREF _Toc529954053 \h 38Figure 6. Converter software GUI. PAGEREF _Toc529954054 \h 60Figure 7. Accessing converter from the Viewer application. PAGEREF _Toc529954055 \h 60Figure 8. Main tabs in the converter. PAGEREF _Toc529954056 \h 61Figure 9. Procedure to convert 2-point networks to spline networks. PAGEREF _Toc529954057 \h 61Figure 10. Conversion of 2-point network to spline network. PAGEREF _Toc529954058 \h 62Figure 11. Procedure to convert 2-point networks to spline networks. PAGEREF _Toc529954059 \h 63Figure 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. PAGEREF _Toc529954060 \h 63Figure 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. PAGEREF _Toc529954061 \h 64Figure 14. Procedure to convert spline networks to 2-point networks. PAGEREF _Toc529954062 \h 65Figure 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. PAGEREF _Toc529954063 \h 65Figure 16. Procedure to convert spline network point properties to 2-point format. PAGEREF _Toc529954064 \h 66Figure 17. Conversion of spline network point property (pressure in this case) to 2-point format. PAGEREF _Toc529954065 \h 66Figure 18. Procedure to convert 2-point networks to spline networks. PAGEREF _Toc529954066 \h 67Figure 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. PAGEREF _Toc529954067 \h 67Figure 20. Procedure to clean spline networks with dangling vessels PAGEREF _Toc529954068 \h 68Figure 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. PAGEREF _Toc529954069 \h 69Figure 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. PAGEREF _Toc529954070 \h 71Figure 23. STL and mesh files comparison. (A). STL file of format for the shown geometry in Figure 24. (B). Gambit file of same geometry. PAGEREF _Toc529954071 \h 72Figure 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. PAGEREF _Toc529954072 \h 72Figure 25. Visualization of converted mesh to stl and original stl in Cerebroview. (B) Converted Mesh to stl. (C) original stl. PAGEREF _Toc529954073 \h 73Figure 26. Visualization of converted stl to mesh and original mesh in ViewerApplication. (A). original sled mouse msh file. (B). Converted msh . PAGEREF _Toc529954074 \h 73Figure 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. PAGEREF _Toc529954075 \h 75Figure 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. PAGEREF _Toc529954076 \h 78Figure 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. PAGEREF _Toc529954077 \h 79Figure 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. PAGEREF _Toc529954078 \h 80Figure 29. The ICEM mesh file has been converted to GAMBIT format and visualized using ViewerApplication.exe. PAGEREF _Toc529954079 \h 82Figure 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. PAGEREF _Toc529954080 \h 82Figure 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. PAGEREF _Toc529954081 \h 84Figure 29. Visualization of the original cs31 and nwk file created from grant’s artificial network generation code (version 1), Project_KFGenAndSolvingApp.exe. PAGEREF _Toc529954082 \h 85Figure 29. Visualization of the .casx file after being converted from .cs31. PAGEREF _Toc529954083 \h 88Figure 29. Visualization of the .casx file after being read by the casx file reader in Step 2. PAGEREF _Toc529954084 \h 89Figure 29. Visualization of the converted file (V2) in viewer application. PAGEREF _Toc529954085 \h 90Figure 30: Main workflow of the Matlab code PAGEREF _Toc529954086 \h 90Figure 31: (A) Arteries and vein fused structure (B) Simple bifurcation PAGEREF _Toc529954087 \h 91Figure 32: Matlab compiler used to convert an .m file into a stand-alone executable PAGEREF _Toc529954088 \h 91Figure 33: Running the stand-alone executable from the command prompt PAGEREF _Toc529954089 \h 92SummaryThis 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.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="Two Dimensional Steady State Diffusion Problem" author="Andreas A Linninger" date="11/13/2007" ProblemType="Diffusion" Comments="Add user defined comments here...">problemtype=Diffusion.V1\PurePascalMGV78_Ian_PhD\Data\msh\grid2_2D_2096.GAMBIT.v2.msh<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.The next section gives information about the simulation parameters.<constants>D=1.8e-9</constants><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><constants> initiates the section for simulation constants.D=1.8e-9 tells the simulation that the simulation parameter “D” has a value of 1.8e-9.</constants> ends the section delineating the simulation constants.<BoundaryConditions> begins the section delineating the boundary conditions for the simulation.bc0= defines the boundary condition named “bc0.SubSection tells the simulation that “bc0” does not apply to all faces but rather one group of faces. VarId=1 tells the simulation that “bc0” only applies to the 1st variable in the simulation.ID=17 tells the simulation which face group which this boundary applies to, in this case it is face group 17.type=Dirichlet tells the simulation what type of boundary condition is to be used, in this case the type is a Derichlet boundary condition. value=10/> tells the simulation the value of the boundary condition.</BoundaryConditions> ends the Boundary Conditions section.The simulation output data is listed in the following section:(vector=metabolism cell)(N=324 type=variable)(12 (0 1 144 0 0)(2.09054280042.27019783082.4486179572.64260703442.8379105753.00071787963.28832970193.983310066...)(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.09054280042.27019783082.4486179572.64260703442.8379105753.00071787963.28832970193.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. CHAPTER 2: Two Dimensional Meshes (Quads)In this chapter, the format of a two-dimensional *.msh file consisted of quadrilaterals is analytically described.The Points Section: (0 "Dimension:")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+001.000000000e+002.000000000e+000.000000000e+00…))The Faces Section: (0 "Faces:")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 Cells Section: (0 "Cells:")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).Interior with no subdivisions - Default-InteriorMeshfiles with no interior subdivision of the domain only have one entry:The default-interior refers a collection of all the faces that do not belong to a boundary specified by the user. It is the list of all faces that the code generator puts into the FaceList. 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.Interior with several subdivisionsIf more subdivisions were defined, more entries with leading (12 (…)) occur.The following example defines the domain “2” comprised of cells with index 1 until index 2.Example: (12 (2 1 2 1 3))Zeroth integer: A leading ‘(12’ is a constant specifier for all zones.First Integer: ‘2’The first index of the interior domains are labeled by an integer. We will call this the InteriorDomainIdentifier. Second and third Integer: ‘1 2’The second and third integer of the interior domains give the starting and the ending index of the InteriorDomain. Note again that interior domains must be numbered with contiguous indices.Fourth and fifth integer: ‘1 3))’The last two integers appears to be 1 and 3 for all interior domains closed with ‘))’.The Zones Section: (0 "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.Boundaries no subdivisions – default wallMeshfiles with no interior subdivision of the domain only have one entry:Example: (0 "Faces:")(13(0 1 18 0))(13(3 1 c 3 0)(2 5 6 9 0…))(45 (3 wall wall)())The integer ‘3’ defines the boundary wall called wall. Note that the boundary identifier also appears in the face section (both ‘3’ are marked in bold face for clarity).Implementation of Zones:In the lower sections of the file, there are two special sections:The cells section (0 "Cells:") and the zones section (0 "Zones:")Example from mg_case2.msh…..(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)())Interior with several subdivisionsIf more subdivisions were defined, more entries with leading (45 (…)) occur.The following example defines the zone ‘2’ as a fluid named ‘bottom’ andzone ‘3’ as a fluid with name ‘top’; and the groupings for the boundaries with index ‘4’ a wall called ‘wall3’, the groupings for the boundaries with index ‘5’ a wall called ‘wall2’, the groupings for the boundaries with index ‘6’ a wall called ‘wall1’, andthe default interior with index ‘8’. 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.First Integer: ‘2’The first index of the boundary domains are labeled by an integer. We will call this the BoundaryGroupingIdentifier Second and third string: ‘fluid bottom’The second and third string of the cells section qualify an interior domains by type (e.g. ‘fluid’, ‘solid’) and by name (e.g. ‘bottom’, ‘top’, ‘wall3’, etc). CHAPTER 3: Two Dimensional Mesh (Triangles)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.(0 "Dimension:") This is Header for “Dimension”(2 2)Dimensions of the domain, here it is 2DThe Points Section: (0 "Dimension:") 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 )) The Faces Section: (0 "Faces:") 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.(0 "Faces:") This is a Header(13 (0 1 1a 0)) “(13: stands for faces (0, 1: First index of faces, 1a: last index of faces, 0))”(13 (3 1 a 3 0)(“(13 stands for faces (3: wall-boundary faces, 1: first index of boundary faces, a: last index of boundary faces, 3, 0))”2 4 5 2 0“(2: number of points consist a face, 4: first point, 5: second point, 2: first volume that face belongs, 0: second volume, “0” stands for boundary)”the same for other boundary faces shown below.2 5 6 d 02 6 1 8 02 1 3 7 02 3 2 6 02 2 8 5 02 8 9 a 02 9 7 3 02 7 a 4 02 a 4 1 0))(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 42 5 b 2 e2 7 b 3 42 b 9 3 c2 8 d 5 92 d 2 5 62 d 3 6 72 d 1 7 82 d 6 8 b2 8 c 9 a2 c d 9 b2 9 c a c2 c 6 b d2 b c c e2 c 5 d e))The Cells Section: (0 "Cells:")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))The Zones Section: (0 "Zones:") (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.0000Figure SEQ Figure \* ARABIC 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.CHAPTER 4: Three Dimensional Mesh (Tetrahedrons)In this chapter, the format of a three-dimensional *.msh file consisted of tetrahedral volumes is discussed. The format of three-dimensional msh Files is similar with those for two dimensions analyzed in the previous chapters. However, some distinct differences are elaborated in this chapter. Such an msh File is constituted of four main parts, namely “Dimensions:”, “Faces”, “Cells” and “Zones”. Before these parts of the file, a header is shown, (0 "GAMBIT to Fluent File"), which informs us that this file was extracted from Gambit to be used as input for Fluent solver.The Points Section: (0 "Dimension:")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. 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 03 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 03: stands for the number of points forming a face6: First Point Index1: Second Point Index8: Third Point Index3: First Volume Index0: 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 facesa : stands for interior (see zones section)d : first index of interior faces1e: last index of interior faces2 : default-interiorIn 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 1where:3: stands for total number of points8: First Index of Points9: Second Index of Points7: Third Index of Points2: First Index of Volumes1: Second Index of VolumesIt 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.The Cells Section: (0 "Cells:")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))The first line is a header. In the second line:12: stands for cells1: First Index of Volumesc: Second Index of VolumesThe Zones Section: (0 "Zones:")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.(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)())In the last line the interior conditions are shown:(45 (10 interior default-interior)())45: stands for zones10: stands for interiorInterior: nameDefault-interior : interior facesIn Figure 2 the first volume (1) of the domain described above is depicted. 68580061468000Figure SEQ Figure \* ARABIC 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:Face 1: (7 8 2) see line “3 7 8 2 1 0” in boundary face section of mshFileFace 2: (8 9 7) see line “3 8 9 7 2 1” in interior face section of mshFileFace 3: (9 8 2) see line “3 9 8 2 9 1” in interior face section of mshFileFace 4: (7 9 2) see line “3 7 9 2 c 1” in interior face section of mshFileFrom 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.CHAPTER 5: Three Dimensional Mesh (Hexahedrons)In this chapter, the format of a three-dimensional *.msh file consisted of hexahedral volumes is discussed. The format of hexahedral msh Files is similar for tetrahedrals. However, some distinct differences are elaborated in this chapter. This type of msh File is constituted of four main parts, namely “Dimensions:”, “Faces”, “Cells” and “Zones”. Before these parts of the file, a header is shown, (0 "GAMBIT to Fluent File"), which informs us that this file was extracted from Gambit to be used as input for Fluent solver.The Points Section: (0 "Dimension:")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. 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 to which said faces belong. For the correct formatting of a hexahedral mesh structure the face matrix must follow a specific ordering scheme. A sample of a correct face section can be seen in below.(13 (3 1 6 0 0)(4 0 1 2 3 1 04 4 5 6 7 1 04 4 0 1 5 1 04 4 7 3 0 1 04 1 2 6 5 1 04 2 6 7 3 1 0))//(Face 1)//(Face 2)//(Face 3)//(Face 4)//(Face 5)//(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.194564099695003054355937250059626521971000 3 27797806750050089027044132500117284566040007 s 6 037973016764000 14 s5 5 aFigure 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 04: stands for the number of points forming a face0: First Point Index1: Second Point Index2: Third Point Index3: Fourth Point Index1: First Volume Index0: Second Volume Index (0 stands for exterior boundary)7969254889553621400536214Figure 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 facesa : stands for interior (see zones section)d : first index of interior faces1e: last index of interior faces2 : default-interior0)(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 1where:4: stands for total number of points8: First Index of Points9: Second Index of Points6: Third Index of Points7: Fourth Index of Points2: First Index of Volumes3321685456565002634615121285003647440121285001: Second Index of Volumes360680654685Volume 2020000Volume 28 s16471902095500230568537528500130556050101500 2 .229489071120001684655-5715Volume 1020000Volume 193154532829500 14420859207500 71647190175260008286753429000 1 d9 2304415400050033s . 0 . 6Figure SEQ Figure \* ARABIC 3.3: Volume numbering scheme for hexahedral meshes.The correct face matrix for the object in Figure 3 can be seen below.(0 “Faces:”)(13(0 1 B 0))(13(1 1 8 0 0)(4 0 1 2 3 1 0...)) (13(1 1 6 0 0)(4 6 7 8 9 1 2))//(Faces section)//(All faces (faces 1-B)//(first face group, Exterior Faces, faces 1-10)//(Face 1)//(Face 2)//(Face 3)//(Face 4)//(second face group, Interior Faces, Face 9)The Cells Section: (0 "Cells:")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))The first line is a header. In the second line:12: stands for cells1: First Index of Volumesc: Second Index of VolumesThe Zones Section: (0 "Zones:")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.(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)())In the last line the interior conditions are shown:(45 (10 interior default-interior)())45: stands for zones10: stands for interiorInterior: nameDefault-interior : interior facesCHAPTER 6: cs31/nwk Files The Case File Section: (.cs31)Case files (.cs31) are formatted the same as .mm files. The major difference is that a case file works with a network (.nwk) file as opposed to a mesh file (.msh). This means that a case file MUST include a data vector entitled “Dia” which contains the diameter information corresponding to the network file associated with it. Without this vector, the associated network file cannot be simulated or visualized.The NWK File Section: (.nwk)NWK files (.nwk) are a specific type of msh file that is 1-dimensional. NWK files are built as 2-point faces (lines) and diameter information. The diameter information is read from a .cs31 file and applied to each point which acts like a volume. The structure of a NWK file is otherwise the exact same as the msh file.CHAPTER 7: – Neutral Files 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_id2520PROGRAM: Gambit VERSION: 2.2.30 Jan 2008 NUMNP NELEM NGRPS NBSETS NDFCD NDFVL 18 22 1 0 2 2The 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 coordinatesThe 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 Header1: 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+000ENDOFSECTION HeaderThe cells connectivity of the elements in the mesh is given in the following section:ELEMENTS/CELLS 2.2.30 Header 1 3 3 12 1 131 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/CellENDOFSECTION HeaderThe last section described below provides general information of the meshGROUP: 1 ELEMENTS: 22 MATERIAL: 2 NFLAGS: 1GROUP : Total number of element groups (1 here)ELEMENTS: Total Number of element/Cells (22 here) MATERIAL: Type of Material (2 stands for fluid) NFLAGS : Number of Solver-Dependent Flags fluid 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22ENDOFSECTION HeaderCHAPTER 8: – Nastran Files 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.The NASTRAN File(This information is based on:)Figure 3 shows a mesh generated in ADINA using the nastran file given in REF _Ref195087593 \h Box 1.Figure SEQ Figure \* ARABIC 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 $* $*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$240411048260GRID: 1-9=node numbers; i, j, k=nodal coordinatesCQUAD: 4 node quadrilateral elements; 10=EGrp # 1-4=element numbers; i,j,k,l=nodal vertices00GRID: 1-9=node numbers; i, j, k=nodal coordinatesCQUAD: 4 node quadrilateral elements; 10=EGrp # 1-4=element numbers; i,j,k,l=nodal verticesBEGIN BULK GRID,1,,0.,0.,0. GRID,2,,5.,0.,0.GRID,3,,10.,0.,0.GRID,4,,0.,5.,0.GRID,5,,5.,5.,0.GRID,6,,10.,5.,0.GRID,7,,0.,10.,0.274701022860PSHELL: 10=group number; 30=material number; 0.25=shell thickness, 30=material numberMAT1: homogenous & isotropic; 30=material number; 3.E7=value of Young’s modulus; 0.33=Poisson Ratio; 2=density; 3=coefThermExp00PSHELL: 10=group number; 30=material number; 0.25=shell thickness, 30=material numberMAT1: homogenous & isotropic; 30=material number; 3.E7=value of Young’s modulus; 0.33=Poisson Ratio; 2=density; 3=coefThermExpGRID,8,,5.,10.,0.GRID,9,,10.,10.,0.CQUAD4,1,10,1,2,5,4 CQUAD4,2,10,2,3,6,5CQUAD4,3,10,4,5,8,7CQUAD4,4,10,5,6,9,8$define element properties (thickness : 0.25)PSHELL,10,30,0.25,30 $define material properties (Ymod=3e7Pa, PR=0.33)1946910110490FORCE: 20 (number matches LOAD above); 5=node number to which force is applied; -1000=force magnitude; 0,0,1 (direction of force is in z direction)SPC1: body is fixed in all directions at these nodes (1-4, 6-9). Node 5 is free because this is where the force is applied.00FORCE: 20 (number matches LOAD above); 5=node number to which force is applied; -1000=force magnitude; 0,0,1 (direction of force is in z direction)SPC1: body is fixed in all directions at these nodes (1-4, 6-9). Node 5 is free because this is where the force is applied.MAT1,30,3.E7,,0.33,2,3 $define loadsFORCE,20,5,,-1000.,0.,0.,1. $define the constraintsSPC1,10,123456,1,2,3,4,6,7,+AA1 +AA1,8,9$the end of input fileENDDATA Box SEQ Box \* ARABIC 1. Sample Nastran fileWe note that the first line of text in the Nastran file is SOL. REF _Ref195087907 \h Box 2 shows some available commands for different types of analyses. SOL Type of Analysis101Linear Statics106Nonlinear Statics129Nonlinear Transient Response153Steady Nonlinear Heat Transfer159Transient Heat Transfer600Non-Linear Static and Dynamic (implicit)601Implicit Non-Linear (Adina)701Explicit Non-Linear (Adina)Box SEQ Box \* ARABIC 2. Sample SOL definitions for various types of analysis More information regarding the construct of the Nastran file can be found in the appendix.CHAPTER 8 – Conversion of msh to Nastran The conversion of a gambit generated .msh file can be converted to a nastran file using a compiled Matlab code that was developed in our lab. The procedure for converting a gambit mech file to a nastran file is as follows:Double click on “adina_conv_quads.exe”Choose the mesh (.msh) file you want to convert. Click openSave as *.nas fileThe generated .nas file is ready to be imported into ADINA as follows. Enter the ADINA AUIClick File -> Import nastranThe code is given in the Appendix.8.1Conversion of .Msh Fie to Nastran File.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.2MATLAB code for the Conversion of .msh to Nastran File.8.2.1Conversion of .msh points to Nastran Points-38100252730(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 )) 020000(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 )) Consider the points coordinates below, to convert these coordinates to Nastran points 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 shownNote: 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 + SStep 5: Open the MATLAB application and paste the code below in the MATLAB Editor.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: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: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)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.The faces are also in groupsTo convert the faces coordinates of .msh to .nas, follow this steps: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 faceStep 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.Note: Only copy the coordinates as shown above.Step 5: Open the MATLAB application and paste the code below on the editorStep 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.Step 11: Repeat the steps for other groups on different notepad++Note: The code is given in the Appendix.Now that we have converted all the points and faces to .nas file, we need to combine the points together.8.2.3 Combining Points and Faces to Form a Nastran fileStep 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 lineStep 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.Now you have your .msh file converted to .nas file.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.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 (). 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 filerenWin.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. -63521971000Figure SEQ Figure \* ARABIC 5. A mesh extracted in VTK by applying the Delaunay TriangulationCHAPTER 10 – Raw Image FormatsDICOMFile extension: .dcm or noneIMPORTANT: 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:Tag CodeTag NameMeaning(0018, 0088)Spacing Between SlicesThe height of each pixel (voxel) in 3D space(0028, 0030)Pixel SpacingThe length and width of each pixel in 3D space(0028, 0010)RowsThe height of the DICOM image in pixels(0028,0011)ColumnsThe width of the DICOM image in pixels(0028,0004)Photometric InterpretationGives information about whether the image is grayscale or color(0020,0012)Acquisition NumberGives information about whether the image is grayscale or color(0020,0013)Instance NumberSame as aboveJPEGFile extension: .jpg or .jpegA 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.TIFFFile extension: .tif or .tiffA 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. 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. Converting TIFF to DICOM:It is frequently convenient for scientists to save their 3D imaging data in TIFF format for easy transfer and small hard drive space requirements. In order to visualize a TIFF dataset in 3D, we must convert it to a DICOM dataset. In order to do this, Grant has written a converter that works within the MatLab environment. A list of required information is listed below that will need to be gathered before the conversion can take place (note that X and Y directions correspond to the image in Figure 10.1):Name of InformationUnitsVoxel size in X directionmmVoxel size in Y directionmmVoxel Depth in Z directionmmSpacing between slices in Z directionmmWhere285753384550Y direction020000Y direction13417554760595X direction020000X direction147955495109500165735377761500Figure 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.1PNGFile extension: .pngA 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.BMPFile extension: .bmpA 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. 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. CHAPTER 11 – FLUENT Data FormatsFLUENT is a professional PDE solver software that is part of the ANSYS package. It is convenient to use with CAD structures where it can create 3D volumetric meshes from these structures and simulate such things as fluid flow and diffusion. We frequently use this software to simulate large geometries and have a need to compare the data from this software to our other data. To do this, we would like to visualize the data in our own tool (Walk-In Brain) that can visualize all of our other datasets as well. This chapter will outline what data structures FLUENT uses and outputs and what steps need to be taken in order to visualize this data in Walk-In Brain.Mesh File FormatThe FLUENT msh file format is built on similar logic to the GAMBIT format, but has some key differences that will be delineated in the following sections. The Mesh file in Fluent consists of a header, a point coordinate matrix header, a point coordinate matrix, a face matrix header, a face matrix and a zone section. Each of these is structures the same way as the GAMBIT format (refer to Chapter 3 and 4) but are in a different order.Mesh ConverterIn order for our tool to correctly read in msh files, the format must strictly follow that of Chapter 3 and Chapter 4. In order to do this, 4 steps must be taken in order to convert the FLUENT msh file into a GAMBIT msh file;Modify the headerCopy over the point coordinate matrixReorder the face matrix groups so that the exterior face groups are firstReduce the zone sectionWe 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.Step 1: Modify the HeaderThe 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.1Box 11.2(0 " Created by : Fluent_V6 Interface Vers. 14.0.3")Step 2: Reading the point coordinate matrixThe 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).Step 3: Reorder the face matrixIn 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.Step 4: Minimize the Zone SectionIn 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) ())Data File FormatFLUENT 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.Writing a Walk-In Brain Case File From FLUENTSummaryWrite ANSYS Fluent simulation data vector parameter values direct to .mm file format for loading into Walk-In-Brain. All template files are contained in folder Fluent Data Export Template. ***Copy entire folder to new directory when changing files.***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.mshStep 3:Create a list of information to be inserted into the new “mm” file following the template in Table 11.1.Table 11.1InformationDescriptionExampleNumber of cell zones# of cell zone groups in the mesh{1,2,…,n}ID number of cell zoneFluent 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 // 705B5EVariable of interest*Parameter to export for each cellpressure, species, etc..mm file nameName of file (Step 3) to write data vector to“WriteVectorFile.mm”*List of UDF specific variable syntax is in Appendix A.1Table 11.2: ANSYS Fluent Parameter Syntax ListMacro Argument Types ReturnsC_R(c,t) cell_t c, Thread *t densityC_P(c,t) cell_t c, Thread *tpressureC_U(c,t) cell_t c, Thread *tu velocityC_V(c,t) cell_t c, Thread *tv velocityC_W(c,t)cell_t c, Thread *t w velocityC_T(c,t)cell_t c, Thread *ttemperatureC_H(c,t)cell_t c, Thread *tenthalpyC_K(c,t)cell_t c, Thread *tturb. kinetic energy C_NUT(c,t)cell_t c, Thread *t turbulent viscosity forSpalart-AllmarasC_D(c,t)cell_t c, Thread *tturb. kinetic energy dissipationrateC_O(c,t)cell_t c, Thread *tspecific dissipation rateC_YI(c,t,i)cell_t c, Thread *t, int iNote: int i is species indexspecies mass fractionStep 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:Initialize the number of cell zones as Threads; line 11Initialize the variable of interest as a real variable; line 16Initialize the number of ID variables to match the number of cell zones; line 21Set each ID# to the specific Fluent specific cell zone id #; line 30Set each ID to the corresponding thread number; line 37Set name of .mm file (Step 3); line 43Set the number of total mesh cells in dec and hex format; lines 48, 49Set variable name and ANSYS UDF variable syntax for each pull loop; line 58Copy the loop ‘n’ times for the number of ‘n’ threadsIf using multiple loops change the thread number to match each cell zoneThe 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.Step 5:Compile UDF into Fluent as shown in Figure 2:Define User-defined Functions CompileIn 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\srcCreating user_nt.udf file for 3ddp ...(…multiple lines of udf specific text will be written…) Creating library libudf.lib and object libudf.expDone.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" openedwrite_vectorDone.Once UDF if loaded into Fluent it must be activated as a ‘function hook’Define User-defined Function HooksClick the ‘Edit’ available for ‘Execute at End’Select your UDF that was loaded and click ‘Add’, then OkFigure 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.References, K.: Finite Element Procedures. New Jersey, Prentice-Hall, Inc., 199Appendix I.1: Two-dimensional *.msh File consisted of triangles(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 02 5 6 d 02 6 1 8 02 1 3 7 02 3 2 6 02 2 8 5 02 8 9 a 02 9 7 3 02 7 a 4 02 a 4 1 0))(13 (5 b 1a 2 0)(2 4 b 1 22 b a 1 42 5 b 2 e2 7 b 3 42 b 9 3 c2 8 d 5 92 d 2 5 62 d 3 6 72 d 1 7 82 d 6 8 b2 8 c 9 a2 c d 9 b2 9 c a c2 c 6 b d2 b c c e2 c 5 d e))(0 "Cells:")(12 (0 1 e 0))(12 (2 1 e 1 1))(0 "Zones:")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 03 4 1 6 4 0))(13 (4 3 4 3 0)(3 3 1 4 a 03 2 1 3 b 0))(13 (5 5 6 3 0)(3 5 4 6 6 03 3 4 5 8 0))(13 (6 7 8 3 0)(3 7 6 8 2 03 5 6 7 5 0))(13 (7 9 a 3 0)(3 7 3 5 7 03 2 3 7 c 0))(13 (8 b c 3 0)(3 2 8 1 9 03 7 8 2 1 0))(13 (a d 1e 2 0)( 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)())I.3: Neutral File for two-dimensional *.msh File consisted of triangles CONTROL INFO 2.2.30** GAMBIT NEUTRAL FILEdefault_id2520PROGRAM: Gambit VERSION: 2.2.30 Jan 2008 NUMNP NELEM NGRPS NBSETS NDFCD NDFVL 18 22 1 0 2 2ENDOFSECTION NODAL COORDINATES 2.2.30 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+000ENDOFSECTION 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 18ENDOFSECTION ELEMENT GROUP 2.2.30GROUP: 1 ELEMENTS: 22 MATERIAL: 2 NFLAGS: 1 fluid 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22ENDOFSECTIONI.4: A closer look at the different types of element formats: CTRIA3, CQUAD4CTRIA3 Format The format of the CTRIA3 element entry is as follows: 12345678910CTRIA3EIDPIDG1G2G3THETA or MCIDZOFFST1T2T3Field Contents EID Element identification number. (Integer > 0) PID Property identification number of a PSHELL or PCOMP entry.(Integer > 0; Default is EID) Gi Grid point identification numbers of connection points. (Integers > 0, all unique) THETA Material property orientation angle in degrees. (Real; Default = 0.0) MCID Material coordinate system identification number. The x-axis of the material coordinate system is determined by projecting the x-axis of the MCID coordinate system (defined by the CORDij entry or zero for the basic coordinate system) onto the surface of the element. (Integer ≥ 0; if blank, then THETA = 0.0 is assumed) ZOFFS Offset from the surface of grid points to the element reference plane. (Real) Ti Membrane thickness of element at grid points G1, G2, and G3. (Real ≥ 0.0 or blank, not all zero) 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. CQUAD4 Format The format of the CQUAD4 entry is as follows: 12345678910CQUAD4EIDPIDG1G2G3G4THETA or MCIDZOFFST1T2T3T4Field 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:File Management SectionThe File Management Section is not used in general solution sequences and is optional. If the problem is large, this section is used to initialize the maximum size of database, member names, and location of file. Also this is used to perform a restart run.Example) RESTARTASSIGN,MASTER=aaa.MASTERExecutive Control SectionThis section specifies the type of analysis solution to be performed.Example) SOL 101 <=== Linear Static TypeCENDCase Control Section (CCS)The Case Control Sections defines the analysis condition with a subcase containingidentification number (ID) of boundary and load conditions specified in the Bulk DataSection (BDS) for the analysis model and the type of outputs required.Example) SUBCASE 1 <=== the first analysis conditionSPC = 10 <-----define the constraint identified as 10 in BDSLOAD = 10 <-----define the load identified as 10 in BDSDISP= ALL <-----print the displacements of all nodesSTRESS = ALL <-----print stresses of all elementsSUBCASE 2 <===the second analysis conditionSPC = 10 <-----define the constraint identified as 10 in BDSLOAD= 20 <-----define the load identified as 20 in BDSDISP= ALL <-----print the displacements of all nodesSTRESS = ALL <-----print stresses of all elementsBulk Data Section (BDS)The Bulk Data Section is mainly generated by the pre-processor and defines everything required to describe the finite element model as nodes and elements grid data, element data, several boundary conditions, load conditions, and parameters required.Example)SOL 101 ======> define the solution sequenceCEND ======> describe the end of ECSSPC=10 ======> define the constraintLOAD=20 ======> define the load conditionDISP=ALL ======> define printing displacementsBEGIN BULK ======> input geometry, loads, and the constraintsGRID,1,,0.,0.,0. ======> define nodesGRID,2,,5.,0.,0.GRID,3,,10.,0.,0.CQUAD4,1,10,1,2,5,4 ======> define elementsCQUAD4,2,10,2,3,6,5CQUAD4,3,10,4,5,8,7CQUAD4,4,10,5,6,9,8PSHELL,10,30,0.25,30 ======> define element properties (thickness : 0.25)MAT1,30,3.E7,,0.33 ======> define material propertiesFORCE,20,5,,-1000.,0.,0.,1. ======> define loadsSPC1,10,123456,1,2,3,4,6,7,+AA1 ====> define the constraints+AA1,8,9ENDDATA ======> the end of input fileMAT1 : Homogeneous, IsotropicMAT2 : Anisotropic material for two-dimensional elements, plates or shells. In-plane, transverse shear materialI.5 : VTK/Python Code for Delaunay Triangulationsimport vtk# Unstructured gridPoints = vtk.vtkPoints()Points.SetNumberOfPoints(14)Points.InsertPoint(0, 0, 0, 0)Points.InsertPoint(1, 2, 0, 0)Points.InsertPoint(2, 1.5, 0.6, 0)Points.InsertPoint(3, 3.5, 0, 0)Points.InsertPoint(4, 4.8, 0.7, 0)Points.InsertPoint(5, 6, 0, 0)Points.InsertPoint(6, 6, 1.4, 0)Points.InsertPoint(7, 5, 1.8, 0)Points.InsertPoint(8, 6, 2, 0)Points.InsertPoint(9, 4, 2, 0)Points.InsertPoint(10, 3.5, 1.1, 0)Points.InsertPoint(11, 2, 2, 0)Points.InsertPoint(12, 1.3, 1.2, 0)Points.InsertPoint(13, 0, 2, 0)strips = vtk.vtkCellArray()strips.InsertNextCell(14)strips.InsertCellPoint(0)strips.InsertCellPoint(1)strips.InsertCellPoint(2)strips.InsertCellPoint(3)strips.InsertCellPoint(4)strips.InsertCellPoint(5)strips.InsertCellPoint(6)strips.InsertCellPoint(7)strips.InsertCellPoint(8)strips.InsertCellPoint(9)strips.InsertCellPoint(10)strips.InsertCellPoint(11)strips.InsertCellPoint(12)strips.InsertCellPoint(13)polyData = vtk.vtkPolyData()polyData.SetPoints(Points)polyData.SetStrips(strips)delny = vtk.vtkDelaunay2D()delny.SetInput(polyData)delny.SetSource(polyData)deci = vtk.vtkDecimatePro()deci.SetInput(delny.GetOutput())deci.SetTargetReduction(0.0)deci.PreserveTopologyOnsmoother = vtk.vtkSmoothPolyDataFilter()smoother.SetInput(deci.GetOutput())smoother.SetNumberOfIterations(50)normals = vtk.vtkPolyDataNormals()normals.SetInput(smoother.GetOutput())normals.FlipNormalsOnmapmesh=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 wireframewriter = 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")renWin.Render()writer.Write()# Render the scene and start interaction.iren.Initialize()renWin.Render()iren.Start()Delphi converter applicationSummaryThe converter application ( REF _Ref527620988 \h Figure 6) converts from 2-point networks to spline networks and vice versa.Figure SEQ Figure \* ARABIC 6. Converter software GUI.The software can be accessed either from the converter application or from the Viewer application ( REF _Ref527621178 \h Figure 7).Figure SEQ Figure \* ARABIC 7. Accessing converter from the Viewer application.Five function tabs can be found at the top ( REF _Ref527624429 \h Figure 8):Convert NWK Files to Splines.Convert CaseFiles To Splines.Convert Splined to Even2ptmesh.Editing And Movement.CleanSplinedNW.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:DisplayNWK.SplineNWKStatistics.NWKStatistics.Figure SEQ Figure \* ARABIC 8. Main tabs in the converter.The test case file considered in this section can be found in:Share\19_ImageInventory\Converter\TestFiles\testCoW.cs31Share\19_ImageInventory\Converter\TestFiles\testCoW.nwkMain functionsConvert NWK Files to SplinesThis function converts 2-point network files (*.nwk) to spline network files (*.snwk). There is no information of the diameter of the network as there is no casefile (*.cs31). The conversion procedure is:Load network (*.nwk) using “loadButton”.Convert to spline network (*.snwk) using “convertButton”.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.Figure SEQ Figure \* ARABIC 9. Procedure to convert 2-point networks to spline networks.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.Figure SEQ Figure \* ARABIC 10. Conversion of 2-point network to spline network. Convert CaseFiles To SplinesThis 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:Load case file (*.cs31) using “loadCSButton”. The corresponding network file (*.nwk) will be loaded automatically, with the information being stored in the case file.Convert to spline case (*.cs4) and network (*.snwk) using “ConvertCase”.Save the spline case (*.cs4) and network files (*.snwk) using “saveCase”. The extensions are automatically added during the saving procedure.Figure SEQ Figure \* ARABIC 11. Procedure to convert 2-point networks to spline networks.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 ( REF _Ref527632135 \h Figure 12).Figure SEQ Figure \* ARABIC 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 SEQ Figure \* ARABIC 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.Convert Splined to Even2ptmeshThis 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: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.Load and convert case file (*.cs4) using “loadSplinedNW_Convert”. The corresponding spline network file (*.snwk) will be loaded automatically and converted.Save the 2-point case (*.cs31) and network (*.nwk) files using “save2DNWK”. The extensions are automatically added during the saving procedure.Figure SEQ Figure \* ARABIC 14. Procedure to convert spline networks to 2-point networks.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.Figure SEQ Figure \* ARABIC 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: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.Load and convert case file (*.cs4) using “convertAndReadProperty”. The corresponding spline network file (*.snwk) will be loaded automatically and converted.Save the 2-point case (*.cs31) and network (*.nwk) files using “save2DNWK”. The extensions are automatically added during the saving procedure.Figure SEQ Figure \* ARABIC 16. Procedure to convert spline network point properties to 2-point format.Figure SEQ Figure \* ARABIC 17. Conversion of spline network point property (pressure in this case) to 2-point format. Editing and MovementThis function moves the displayed image along the horizontal axis. The user needs to choose the offset factor of the original network by inserting an offset index value between -1 and 1:Insert offset index.Clicking the “toggleOffset” button. Figure SEQ Figure \* ARABIC 18. Procedure to convert 2-point networks to spline networks.The offset is performed on the original image and moves either left (negative offset) or right (positive offset). REF _Ref527626020 \h Figure 18 shows the original image and REF _Ref527625974 \h Figure 19 shows the offset with an offset index of 0.5. The original image has moved towards the right. Figure SEQ Figure \* ARABIC 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. CleanSplinedNWThis function finds and removes dangling splines in spline case and network (*.snwk) files. The finding and removing procedure is as follows:Load the case file (*.cs4) using “loadSplinedNW”. The corresponding spline network file (*.snwk) will be loaded automatically.Determine the dangling splines using “showAllDanglingSplines”. This will show a list of splines that are dangling on the “RemoveSplines” box.Remove the dangling splines by clicking the “DoIt” button next to the “RemoveSplines” box.Save the cleaned spline case (*.cs4) and network (*.snwk) files using “saveSplinedNW”. The extensions are automatically added during the saving procedure.Figure SEQ Figure \* ARABIC 20. Procedure to clean spline networks with dangling vesselsThe 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 SEQ Figure \* ARABIC 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.Additional functions for visualization and statisticsDisplayNWKThis function changes the visualization of the network display. There are five options:ToggleCylinderView – it changes visualisation from line to cylindrical view of the diameter, when the information is available.ToggleGroupview – shows the different groups.PointLabels – shows the node (vertex) indices.FaceLabels – shows the face (edge) indices.Direction – shows the direction in which the face was labelled.SplineNWKStatisticsThis function provides statistical information of the spline networks. There are four options:reportSNWKBtn – it provides information of the network.meshFileBtn – [Currently does nothing].PointMx – shows the connection between the node (vertex) indices.ptCoordMx – shows the co-ordinates of the nodes (vertices).NWKStatisticsThis function provides statistical information of the 2-point networks. There are four options:nwkLength – [Currently does nothing].BitBtn2 – [Currently does nothing].BitBtn3 – [Currently does nothing].BitBtn4 – [Currently does nothing]. Converting among mesh and stlWritten: Homa Rashidisabet 11/8/2018Edited: Grant Hartung 11/14/2018How to make a mesh for testing converterIn order to validate the conversion between STL and mesh format, a case study must be procured. The optimal choice for simplicity is a simple tetrahedron. 13335034925C00C372745-3175E00E4635534925F00FFigure SEQ Figure \* ARABIC 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: Figure SEQ Figure \* ARABIC 23. STL and mesh files comparison. (A). STL file of format for the shown geometry in Figure SEQ Figure \* ARABIC 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 SEQ Figure \* ARABIC 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. Converter from mesh to stlThe 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. REF _Ref528175710 \h 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 ( REF _Ref528175710 \h 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 REF _Ref529953826 \r \h 20.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 SEQ Figure \* ARABIC 25. 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” buttonStep 2: select the “mesh/STL converter” tab on the far rightStep 3: Load a triangulated (triangulated surface mesh or tetrahedral volumetric mesh) mesh file by selecting the “Load Triangulated Mesh” buttonStep 4: Load your mesh and observe that the display shows the mesh you expected to see: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 REF _Ref529954238 \h Figure 26. The visualization of both files are exactly the same.Figure SEQ Figure \* ARABIC 26. Visualization of converted mesh to stl and original stl in Cerebroview. (B) Converted Mesh to stl. (C) original stl.Converter from stl to mshIn 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 REF _Ref528175710 \h 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” buttonStep 2: select the “mesh/STL converter” tab on the far rightStep 3: Load an STL mesh by selecting the “Load STL” buttonStep 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:And open the new mesh file in ViewerApplication.exe for validation:Walk through of viewer application for visualizing mesh filesWe 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. Figure SEQ Figure \* ARABIC 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.Registration of two objectsThe Delphi code for writing a system of linear equations is implemented in a sparse format which is more efficient in the sense of memory allocation. In “ooXSolverSource” unit, we made a class procedure to test and scrutinize how Delphi code has been programed for writing equations and solving them. In linear system of Ax=b, we write A matrix and b vector in a sparse format which means we omit all zeroed coefficient variables and zeroed values of right-hand-side. Furthermore, we might have different subset variables which can be stored in different vectors, but at the end before solving the equations, we make a global variable that is made by concatenation of all subset variables. Having all variables in one global variable makes programing easier because indexing of variables will become easier.As we showed previously in image registration report, alignment of two object can be considered as solving a system of equations. Thus, this case study is for aligning two misaligned identical 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 REF _Ref525756331 \h Error! Reference source not found. Table SEQ Table \* ARABIC 1. Coordinates of points on both cubes used for alignment.COW 1COW 2XYZXYZ1.8900 0.1080-0.0117-0.0540-0.0039 -0.09851.8500 -0.0758 -0.01880.0379 -0.0063 -0.08791.8900 0.0094-0.0018-0.0047 -0.0006 -0.09741.4000 0.0005 -0.2640-0.0002 -0.0881 0.0254R= -0.1089-2.0009-0.0012.362-0.0063.004-2.302-0.0040.006, t= 1.6600( SEQ Equation \* ARABIC 1)rmax=0 , rnorm=0( SEQ Equation \* ARABIC 2)Walk through of viewer application for visualizing mesh files In Figure 21, we show step by step guidance of how we can use the registration application code, “RegistrationApplication.pas”. The coordinates for the object 1 and object 2 is given in table 2. Figure SEQ Figure \* ARABIC 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. Figure SEQ Figure \* ARABIC 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.Documentation of ICEM/GAMBIT mesh converter. Written: Grant Hartung 11/14/2018Sometimes 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):Converting ICEM mesh file to GAMBIT mesh file:The following walkthrough is explained using a test case named M1V3.icem.msh (an ICEM mesh generated in ICEM) located in S:\__temp\Converter\. This mesh can be visualized in ICEM as in REF _Ref529957068 \h Figure 31 and converted using the converter in the ViewerApplication_updatedConverter.exe located in Z:\__temp\Converter\ or is available by Grant.Figure SEQ Figure \* ARABIC 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” buttonStep 2: select the “ICEM GAMBIT Mesh Converter” tabStep 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:Step 5: Validate that the new mesh file is the same as the original mesh file by loading it in ViewerApplication.exe:Instructions for converting from GAMBIT to ICEM:Any GAMBIT mesh can be converted to ICEM-compatible mesh using the converter in the ViewerApplication_updatedConverter.exe located in Z:\__temp\Converter\ or is available by Grant. Note, the new ICEM mesh must be loaded into ICEM using “ImportMeshfromFluent”. If nothing appears on screen, click off and on the checkboxes for each part of the mesh to reveal the loaded mesh.Figure SEQ Figure \* ARABIC 33. Visualization of the GAMBIT file generated using the converter in Section REF _Ref529871782 \r \h 20.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” buttonStep 2: select the “ICEM GAMBIT Mesh Converter” tabStep 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:Step 5: Save the mesh in ICEM format by selecting “Save as ICEM mesh” buttonStep 6: Validate that the ICEM mesh loads and looks correct in the ICEM program:Figure SEQ Figure \* ARABIC 34. 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.Documentation of Delphi “.cs31” and “.casx” converter.Written: Grant Hartung 11/14/2018All 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 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.Converting .cs31 file to .casx file:This walkthrough will be exemplified by a case study entitled au.1.tortuous.cs31 and au.1.tortuous.nwk located in S:\__temp\Converter. It is worth noting at this point that the .casx file convention does not preserve the group affiliation originally stored in the .cs31 file structure.Figure SEQ Figure \* ARABIC 35. 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” buttonStep 2: select the “ICEM GAMBIT Mesh Converter” tabStep 3: Open a case file (.cs31) using the “LoadCaseFile” button:Step 4: Select an appropriate case file and verify the visualization matches the expectated network: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 6: Choose a suitable file name to save the file as:Step 7: Open the new casX file to validate that the file has the correct date: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:Step 8: Validate the visualization of the .casx network by clearing the form:And opening the casx file by selecting “Choose .casx file” button”And then by reviewing the visualization of the network:Instructions for converting from .casx to .cs31:Step 1: Launch the Viewer Application and select the “Converter” buttonStep 2: select the “ICEM GAMBIT Mesh Converter” tabStep 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: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: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.Figure SEQ Figure \* ARABIC 39: Main workflow of the Matlab codeThe code was used for .casx and .cas files of two simple bifurcations and a simplified structure of the arteries and veins fused. ABFigure SEQ Figure \* ARABIC 40: (A) Arteries and vein fused structure (B) Simple bifurcationThe 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 SEQ Figure \* ARABIC 41: Matlab compiler used to convert an .m file into a stand-alone executableBy 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 SEQ Figure \* ARABIC 42: Running the stand-alone executable from the command promptAppendix A: Points_Converter: (Conversion of .Msh Fie to Nastran File.)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;endfclose(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);endfclose(f);Face_Converter:clear all; close all; clc;fileID =fopen('Sample 7_Faces.txt','r'); j = 1;while ~feof(fileID) line = fgetl(fileID); faceMx(j,:) = sscanf(line, '%x %x %x %x %x'); j = j+1;endfclose(fileID);a = faceMx(:,1);b = faceMx(:,2);c = faceMx(:,3);d = faceMx(:,4);e = faceMx(:,5);% g = faceMx(:,6);% h = faceMx(:,7); 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)); point=sprintf('CTRIA3,%d,7,%d,%d,%d\n',j+(Start_Connection_Number-1),a(j),b(j),c(j)); fwrite(f,point);endfclose(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'); %% Get network information nwk = casxRead([pathname filename]); %% Plot NetworkcasxVisualizer(nwk.ptCoord,nwk.faceMx,nwk.Dia,labelChoice)endfunction nwk = casxRead(filename)fid = fopen(filename); %% Reads through filenone = 0;pointMx = 1;faceMx = 2;dia = 3;flow = 4; 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 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 endend trynwk.Dia = myDiameter; nwk.ptCoord=myPtCoord; nwk.faceMx=myFaceMx; nwk.flowVec=myFlow;catchendfclose(fid);endfunction casxVisualizer(ptCoordMx,faceMx,diaVec,labelChoice)figure; %Plot points,faces scaled by diasz=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; if(labelChoice == 1) %Labels on or off disp('With Labels') %Plot points labels for i = 1:size(ptCoordMx,1) x = ptCoordMx(i,1)+0.8; y = ptCoordMx(i,2)+0.01; z = ptCoordMx(i,3); str = ['P',num2str(i)]; text(x,y,z,str,'Fontsize',8.5);hold on; end else disp('No Labels') endset(gcf,'color','w');endAppendix B: Stl to msh converter code in Delphi:// Homai 10/19/2018unit ooSTLtoMeshConverter;interfaceuses SysUtils, Dialogs, Classes, Math, StrUtils,Variants, Windows, psAPI, ooRoot, SAEInterfaces, ooTubeMeshSource, ooUtilities.V2, ooCaseFileReaderSource, ooGambitWriterSource, ooSplinedTubeSource;type STLReader = class (TObject) NFaces, NPoints: integer; LinesInFile: TStringList; 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;implementationprocedure STLReader.loadSTLFile(aSTLFileName:String); //constructor ooCaseFileReader.Createvar s,localmeshFileName, FileName: string; STLLoaded: boolean;begin LinesInFile := TStringList.Create; if not FileExists(aSTLFileName) then begin ShowMessage('The selected STL file: ' + aSTLFileName + ' does not exist. Please check *.stl file'); STLLoaded := false; exit; end else STLLoaded := true; LinesInFile.LoadFromFile(aSTLFileName);end;// dervied from basic cleanfunction STLReader.clean(aLine:String):string;begin aLine := StringReplace(aLine, 'vertex', '',[rfReplaceAll]); result := aLine;end;procedure STLReader.addPoint(var ptCoordMx: PDblMatrix;aP: PDblArray);var oldNPoints,dimensions: integer;begin oldNPoints := length(ptCoordMX)-1; // the zero-th element is not used NPoints := oldNPoints+1; dimensions := 3; SetLength(ptCoordMx, NPoints+1, dimensions); // on bigger than NPoints CopyVectorContent(PDblArray(ptCoordMx[NPoints]), aP);end;function STLReader.addPtAtNewOrExistingIdx(var aPtCoordMx: PDblMatrix;p1: PDblArray):integer;var Idx: integer; aP: PDblArray; begin result := -1; // loop over the pointCoordMatrix for Idx:= 1 to NPoints do begin aP := PdblArray(aPtCoordMx[Idx]); if IsIdentical(p1, aP) then begin result := Idx; exit; end; end; // if points is not in aPtCoordMx then add it to the pointCoordMx and return new Idx if result = -1 then begin // add point at the end of the mesh addPoint(aPtCoordMx,P1); result := NPoints; // the new index; end;end;constructor STLReader.createfromSTLFiletoMesh(aSTLFileName: string);var n, p1Idx, p2idx, p3Idx, iFacetLineIdx, grpID: integer;ptCoordMx:PdblMatrix; p1,p2,p3,coordinate:pdblArray; faceMx: PIntMatrix;aLine:string;begin NPoints := 0; setlength(ptCoordMx,1,3); //dimentions setlength(faceMx,2, 6); grpId := 10000; //name eof the group loadSTLFile(aSTLFileName); 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;class procedure STLReader.test();var fileName:string;beginfileName:='C:\andi\MG.V1\PurePascalMGV88.1\Data\HomaiData\Cube_10_10_10HR.stl';//fileName:='C:\andi\MG.V1\PurePascalMGV88.1\Data\HomaiData\IGICEM.stl';//fileName:='C:\Users\Homa\Desktop\IG_vmtk_davidResults\UIC2012-1070_SubjectIV_COWmeshV2.stl'; //STLCreator(fileName); //open(fileName); //STLtoMesh(fileName); STLReader.createfromSTLFiletoMesh(fileName);end;{ STLReader }begin STLReader.test();end.Appendix B: msh to stl converter code in Delphi:// Homai 10/19/2018// based on linearVascularTest by Lin// Lin 8/21/2013// Lin 1/3/2017 --- updated for compatibility with libraries// Lin&GH 1/9/2017 -- visualizationunit HomaiMeshSTLConverter;interfaceuses SysUtils, Dialogs, Classes, Math, StrUtils,Variants, Windows, psAPI, {ooRoot,} SAEInterfaces, ooTubeMeshSource, ooUtilities.V2, ooCaseFileReaderSource,ooRoot;procedure STLwriterFromMesh();//function Add(const S: string): Integer;//function AddObject(const S: string; AObject: TObject): Integer; override;implementation{function TStringList.Add(const S: string): Integer;begin Result := AddObject(S, nil);end;function TStrings.AddObject(const S: string; AObject: TObject): Integer;begin Result := Add(S); PutObject(Result, AObject);end; }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]]); 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.Appendix C: Registration application code.// Lin 10/15/2018// Interfaces for the 3d Registration application to show to Homa// use 4 pts in Object1 and 4 pts in Object2 to solve for the transformation matrix//unit ooRegistrationApplicationSource;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, StdCtrls, Buttons, ooRoot, ooGLPanelSimpleByAL, ooGLPanelWithButtons, ooRendererSource, SAEInterfaces, ooUtilities.V2, ooCaseFileReaderSource,ooXSolverSource;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; 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}procedure TRegistrationForm.FormCreate(Sender: TObject);begin myGLPanel := TGLPanelSimple.CreateOnExistingForm(Panel1);end;procedure TRegistrationForm.BitBtn1Click(Sender: TObject);var aR1, aR2, aR3, aR4: PDblArray; n,i: integer;begin Setlength(ptsObj1,4,3);Setlength(ptsObj2,4,3); for i:= 0 to 3 do begin PdblArray(ptsObj1[i]) := ooCaseFileReader.parseLineForDouble(memo1.Lines[i], n); PdblArray(ptsObj2[i]) := ooCaseFileReader.parseLineForDouble(memo2.Lines[i], n); end; testViews(); //testviewsHardCoded;end;function TRegistrationForm.VectorToSquerMatrix(A:PdblArray;n:integer):PdblMatrix;var i,j,u:integer; B:Pdblmatrix;begin 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;procedure TRegistrationForm.transFormObject(JJ:PDblMatrix; b: PDblArray);var i,n: integer; pt:PDblArray; InsertedPts:integer; ptsObj1:pdblArray; Obj1Coord:Tstringlist;begin InsertedPts:=4; n:=4; /// both numbers should change from hsrdcode to global vars //HR--10/29/2018 setlength(ptsObj1,3); Obj1Coord:= TStringlist.create; Obj1Coord.addStrings(Memo1.lines); for i:= 1 to InsertedPts do begin //PdblArray(ptsObj1[1]) := ooCaseFileReader.parseLineForDouble(memo1.Lines[1], n); //pt := PdblArray(ptsObj1[1]); pt:= parseLineForDouble(Obj1Coord[i]); pt := AAx(JJ,pt); ptsObj1 := plus(pt, b); memo5.lines.addStrings(printvectorAsStringList(ptsObj1)); end;end;function TRegistrationForm.MatrixMultiplication(A,B:PDblMatrix):PdblMatrix;var i,j,k:integer; sum:double;beginsum:=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;{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;procedure TRegistrationForm.SpeedButton1Click(Sender: TObject);var Obj1Coord,Obj2Coord:TStringlist; p1,p2,p3,p4,pprim1,pprim2,pprim3,pprim4,b,OffsetVec:PdblArray; transformationMx,projectedOBj2,transposeObj2: PdblMatrix;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.Appendix D: Code for saving the case file as a .casx file This is a callback code for a button onClick on a form. The method uses a global parameter (mesh) that has been previously instantiated. The writer creates the .casx file using the aCaseFileName parameter. The saveToFile procedure saves the .casx file to the hard drive. The aCaseFileName parameter must be a full file name including path. This procedure requires the following procedures (currently located in ghCaseFileUtilities.pas). The findDataInFile function returns a boolean true if data is found in the case file and false if there is only a diameter vector. In this way, the method is robust; in the event that a case file does not have data, the procedure just writes the file as is (with diameter vector only). The data is written using the writeVectorProperty procedure.procedure TForm2.Button2Click(Sender: TObject);var minimalistCaseFileWriter:ghCaseXFileWriter; aPropNameList:TSTringList; aPropMx:PDblMatrix; i:integer;beginminimalistCaseFileWriter := ghCaseXFileWriter.create(aCaseFileName,mesh.dia,mesh);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 fileThis 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: function findDataInFileWithDiameter(aCaseFileName:string; nwk:ooTubeMesh; var aPropNameList:TSTringList; var aPropValueVector:PDblMatrix):boolean; procedure findPropertyVectors(linesInFile:TSTringList; var aPropNameList:TStringList); procedure fillDataVectorsFromFile(aCaseFileR:ooCaseFileReader; aPropNameList:TSTringList; var aPropValueVector:PDblMatrix; groupMx:PIntMatrix);Implementation:findDataInFile(aCaseFileName:string; nwk:ooTubeMesh; var aPropNameList:TSTringList; var aPropValueVector:PDblMatrix):boolean;var i:integer; aCaseFileR: ooCaseFileReader; aTempList:TstringList;begin aCaseFileR := ooCaseFileReader.Create(aCaseFileName); aTempList := TSTringList.Create; findPropertyVectors(aCaseFileR.linesInFile, aTempList); setLength(aPropValueVector,aTempList.Count, nwk.NFaces+1); fillDataVectorsFromFile(aCaseFileR,aTempList,aPropValueVector,nwk.groupMx); 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;procedure findPropertyVectors(linesInFile:TSTringList; var aPropNameList:TStringList);var i,n:integer; key,aLine,aPropName:string; aStrL:TStringList;begin 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;procedure fillDataVectorsFromFile(aCaseFileR:ooCaseFileReader; aPropNameList:TSTringList; var aPropValueVector:PDblMatrix; groupMx:PIntMatrix);var i:integer;begin for i := 0 to aPropNameList.Count-1 do begin //first set is always diameter aCaseFileR.getTubeVectorPropertyForGroups(aPropNameList[i],PDblArray(aPropValueVector[i]),groupMx); aPropValueVector[i,0] := aPropValueVector[i,1]; //for visualization, never let 1st index be 0, it affects range end;end;Appendix F: Code for reading a casx fileThis is a callback code for a button onClick on a form. The method creates a local case file reader of type ghCaseXFileReader. This reader creates a mesh inside itself. The global parameter (mesh) that is of type ooTubeMesh is then assigned to the mesh within the ghCaseXFileReader. procedure TForm2.Button3Click(Sender: TObject);var minimalistCaseFileReader:ghCaseXFileReader; aR:ooTubeRenderer; aPanel:TGLPanelWithButton;begin OpenDialog1.Title := 'Open a Vasculature Network File....'; OpenDialog1.Filter := 'Case Files|*.*'; if OpenDialog1.Execute then begin aCaseFileName := OpenDialog1.Filename; minimalistCaseFileReader := ghCaseXFileReader.create(aCaseFileName); mesh := minimalistCaseFileReader.mesh; end;end;Appendix G:Code for writing and reading a .casx fileThis is a standalone class that includes both the ghCaseXFileWriter and ghCaseXFileReader object definitions and implementations. Both objects include the same parameters; a caseFileName (string), linesInFile (TStringList), and a mesh (ooTubeMesh). These parameters are global and can be accessed by the user outside of the class. //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 fileunit ghCaseXFileSource;interfaceuses 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'; ptCoordHeader = 'point coordinates'; connectivityHeader = 'arc connectivity matrix'; vectorHeaderFaces = ': vector on arc;'; vectorHeaderPoints = ': vector on arc;'; commentConstant = '//'; endSectionConstant = '//end '; 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; 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;implementationconstructor 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;//minimalist writer ////////////////////////////////////////////Create procedure allows you to create, then add more vectors on the fly, then saveToFile//for this, use (1) Create, (2) writeVectorProperty, (3) saveToFileconstructor ghCaseXFileWriter.create(aCaseFileName:String; aDvector: PDblArray; aMesh: ooTubeMesh; anExt:string=caseFileExt);begin LinesInFile := TStringList.create; caseFileName := stringReplace(aCaseFileName,caseFileExt,'',[rfReplaceAll]); caseFileName := stringReplace(aCaseFileName,nwkExt,'',[rfReplaceAll]); caseFileName := aCaseFileName+ghMinimalistCaseFileExt; mesh := aMesh; writeHeader; addPointSection; addFaceSections; writeVectorProperty('diameter',mesh.dia);end;procedure ghCaseXFileWriter.saveToFile;begin saveToFileFromSTringList(linesInFile,caseFileName); end; //use method from ghCaseFileUtilities to save to fileprocedure ghCaseXFileWriter.writeHeader;var nwkFileNameWithoutPath: string;begin LinesInFile.add(commentConstant+modelHeader); LinesInFile.add(commentConstant+authorString); LinesInFile.add(commentConstant+dateString+DateToStr(Now)); LinesInFile.add(commentConstant+copyrightString); LinesInFile.add(commentConstant+instructionString); LinesInFile.add(commentConstant+NoteString); LinesInFile.add(GambitBlank);end;procedure ghCaseXFileWriter.writeVectorProperty(propName: string; anArray: PDblArray);var Header, aLine: string; iGrp, iFace, groupIdx, N: integer;begin if high(anArray) = mesh.NFaces then LinesInFile.add(commentConstant+propName+vectorHeaderFaces+' nArcs='+intToStr(mesh.NFaces)) else if high(anArray) = mesh.NPoints then LinesInFile.add(commentConstant+propName+vectorHeaderPoints+' nPoints='+intToStr(mesh.nPoints)) else showMessage('length of vector does not match points or faces'); for iFace := 1 to high(anArray) do begin aLine := FloatToStr(anArray[iFace]); LinesInFile.add(aLine); end; LinesInFile.add(endSectionConstant+propName); LinesInFile.add(GambitBlank); 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); LinesInFile.add(GambitBlank);end; //only use ptIdx in minimalist methodfunction ghCaseXFileWriter.writeFace(aFaceInfo: PIntArray):string;var i:integer;aLine:string;begin for i:= 1 to 2 do aLine := aLine + Format('%s ', [IntToHexStr(aFaceInfo[i])]); result := aLine; end;///////////////////////////////////////////////////////////minimalist reader //////////////////////////////////////////constructor ghCaseXFileReader.Create(matrixFileName:string);var idxPtMxStart,idxFaceMxStart,idxDiaVectorStart,idxDiaVectorEnd,idxPtMxEnd,idxFaceMxEnd:integer; tempMesh:ghTubeMesh;begin caseFileName := matrixFileName; tempMesh := ghTubeMesh.createWithSize1;// need to create mesh here mesh := ooTubeMesh(tempMesh); linesInFile := TStringList.create; linesInFile.LoadFromFile(caseFileName); idxPtMxStart := LinesInFile.IndexOf(commentConstant+ptCoordHeader)+1; idxPtMxEnd := LinesInFile.IndexOf(endSectionConstant+ptCoordHeader)-1; idxFaceMxStart := LinesInFile.IndexOf(commentConstant+connectivityHeader)+1; idxFaceMxEnd := LinesInFile.IndexOf(endSectionConstant+connectivityHeader)-1; idxDiaVectorStart := LinesInFile.IndexOf(commentConstant+vectorHeaderFaces+'diameter')+1; idxDiaVectorEnd := LinesInFile.IndexOf(endSectionConstant+'diameter')-1; readPointCoordinates(mesh.ptCoordMx,idxPtMxStart,idxPtMxEnd); readFaceMatrix(mesh.faceMx,idxFaceMxStart,idxFaceMxEnd); readVector(mesh.dia,idxDiaVectorStart,idxDiaVectorEnd); setLength(mesh.pointMx,mesh.NPoints +1, maxPointCol); mesh.makeGroupMxFromFaceMx; mesh.makeTubeConnections(mesh.faceMx,mesh.pointMx);end;procedure ghCaseXFileReader.readPointCoordinates(var ptCoordMx: PDblMatrix; startIdx,endIdx:integer);var iFace,i,j, toIdx, fromIdx:integer; faceInfo: PIntArray; aLine:string; isBoundary: boolean;SectionIdx: integer;begin iFace := 1; setLength(ptCoordMx,endIdx-startIdx+2,3); for i := startIdx to endIdx do begin copyVectorContent(pDblArray(ptCoordMx[iFace]),parseLineForDoublesNew(LinesInFile[i])); iFace := iFace + 1; end; mesh.NPoints := iFace-1;end;procedure ghCaseXFileReader.readFaceMatrix(var faceMx: PIntMatrix; startIdx,endIdx:integer);var iFace,i,j, toIdx, fromIdx:integer; faceInfo: PIntArray; aLine:string; isBoundary: boolean;SectionIdx: integer;begin iFace := 1; setLength(faceMx,endIdx-startIdx+2,5); for i := startIdx to endIdx do begin 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;procedure ghCaseXFileReader.readVector(var aVec:PDblArray; startIdx,endIdx:integer);var iFace,i,j, toIdx, fromIdx:integer; faceInfo: PIntArray; aLine:string; isBoundary: boolean;SectionIdx: integer;begin setLength(aVec,endIdx-startIdx+2); iFace := 1; for i := startIdx to endIdx do begin aVec[iFace] := strToFloat(LinesInFile[i]); iFace := iFace + 1; end;end;function ghCaseXFileReader.parseLineForIntegersNew(aLine:string): PIntArray;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 result[i] := StrToInt('$'+ aStrL[i]); aStrl.destroy;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.Appendix H: Calling the icem mesh file readerThis 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).procedure TForm2.Button1Click(Sender: TObject);var aR:ooRenderer;beginOpenDialog1.Title := 'Select an ANSYS Volumetric Mesh file in ASCII Format...';OpenDialog1.filter := 'MSH files|*.msh'; if OpenDialog1.execute then begin aMeshFileName := openDialog1.filename; memo1.Lines.clear(); memo1.Lines.Add('You have selected meshFile'+aMeshFileName); aAR := ooANSYSReader.createFlat(aMeshFileName); mesh := aAR.mesh; SetLength(aMeshFileName, length(aMeshFileName)-3); aMeshFileName := aMeshFileName + 'GAMBIT.msh'; memo1.Lines.Add('Mesh File is Loaded'); //aR := ooMesRenderer.Create(); end;end;Appendix G: Calling the ICEM writerprocedure TForm2.Button6Click(Sender: TObject);var aW:ooANSYSwriter;begin aW := ooANSYSwriter.CreateAndSave(aMeshFileName,mesh);end;Appendix H: ICEM reader/writer source codeThis 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 formatunit ghANSYSMeshFileSource;interfaceuses WinTypes, WinProcs,Stdctrls,Classes,ExtCtrls,SysUtils, Dialogs, Controls, Forms, IDGlobal, ooUtilities, strUtils, ooRoot,SAEinterfaces, ooGambitConstants;procedure __readMeshFromANSYSFileIntoLists(aFileName:string; var ptCoordMx: PDblMatrix; var faceMx, groupMx:PIntMatrix);constANSYSDim = '(0 " Created by : FLUENT'; //GH 10/31/2018 -- shortenedANSYSFaces = '(13 (0'; //GH 10/31/2018 -- updated, ansys switchis this tag all the timeANSYSBoundaryFaces = '(0 "Faces of zone PART.1")';ANSYSZones = '(0 "Zone Sections")';ANSYSPtBegin = '(10 ('; // beginning of points BlockANSYSCellBegin = '(12 ('; // beginning of Cell BlockANSYSFaceBegin = '(13 ('; // beginning of face block//GH -- for writerANSYSHeader = '(0 " Created by : Fluent_V6 Interface Vers. 14.0.3")';ANSYSDimensions = '(2 3)';ANSYSPointHeader = '(0 "Node Section")';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 constructor createFlat(Fname: String); function readPointSectionHeader(var nrPoints, fromIdx, toIdx, dimensions: integer): integer; function findLineContainingKey(aKey:string):integer; function findStringBetweenLines(idx1,idx2:integer;aString:string):integer; function Clean(var aLine: string): string; procedure readPointCoordinates(var ptCoordMx:PDblMatrix;dimensions, fromIdx, toIdx:integer); virtual; function parseLineForDoublesNew(aLine:string):PDblArray; procedure readFaceMatrixAndGroups(var faceMx,aGrMx:PIntMatrix); virtual; function readGlobalFaceSectionHeader(var nrFaces, nrOfPointsPerFace: integer): integer; function readFaceSectionFlat(var faceMx: PIntMatrix; startIdx: integer; var endIdx, iFace: integer; var aGrMx: PIntMatrix): boolean; class procedure StoreSectionInGroupMX(var aGM: PIntMatrix; aFaceHeader: PIntArray); function parseForNrOfVolumes: integer; function getIndexFromHeader(lineIndex, headerIndex: integer): integer; 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;implementationvar aAR: ooANSYSReader;///////////////////////////////////// reader //////////////////////////////////////////////////constructor ooANSYSReader.createFlat(Fname:String);var str:string; dimensions: integer;fromIdx, toIdx, pointIdx:integer;begin LinesInFile := TStringList.create; 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 linefunction 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.readPointSectionHeader(var nrPoints,fromIdx,toIdx, dimensions: integer):integer;var idx:integer;aLine:string;ptArray: PIntArray;begin //Find First Point Block idx := findStringBetweenLines(IdxS1, IdxS2, ANSYSPtBegin); aLine := LinesInFile[idx+1]; // skip a line ptArray := parseLineForIntegersNew(Clean(aLine)); fromIdx := idx + 2 + ptArray[1]; toIdx := idx + 2 + ptArray[2]; dimensions := ptArray[4]; // 2 means 2d points coordinates (x,y), 3 means 3d point coordinates (x,y,z) // Lin 1/4/2008 nrPoints := toIdx-fromIdx+1;end;function ooANSYSReader.findStringBetweenLines(idx1,idx2:integer;aString:string):integer;var i:integer;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.Clean(var aLine:string):string;var pos1, pos2:integer; s: string;begin aLine := StringReplace(aLine, ANSYSPtBegin, '',[rfReplaceAll]); aLine := StringReplace(aLine, ANSYSFaceBegin, '',[rfReplaceAll]); aLine := StringReplace(aLine, ANSYSCellBegin, '',[rfReplaceAll]); aLine := StringReplace(aLine, ')', '',[rfReplaceAll]); aLine := StringReplace(aLine, '(', '',[rfReplaceAll]); result := aLine;end;procedure ooANSYSReader.readPointCoordinates(var ptCoordMx:PDblMatrix; dimensions, fromIdx, toIdx:integer);var i,j, pointIdx:integer; aPtCoordArray: PDblArray;begin pointIdx := 1; for i := fromIdx to toIdx do begin aPtCoordArray := parseLineForDoublesNew(LinesInFile[i]); for j := 0 to dimensions-1 do begin ptCoordMx[pointIdx, j] := aPtCoordArray[j];end; pointIdx := pointIdx+1; end;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;procedure ooANSYSReader.readFaceMatrixAndGroups(var faceMx,aGrMx:PIntMatrix);var fromIdx, toIdx,iFace:integer; isBoundary:boolean; nrOfPointsPerFace: integer;grpCount: integer;begin fromIdx := readGlobalFaceSectionHeader(mesh.NFaces, nrOfPointsPerFace); // total number of Faces allocateFaceMx(nrOfPointsPerFace); // Read 2Pt faceMx or 3Pt faceMx SetLength(tempFMx, length(faceMx), length(faceMx[0])); iFace := 1; // write into first row of matrix grpCount := 0; 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/12end;procedure ooANSYSReader.arrangeFaceMx(var tempFMx, faceMx: PIntMatrix);var faceCount, grpIdx, iFace: integer;begin faceCount := 1; for grpIdx := low(bArray) to high(bArray) do if bArray[grpIdx] = True then addSectionToFaceMx(tempFMx, faceMx, grpIdx, faceCount); for grpIdx := low(bArray) to high(bArray) do if bArray[grpIdx] = False then addSectionToFaceMx(tempFMx, faceMx, grpIdx, faceCount);end;procedure ooANSYSReader.addSectionToFaceMx(var tempFMx, faceMx: PIntMatrix; var grpIdx, faceCount: integer);var iFace: integer;begin for iFace := mesh.groupMx[grpIdx,_b] to mesh.groupMx[grpIdx,_e] do begin faceMx[faceCount] := tempFMx[iFace]; faceCount := faceCount +1; end;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 facesend;function ooANSYSReader.readGlobalFaceSectionHeader(var nrFaces, nrOfPointsPerFace: integer):integer;var aLine:string;ptArray: PIntArray;begin nrFaces := getIndexFromHeader(IdxS2, 2); //GH 10/31/2018 -- to read the correct line nrOfPointsPerFace := getIndexFromHeader(IdxS2+2, 4); //GH 10/31/2018 result := IdxS2+2; //GH 10/31/2018end;function ooANSYSReader.getIndexFromHeader(lineIndex, headerIndex:integer):integer;var aLine:string;ptArray: PIntArray;begin aLine := LinesInFile[lineIndex]; ptArray := parseLineForIntegersNew(Clean(aLine)); result := ptArray[headerIndex];end;function ooANSYSReader.readFaceSectionFlat(var faceMx: PIntMatrix;startIdx:integer; var endIdx, iFace: integer; var aGrMx: PIntMatrix):boolean;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]; updateFaceInfo(faceInfo, iFace); //update faceInfo for writing groupMx accordingly 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(LinesInFile[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 faceMx[iFace,_GroupID]:=sectionIdx; iFace := iFace + 1; end; endIdx := toIdx + 4; // push to new face and include two linefeeds for ');)' and headerend;procedure ooANSYSReader.makeGroupMxFromFaceMx(var aGroupMx,aFaceMx:PIntMatrix);var cGrp, pGrp: TGroupIdx; iFace: TFaceIdx; bi, ei: integer;faceInfo:PintArray;begin aGroupMx := nil; SetLength(aGroupMx , maxGroupRow, maxGroupCol); bi := 1; pGrp := aFaceMx[1,_GroupId]; // first section Setlength(faceInfo,5); for iFace := 1 to high(aFaceMx) do begin cGrp := aFaceMx[iFace,_GroupId]; if cGrp <> pGrp then begin // this is the end of a section // store grp indices ei := iFace -1; faceInfo[_GroupID]:= pGrp; faceInfo[_b]:= bi; faceInfo[_e]:= ei; StoreSectionInGroupMX(aGroupMx,faceInfo); // start new grp bi := iFace; pGrp := cGrp; end; end; // write last group ei := iFace -1; faceInfo[_GroupID]:= pGrp; faceInfo[_b]:= bi; faceInfo[_e]:= ei; StoreSectionInGroupMX(aGroupMx,faceInfo);end;procedure ooANSYSReader.updateFaceInfo(var faceInfo: PIntArray; iFace: integer);begin faceInfo[2] := faceInfo[2] - faceInfo[1] +iFace; faceInfo[1] := iFace;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 headerend;class procedure ooANSYSReader.StoreSectionInGroupMX(var aGM: PIntMatrix;aFaceHeader: PIntArray);var i:integer;begin for i:= low(aGM) to high(aGM) do begin if aGM[i,_GroupID] = 0 then begin aGM[i,_GroupID] := aFaceHeader[_groupId]; aGM[i,_b] := aFaceHeader[_b]; aGM[i,_e] := aFaceHeader[_e]; aGM[i,_i1] := aFaceHeader[_i1]; aGM[i,_i2] := aFaceHeader[_i2]; exit; end; end;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 deadlinefunction 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;procedure ooANSYSReader.swapBoundaryFaceValues(anArray: PIntArray);var anIndex: integer;begin if anArray[4] = 0 then exit; if anArray[3] = 0 then begin anIndex := anArray[1]; anArray[1] := anArray[2]; anArray[2]:= anIndex; // swap point indixes anIndex := anArray[3]; anArray[3] := anArray[4]; anArray[4]:= anIndex; // swap volume indices end;end;///////////////////////////////////// end reader /////////////////////////////////////////////////////////////////////////////////////// writer //////////////////////////////////////////////////constructor ooANSYSwriter.createAndSave(aMeshFileName:String; aMesh: ooMesh);begin LinesInFile := TStringList.create; 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 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;function ooANSYSwriter.writeFace(aFaceInfo: PIntArray):string;var i:integer;aLine:string;begin if length(aFaceInfo) = 5 then begin aLine := ''; // 2Pt faces if aFaceInfo[_v2Idx] > mesh.iNVolumes then aFaceInfo[_v2Idx] := 0; end; if length(aFaceInfo) = 6 then begin aLine := ''; // 3Pt faces //IGG 8/9/12 bNVolumes must be written to msh file as zeros! if aFaceInfo[_v3Idx] > mesh.iNVolumes then aFaceInfo[_v3Idx] := 0; end; if length(aFaceInfo) = 7 then begin aLine := ''; // 4Pt faces //IGG 8/9/12 bNVolumes must be written to msh file as zeros! if aFaceInfo[6] > mesh.iNVolumes then aFaceInfo[6] := 0; end; for i:= 1 to high(aFaceInfo) do begin aLine := aLine + Format('%s ', [IntToHexStr(aFaceInfo[i])]); end; result := aLine;end;//GH -- this procedure assumes the boundary faces come first//Sections of file: 1->points, volumes, 3+ ->facesprocedure ooANSYSwriter.addZoneSection;var aLine:string; i,j:integer;begin mesh.iNFaces := mesh.nFaces - mesh.bNFaces; aLine := '(0 "Zone Sections")'; LinesInFile.add(aLine); LinesInFile.add('(39 (' + IntToHexStr(2) + ' fluid 2)())'); for i := 2 to sectionCounter do begin if (mesh.groupMx[i-2,2] <= mesh.bNFaces) then 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 //////////////////////////////////////////////////// a method that creates a mesh objectconstructor ghMesh.createWithSize1;var i:integer;begin NPoints := 1; nFaces := 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 __readMeshFromANSYSFileIntoLists(aFileName:string; var ptCoordmx: PDblMatrix; var faceMx,groupMx:PIntMatrix);begin aAr := ooANSYSReader.createFlat(aFileName); end;//ripped from ooGambitWriterSourcefunction IntToHexStr(i:integer):string;begin result := IntTohex(i,1);end;function parseLineForIntegersNew(aLine:string): PIntArray;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 result[i] := StrToInt('$'+ aStrL[i]); aStrl.destroy;end;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.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 fileaGambitWriter := 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)procedure TForm2.Button5Click(Sender: TObject);beginOpenDialog1.Title := 'Select an ANSYS Volumetric Mesh file in ASCII Format...';OpenDialog1.filter := 'MSH files|*.msh'; if OpenDialog1.execute then begin aMeshFileName := openDialog1.filename; mesh := ooMesh.Create(aMeshFileName); end;end;Appendix J: Code for creating tube mesh from file (already known, but included for completeness)This is a callback code for a button onClick on a form. The method creates a global parameter (mesh) that is of type ooTubeMesh. This mesh is instantiated from the ooTubeMesh.CreateFromCasefile method.procedure TForm2.selectCaseFileButtonClick(Sender: TObject);var aR:ooTubeRenderer; aPanel:TGLPanelWithButton;begin OpenDialog1.Title := 'Open a Vasculature Network File....'; OpenDialog1.Filter := 'Case Files|*.cs31;*.cs4'; if OpenDialog1.Execute then begin aCaseFileName := OpenDialog1.Filename; Caption := 'CurrentCase: ' + aCaseFileName; mesh := ooTubeMesh.CreateFromCaseFile(aCaseFileName); end;end;Appendix k: Code for writing a .cs31 file (already known, but included for the sake of completeness)This is a callback code for a button onClick on a form. The method uses a global parameter (mesh) that is of type ooTubeMesh and writes the .cs31 and .nwk file using the method ooTubeMesh.SaveAsCaseAndNWKFile.procedure TForm2.Button5Click(Sender: TObject);begin aCaseFileName := stringreplace(aCaseFileName, 'casx','',[]); mesh.saveAsCaseAndNWKFile(aCaseFileName+'v2.cs31'); finishedLabel.Caption := 'finished';end; ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download