Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalized Tecplot ASCII and Binary Readers/Writers #95

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6c8fc28
Implemented tecplot ascii and binary readers and writers for n-dimens…
lamkina Jun 29, 2024
16191ce
Fixing black
lamkina Jun 29, 2024
3718d06
Adding docs for tecplot module
lamkina Jun 29, 2024
b277258
Bumped the minor version
lamkina Jun 29, 2024
0f35428
Fixed exception in external io test to catch all errors
lamkina Jun 29, 2024
b03bcac
Adding zone input validation, better use of enums, refactoring, and b…
lamkina Jul 20, 2024
9ebce66
Fixing regex for zone name matching
lamkina Aug 4, 2024
0288bee
Added terminating comma to regex pattern for zone header
lamkina Aug 4, 2024
d8fdc99
Fixed regex for zone name matching
lamkina Sep 13, 2024
660609b
Updating tecplot writers in the weight problem
lamkina Sep 13, 2024
f88c903
Fixing if checks for types
lamkina Sep 13, 2024
47903db
Updating tecplot writers in the aero solver
lamkina Sep 13, 2024
75f59ea
Fixing strand ID and solution time bugs in ASCII writer
lamkina Sep 20, 2024
80196c6
Fixed random data in ordered zones and added stress testing
lamkina Sep 20, 2024
63169ee
Added block format writer and reader to adhere to line width constraints
lamkina Sep 24, 2024
a503e8c
Added line length test for ASCII files
lamkina Sep 24, 2024
fc5c1c2
Improved the ascii data reader to use multiple separators and ignore …
lamkina Sep 24, 2024
066a6bd
Added full reader and writer separator support with tests
lamkina Sep 24, 2024
449c9b9
Cleaning up documentation, imports, and api
lamkina Sep 25, 2024
c2baf7c
Added tri connectivity property for FE zones with tests
lamkina Nov 8, 2024
fc5fbe8
Flake 8 is always watching
lamkina Nov 8, 2024
1e44f71
Added unique indices and nodes to fe zones
lamkina Nov 8, 2024
b9b83aa
New connectivity handling for FE zones with unique data and connectiv…
lamkina Nov 10, 2024
b30741e
Fixed remap connectivity bug
lamkina Nov 12, 2024
99e04c7
Switched remap connectivity to numpy for sppeeeed
lamkina Nov 12, 2024
7fc9a08
Updgraded the zone name matching to be more robust
lamkina Nov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions baseclasses/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
__version__ = "1.8.0"
__version__ = "1.9.0"

from .problems import (
AeroProblem,
TransiProblem,
StructProblem,
AeroStructProblem,
EngineProblem,
FieldPerformanceProblem,
FluidProperties,
FuelCase,
ICAOAtmosphere,
LGProblem,
MissionProblem,
MissionProfile,
MissionSegment,
StructProblem,
TransiProblem,
WeightProblem,
FuelCase,
FluidProperties,
ICAOAtmosphere,
EngineProblem,
FieldPerformanceProblem,
LGProblem,
)

from .solvers import BaseSolver, AeroSolver

from .utils import getPy3SafeString

from .solvers import AeroSolver, BaseSolver
from .testing import BaseRegTest, getTol
from .utils import getPy3SafeString, tecplotIO
121 changes: 62 additions & 59 deletions baseclasses/problems/pyWeight_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
Holds the weightProblem class for weightandbalance solvers.
"""

import numpy as np
import copy
from pathlib import Path

import numpy as np

from ..utils import TecplotFEZone, TecplotOrderedZone, writeTecplot
from ..utils.tecplotIO import ZoneType

try:
from pygeo import geo_utils
Expand Down Expand Up @@ -68,9 +73,9 @@ def addComponents(self, components): # *components?
"""

# Check if components is of type Component or list, otherwise raise Error
if type(components) == list:
if isinstance(components, list):
pass
elif type(components) == object:
elif isinstance(components, object):
components = [components]
else:
raise Error("addComponents() takes in either a list of or a single component")
Expand Down Expand Up @@ -132,7 +137,7 @@ def setSurface(self, surf):

