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

# Check if components is of type Component or list, otherwise raise Error
if type(components) == list:
if isinstance(components, list):

Check warning on line 76 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L76

Added line #L76 was not covered by tests
pass
elif type(components) == object:
elif isinstance(components, object):

Check warning on line 78 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L78

Added line #L78 was not covered by tests
components = [components]
else:
raise Error("addComponents() takes in either a list of or a single component")
Expand Down Expand Up @@ -132,7 +137,7 @@
"""

if type(surf) == list:
if isinstance(surf, list):

Check warning on line 140 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L140

Added line #L140 was not covered by tests
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 @@
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]}

Check warning on line 207 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L203-L207

Added lines #L203 - L207 were not covered by tests

# Create the connectivity
conn = np.zeros((len(self.p0), 3), dtype=int)

Check warning on line 210 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L210

Added line #L210 was not covered by tests
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]

Check warning on line 212 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L212

Added line #L212 was not covered by tests

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

Check warning on line 215 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L215

Added line #L215 was not covered by tests

writeTecplot(

Check warning on line 217 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L217

Added line #L217 was not covered by tests
fileName,
title="weight_problem Surface Mesh",
zones=zones,
datapacking="POINT",
precision="SINGLE",
)

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

# Check if case is a single entry or a list, otherwise raise Error
if type(cases) == list:
if isinstance(cases, list):

Check warning on line 374 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L374

Added line #L374 was not covered by tests
pass
elif type(cases) == object:
elif isinstance(cases, object):

Check warning on line 376 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L376

Added line #L376 was not covered by tests
cases = [cases]
else:
raise Error("addFuelCases() takes in either a list of or a single fuelcase")
Expand Down Expand Up @@ -447,7 +456,7 @@

if includeType is not None:
# Specified a list of component types to include
if type(includeType) == str:
if isinstance(includeType, str):

Check warning on line 459 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L459

Added line #L459 was not covered by tests
includeType = [includeType]
weightKeysTmp = set()
for key in weightKeys:
Expand All @@ -457,21 +466,21 @@

if include is not None:
# Specified a list of compoents to include
if type(include) == str:
if isinstance(include, str):

Check warning on line 469 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L469

Added line #L469 was not covered by tests
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):

Check warning on line 476 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L476

Added line #L476 was not covered by tests
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):

Check warning on line 483 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L483

Added line #L483 was not covered by tests
excludeType = [excludeType]
weightKeysTmp = copy.copy(weightKeys)
for key in weightKeys:
Expand All @@ -490,48 +499,42 @@
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 = []

Check warning on line 508 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L508

Added line #L508 was not covered by tests
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()):

Check warning on line 511 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L510-L511

Added lines #L510 - L511 were not covered by tests
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

Check warning on line 517 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L514-L517

Added lines #L514 - L517 were not covered by tests

data = {

Check warning on line 519 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L519

Added line #L519 was not covered by tests
"CoordinateX": dataArray[:, 0],
"CoordinateY": dataArray[:, 1],
"CoordinateZ": dataArray[:, 2],
"Mass": dataArray[:, 3],
}

zones.append(TecplotOrderedZone(loc, data))

Check warning on line 526 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L526

Added line #L526 was not covered by tests

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

Check warning on line 529 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L529

Added line #L529 was not covered by tests

writeTecplot(

Check warning on line 531 in baseclasses/problems/pyWeight_problem.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/problems/pyWeight_problem.py#L531

Added line #L531 was not covered by tests
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 @@
"""
[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]}

Check warning on line 214 in baseclasses/solvers/pyAero_solver.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/solvers/pyAero_solver.py#L210-L214

Added lines #L210 - L214 were not covered by tests

conn = np.zeros((len(p0), 3), dtype=int)

Check warning on line 216 in baseclasses/solvers/pyAero_solver.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/solvers/pyAero_solver.py#L216

Added line #L216 was not covered by tests
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]

Check warning on line 218 in baseclasses/solvers/pyAero_solver.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/solvers/pyAero_solver.py#L218

Added line #L218 was not covered by tests

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

Check warning on line 220 in baseclasses/solvers/pyAero_solver.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/solvers/pyAero_solver.py#L220

Added line #L220 was not covered by tests

writeTecplot(

Check warning on line 222 in baseclasses/solvers/pyAero_solver.py

View check run for this annotation

Codecov / codecov/patch

baseclasses/solvers/pyAero_solver.py#L222

Added line #L222 was not covered by tests
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