"""

if type(surf) == list:
if isinstance(surf, list):
self.p0 = np.array(surf[0])
self.v1 = np.array(surf[1])
self.v2 = np.array(surf[2])
Expand Down Expand Up @@ -194,24 +199,28 @@ def writeSurfaceTecplot(self, fileName):
File name for tecplot file. Should have a .dat extension.

"""
f = open(fileName, "w")
f.write('TITLE = "weight_problem Surface Mesh"\n')
f.write('VARIABLES = "CoordinateX" "CoordinateY" "CoordinateZ"\n')
f.write("Zone T=%s\n" % ("surf"))
f.write("Nodes = %d, Elements = %d ZONETYPE=FETRIANGLE\n" % (len(self.p0) * 3, len(self.p0)))
f.write("DATAPACKING=POINT\n")
for i in range(len(self.p0)):
points = []
points.append(self.p0[i])
points.append(self.p0[i] + self.v1[i])
points.append(self.p0[i] + self.v2[i])
for i in range(len(points)):
f.write(f"{points[i][0]:f} {points[i][1]:f} {points[i][2]:f}\n")
# Build the FETriangle data array
dataArrays = np.zeros((len(self.p0) * 3, 3), dtype=float)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking here, but why use this large array? Makes it more readable to just use x etc. If there is no need to keep the data together, I would favor readability. This appears in other classes as well.

dataArrays[::3] = self.p0
dataArrays[1::3] = self.p0 + self.v1
dataArrays[2::3] = self.p0 + self.v2
data = {"CoordinateX": dataArrays[:, 0], "CoordinateY": dataArrays[:, 1], "CoordinateZ": dataArrays[:, 2]}

# Create the connectivity
conn = np.zeros((len(self.p0), 3), dtype=int)
for i in range(len(self.p0)):
f.write("%d %d %d\n" % (3 * i + 1, 3 * i + 2, 3 * i + 3))
conn[i, :] = [3 * i + 1, 3 * i + 2, 3 * i + 3]

f.close()
# Create the single zone
zones = [TecplotFEZone("surf", data, conn, zoneType=ZoneType.FETRIANGLE)]

writeTecplot(
fileName,
title="weight_problem Surface Mesh",
zones=zones,
datapacking="POINT",
precision="SINGLE",
)

def writeTecplot(self, fileName):
"""
Expand Down Expand Up @@ -362,9 +371,9 @@ def addFuelCases(self, cases):
"""

# Check if case is a single entry or a list, otherwise raise Error
if type(cases) == list:
if isinstance(cases, list):
pass
elif type(cases) == object:
elif isinstance(cases, object):
cases = [cases]
else:
raise Error("addFuelCases() takes in either a list of or a single fuelcase")
Expand Down Expand Up @@ -447,7 +456,7 @@ def _getComponentKeys(self, include=None, exclude=None, includeType=None, exclud

if includeType is not None:
# Specified a list of component types to include
if type(includeType) == str:
if isinstance(includeType, str):
includeType = [includeType]
weightKeysTmp = set()
for key in weightKeys:
Expand All @@ -457,21 +466,21 @@ def _getComponentKeys(self, include=None, exclude=None, includeType=None, exclud

if include is not None:
# Specified a list of compoents to include
if type(include) == str:
if isinstance(include, str):
include = [include]
include = set(include)
weightKeys.intersection_update(include)

if exclude is not None:
# Specified a list of components to exclude
if type(exclude) == str:
if isinstance(exclude, str):
exclude = [exclude]
exclude = set(exclude)
weightKeys.difference_update(exclude)

if excludeType is not None:
# Specified a list of compoent types to exclude
if type(excludeType) == str:
if isinstance(excludeType, str):
excludeType = [excludeType]
weightKeysTmp = copy.copy(weightKeys)
for key in weightKeys:
Expand All @@ -490,48 +499,42 @@ def writeMassesTecplot(self, filename):

filename: str
filename for writing the masses. This string will have the
.dat suffix appended to it.
# .dat suffix appended to it if it does not already have it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# intentional?

"""

fileHandle = filename + ".dat"
f = open(fileHandle, "w")
nMasses = len(self.nameList)
f.write('TITLE = "%s: Mass Data"\n' % self.name)
f.write('VARIABLES = "X", "Y", "Z", "Mass"\n')
locList = ["current", "fwd", "aft"]

zones = []
for loc in locList:
f.write('ZONE T="%s", I=%d, J=1, K=1, DATAPACKING=POINT\n' % (loc, nMasses))

for key in self.components.keys():
dataArray = np.zeros((nMasses, 4), dtype=float)
for i, key in enumerate(self.components.keys()):
CG = self.components[key].getCG(loc)
mass = self.components[key].getMass()
x = np.real(CG[0])
y = np.real(CG[1])
z = np.real(CG[2])
m = np.real(mass)

f.write(f"{x:f} {y:f} {z:f} {m:f}\n")

# end
f.write("\n")
# end

# textOffset = 0.5
# for loc in locList:
# for name in self.nameList:
# x= np.real(self.componentDict[name].CG[loc][0])
# y= np.real(self.componentDict[name].CG[loc][1])
# z= np.real(self.componentDict[name].CG[loc][2])+textOffset
# m= np.real(self.componentDict[name].W)

# f.write('TEXT CS=GRID3D, HU=POINT, X=%f, Y=%f, Z=%f, H=12, T="%s"\n'%(x,y,z,name+' '+loc))
# # end

# # end

f.close()
return
dataArray[i, 0] = CG[0]
dataArray[i, 1] = CG[1]
dataArray[i, 2] = CG[2]
dataArray[i, 3] = mass

data = {
"CoordinateX": dataArray[:, 0],
"CoordinateY": dataArray[:, 1],
"CoordinateZ": dataArray[:, 2],
"Mass": dataArray[:, 3],
}

zones.append(TecplotOrderedZone(loc, data))

# Create the path with the .dat extension
filePath = Path(filename).with_suffix(".dat")

writeTecplot(
filePath,
title=f"{self.name}: Mass Data",
zones=zones,
datapacking="POINT",
precision="SINGLE",
)

def writeProblemData(self, fileName):
"""
Expand Down
35 changes: 18 additions & 17 deletions baseclasses/solvers/pyAero_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
# Extension modules
# =============================================================================
from .BaseSolver import BaseSolver
from ..utils import CaseInsensitiveDict, Error
from ..utils import CaseInsensitiveDict, Error, TecplotFEZone, writeTecplot
from ..utils.tecplotIO import ZoneType

# =============================================================================
# AeroSolver Class
# =============================================================================


class AeroSolver(BaseSolver):

"""
Abstract Class for Aerodynamic Solver Object
"""
Expand Down Expand Up @@ -207,24 +207,25 @@ def writeTriangulatedSurfaceTecplot(self, fileName, groupName=None, **kwargs):
"""
[p0, v1, v2] = self.getTriangulatedMeshSurface(groupName, **kwargs)
if self.comm.rank == 0:
f = open(fileName, "w")
f.write('TITLE = "%s Surface Mesh"\n' % self.name)
f.write('VARIABLES = "CoordinateX" "CoordinateY" "CoordinateZ"\n')
f.write("Zone T=%s\n" % ("surf"))
f.write("Nodes = %d, Elements = %d ZONETYPE=FETRIANGLE\n" % (len(p0) * 3, len(p0)))
f.write("DATAPACKING=POINT\n")
for i in range(len(p0)):
points = []
points.append(p0[i])
points.append(p0[i] + v1[i])
points.append(p0[i] + v2[i])
for i in range(len(points)):
f.write(f"{points[i][0]:f} {points[i][1]:f} {points[i][2]:f}\n")
dataArray = np.zeros((len(p0) * 3, 3), dtype=float)
dataArray[::3] = p0
dataArray[1::3] = p0 + v1
dataArray[2::3] = p0 + v2
data = {"CoordinateX": dataArray[:, 0], "CoordinateY": dataArray[:, 1], "CoordinateZ": dataArray[:, 2]}

conn = np.zeros((len(p0), 3), dtype=int)
for i in range(len(p0)):
f.write("%d %d %d\n" % (3 * i + 1, 3 * i + 2, 3 * i + 3))
conn[i, :] = [3 * i + 1, 3 * i + 2, 3 * i + 3]

f.close()
zones = [TecplotFEZone("surf", data, conn, zoneType=ZoneType.FETRIANGLE)]

writeTecplot(
fileName,
title=f"{self.name} Surface Mesh",
zones=zones,
datapacking="POINT",
precision="SINGLE",
)

def checkSolutionFailure(self, aeroProblem, funcs):
"""Take in a an aeroProblem and check for failure. Then append the
Expand Down
12 changes: 9 additions & 3 deletions baseclasses/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from .containers import CaseInsensitiveSet, CaseInsensitiveDict
from .containers import CaseInsensitiveDict, CaseInsensitiveSet
from .error import Error
from .utils import getPy3SafeString, pp, ParseStringFormat
from .fileIO import writeJSON, readJSON, writePickle, readPickle, redirectIO, redirectingIO
from .fileIO import readJSON, readPickle, redirectingIO, redirectIO, writeJSON, writePickle
from .solverHistory import SolverHistory
from .tecplotIO import TecplotFEZone, TecplotOrderedZone, TecplotZone, readTecplot, writeTecplot
from .utils import ParseStringFormat, getPy3SafeString, pp

__all__ = [
"CaseInsensitiveSet",
Expand All @@ -17,5 +18,10 @@
"redirectIO",
"redirectingIO",
"SolverHistory",
"TecplotZone",
"TecplotFEZone",
"TecplotOrderedZone",
"writeTecplot",
"readTecplot",
"ParseStringFormat",
]
Loading
Loading