Skip to content

Commit d900467

Browse files
authored
Merge pull request #54 from nasa/glennht-fixes
Glennht fixes
2 parents ef2bc41 + 5afc5d0 commit d900467

File tree

5 files changed

+101
-145
lines changed

5 files changed

+101
-145
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*.lock
1111
python/mesh.pickle
1212
python/examples/WELD/weld_ascii.bxyz
13-
python/connectivity.pickle
13+
python/connectivity*.pickle
1414
python/connectivity_2x2x2.pickle
15-
python/examples/pointwise/saved_state.pickle
15+
python/examples/pointwise/saved_state.pickle
16+
mesh.pickle

python/job

Lines changed: 0 additions & 49 deletions
This file was deleted.

python/plot3d/glennht/class_definitions.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class BoundaryConditionType(IntEnum):
1515
GIF = 1000
1616

1717
class InletBC_Subtype(IntEnum):
18-
Normal = 0
19-
AngleSpecified = 1
20-
AngleAndProfileSpecified = 2
18+
Normal = 1
19+
AngleSpecified = 2
20+
AngleAndProfileSpecified = 3
2121

2222
class InletBC_Direction(IntEnum):
2323
Something = 1
@@ -76,7 +76,8 @@ class BoundaryCondition:
7676

7777
@dataclass
7878
class InletBC(BoundaryCondition):
79-
inlet_subType: Optional[InletBC_Subtype] = InletBC_Subtype.Normal
79+
inlet_subType: InletBC_Subtype = InletBC_Subtype.Normal
80+
surfID_inlet:int = 1
8081
inlet_ref_Mach_Nr: Optional[float] = 0.2
8182

8283
T0_const: Optional[float] = None # K (will be normalized by refT0)
@@ -99,7 +100,8 @@ class InletBC(BoundaryCondition):
99100

100101
@dataclass
101102
class OutletBC(BoundaryCondition):
102-
outlet_subType: Optional[OutletSubtype] = None
103+
outlet_subType: OutletSubtype = OutletSubtype.UniformPressure
104+
surfID_outlet:int = 2
103105
extrapolation_order: Optional[int] = None
104106
Pback_extrapolate_profile: bool = False
105107
Pback_const: Optional[float] = None
@@ -114,12 +116,14 @@ class OutletBC(BoundaryCondition):
114116

115117
@dataclass
116118
class SymmetricSlipBC(BoundaryCondition):
117-
slip_subType: Optional[SymmetricSlipSubtype] = None
119+
surfID_symmetricSlip:int = 3
120+
slip_subType: SymmetricSlipSubtype = SymmetricSlipSubtype.Slip
118121
slip_omega: Optional[float] = None
119122

120123
@dataclass
121124
class WallBC(BoundaryCondition):
122-
wall_subType: Optional[int] = None
125+
wall_subType: WallSubtype = WallSubtype.SpecifiedWallHeatFlux
126+
surfID_wall:int = 3
123127
Twall_const: Optional[float] = None
124128
have_Twall_prof: bool = False
125129
filen_Twall_prof: Optional[str] = None

python/plot3d/glennht/export_functions.py

Lines changed: 86 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import pathlib
77
from dataclasses import asdict, is_dataclass
88
from typing import Any, Iterable, Tuple, Dict, List
9-
import os
109

1110
from .class_definitions import (
1211
Job, BCGroup, GIF, VolumeZone,
@@ -83,7 +82,9 @@ def rpm_to_omegab(rpm: float | None) -> float:
8382
# ============================================================
8483
def ensure_extension(path: str | pathlib.Path, ext: str) -> str:
8584
p = pathlib.Path(path)
86-
return str(p if p.suffix.lower() == ext.lower() else p.with_suffix(ext))
85+
if p.suffix:
86+
return str(p)
87+
return str(p.with_suffix(ext))
8788

8889
def _asdict_soft(x):
8990
if is_dataclass(x):
@@ -146,26 +147,46 @@ def _export_namelist_block(header: str, obj: Any, *, exclude_names=()) -> str:
146147
inner = ", ".join(pairs)
147148
return f" &{header}\n{inner}\n &END\n"
148149

150+
# ============================================================
151+
# GIF + Volume Zone writers (dict/object inputs supported)
152+
# ============================================================
153+
def _get_field(obj: Any, name: str, default: Any = None) -> Any:
154+
if isinstance(obj, dict):
155+
return obj.get(name, default)
156+
return getattr(obj, name, default)
157+
158+
def _set_field(obj: Any, name: str, value: Any) -> None:
159+
if isinstance(obj, dict):
160+
obj[name] = value
161+
else:
162+
setattr(obj, name, value)
163+
164+
def _first_field(obj: Any, names: Iterable[str], default: Any = None) -> Any:
165+
for name in names:
166+
value = _get_field(obj, name)
167+
if value is not None:
168+
return value
169+
return default
170+
149171
def _write_bsurf_spec(w, bc):
150172
line = (
151173
f" &BSurf_Spec\n"
152-
f"BSurfID={bc.SurfaceID}, BCType={int(bc.BCType)}, BSurfName='{bc.Name}'"
174+
f"BSurfID={_get_field(bc, 'SurfaceID')}, "
175+
f"BCType={int(_get_field(bc, 'BCType'))}, "
176+
f"BSurfName='{_get_field(bc, 'Name')}'"
153177
)
154-
if getattr(bc, "IsPostProcessing", False):
178+
if _get_field(bc, "IsPostProcessing", False):
155179
line += ", BRefCond=T"
156-
if getattr(bc, "IsCalculateMassFlow", False) or getattr(bc, "ToggleProcessSurface", False):
180+
if _get_field(bc, "IsCalculateMassFlow", False) or _get_field(bc, "ToggleProcessSurface", False):
157181
line += ", BCalc=T"
158182
w.write(line + "\n &END\n\n")
159183

160-
# ============================================================
161-
# GIF + Volume Zone writers (dict inputs supported)
162-
# ============================================================
163-
def _write_gif_from_dict(w, gdict: Dict[str, Any]) -> None:
164-
sid1 = int(gdict.get("a", 0))
165-
sid2 = int(gdict.get("b", 0))
166-
name1 = f"surface {sid1}"
167-
name2 = f"surface {sid2}"
168-
bctype = 4 # GIF
184+
def _write_gif_pair(w, pair: Any) -> None:
185+
sid1 = int(_first_field(pair, ("GIFSurface1", "id1", "a"), 0))
186+
sid2 = int(_first_field(pair, ("GIFSurface2", "id2", "b"), 0))
187+
name1 = _first_field(pair, ("Name1", "name1"), f"surface {sid1}")
188+
name2 = _first_field(pair, ("Name2", "name2"), f"surface {sid2}")
189+
bctype = int(_first_field(pair, ("BCType", "bctype"), 4))
169190
w.write(
170191
f" &BSurf_Spec\nBSurfID={sid1}, BCType={bctype}, BSurfName='{name1}'\n &END\n\n"
171192
)
@@ -174,14 +195,14 @@ def _write_gif_from_dict(w, gdict: Dict[str, Any]) -> None:
174195
)
175196
w.write(f" &GIF_Spec\nSurfID_1={sid1}, SurfID2={sid2}\n &END\n\n")
176197

177-
def _write_vzconditions(w, vz: Dict[str, Any]) -> None:
198+
def _write_vzconditions(w, vz: Any) -> None:
178199
"""
179-
Convert your dict style:
180-
{"block_index": 1, "zone_type": "fluid"|"solid", "contiguous_id": 1}
200+
Convert inputs like:
201+
{"block_index": 1, "zone_type": "fluid"|"solid", "contiguous_index": 1}
181202
to the GHT namelist you showed (defaults baked in).
182203
"""
183-
vzid = int(vz.get("contiguous_id", 0))
184-
ztype = str(vz.get("zone_type", "fluid")).strip().lower()
204+
vzid = int(_first_field(vz, ("contiguous_index", "contiguous_id"), 0))
205+
ztype = str(_get_field(vz, "zone_type", "fluid")).strip().lower()
185206
vztype = 1 if ztype == "fluid" else 2
186207

187208
if vztype == 1:
@@ -312,8 +333,8 @@ def export_to_boundary_condition(
312333
file_path_to_write: str,
313334
job_settings: Job,
314335
bc_group: BCGroup,
315-
gif_pairs: List[GIF] | List[Dict[str,Any]],
316-
volume_zones: List[VolumeZone] | List[Dict[str,Any]],
336+
gif_pairs: List[Any],
337+
volume_zones: List[Any],
317338
):
318339
file_path_to_write = ensure_extension(file_path_to_write, '.bcs')
319340
path = pathlib.Path(file_path_to_write)
@@ -325,7 +346,7 @@ def export_to_boundary_condition(
325346
"outlets": [_asdict_soft(x) for x in bc_group.Outlets],
326347
"slips": [_asdict_soft(x) for x in bc_group.SymmetricSlips],
327348
"walls": [_asdict_soft(x) for x in bc_group.Walls],
328-
"volume_zones": [x for x in volume_zones],
349+
"volume_zones": [_asdict_soft(x) for x in volume_zones],
329350
"gif_pairs": [_asdict_soft(x) for x in gif_pairs],
330351
"job_settings": _asdict_soft(job_settings),
331352
}
@@ -338,10 +359,10 @@ def _reference_inlet(inlets: List[Any]) -> Tuple[Any | None, float | None]:
338359
best = None
339360
best_pa: float | None = None
340361
for inlet in inlets:
341-
p0 = getattr(inlet, "P0_const", None)
362+
p0 = _get_field(inlet, "P0_const")
342363
if p0 is None:
343364
continue
344-
phys_pa = to_pa(p0, getattr(inlet, "P0_const_unit", "Pa"))
365+
phys_pa = to_pa(p0, _get_field(inlet, "P0_const_unit", "Pa"))
345366
if phys_pa is None:
346367
continue
347368
if best_pa is None or phys_pa > best_pa:
@@ -364,14 +385,14 @@ def _reference_inlet(inlets: List[Any]) -> Tuple[Any | None, float | None]:
364385

365386
# refT0: from first inlet if missing
366387
if getattr(ref, "refT0", None) in (None, 0):
367-
if ref_inlet and getattr(ref_inlet, "T0_const", None) is not None:
368-
ref.refT0 = ref_inlet.T0_const # type: ignore
388+
if ref_inlet and _get_field(ref_inlet, "T0_const") is not None:
389+
ref.refT0 = _get_field(ref_inlet, "T0_const") # type: ignore
369390

370391
def _dedupe_by_bc_id(objs: Iterable[Any]) -> List[Any]:
371392
seen: set[int] = set()
372393
unique: List[Any] = []
373394
for obj in objs:
374-
sid = obj.get("id") if isinstance(obj, dict) else getattr(obj, "SurfaceID", None)
395+
sid = _get_field(obj, "id", _get_field(obj, "SurfaceID"))
375396
if sid is None or sid in seen:
376397
continue
377398
seen.add(sid)
@@ -382,26 +403,26 @@ def _dedupe_by_bc_id(objs: Iterable[Any]) -> List[Any]:
382403
with path.open("w", encoding="utf-8") as w:
383404
# INLETS (normalize to refP0, refT0, refLen)
384405
for inlet in _dedupe_by_bc_id(bc_group.Inlets):
385-
if getattr(inlet, "P0_const", None) is not None:
386-
phys_pa = to_pa(inlet.P0_const, getattr(inlet, "P0_const_unit", "Pa"))
406+
if _get_field(inlet, "P0_const") is not None:
407+
phys_pa = to_pa(_get_field(inlet, "P0_const"), _get_field(inlet, "P0_const_unit", "Pa"))
387408
if phys_pa is not None and ref.refP0 not in (None, 0):
388-
inlet.P0_const = phys_pa / ref.refP0
389-
if getattr(inlet, "T0_const", None) is not None and ref.refT0 not in (None, 0):
390-
inlet.T0_const = inlet.T0_const / ref.refT0 # type: ignore
391-
if getattr(inlet, "twall_hub", None) is not None and ref.refT0 not in (None, 0):
392-
inlet.twall_hub = inlet.twall_hub / ref.refT0 # type: ignore
393-
if getattr(inlet, "twall_case", None) is not None and ref.refT0 not in (None, 0):
394-
inlet.twall_case = inlet.twall_case / ref.refT0 # type: ignore
395-
if getattr(inlet, "Ts_const", None) is not None and ref.reflen not in (None, 0):
396-
inlet.Ts_const = inlet.Ts_const / ref.reflen # type: ignore
409+
_set_field(inlet, "P0_const", phys_pa / ref.refP0)
410+
if _get_field(inlet, "T0_const") is not None and ref.refT0 not in (None, 0):
411+
_set_field(inlet, "T0_const", _get_field(inlet, "T0_const") / ref.refT0)
412+
if _get_field(inlet, "twall_hub") is not None and ref.refT0 not in (None, 0):
413+
_set_field(inlet, "twall_hub", _get_field(inlet, "twall_hub") / ref.refT0)
414+
if _get_field(inlet, "twall_case") is not None and ref.refT0 not in (None, 0):
415+
_set_field(inlet, "twall_case", _get_field(inlet, "twall_case") / ref.refT0)
416+
if _get_field(inlet, "Ts_const") is not None and ref.reflen not in (None, 0):
417+
_set_field(inlet, "Ts_const", _get_field(inlet, "Ts_const") / ref.reflen)
397418
_write_bsurf_spec(w, inlet)
398419

399420
# OUTLETS (normalize back-pressure by refP0)
400421
for outlet in _dedupe_by_bc_id(bc_group.Outlets):
401-
if getattr(outlet, "Pback_const", None) is not None and ref.refP0 not in (None, 0):
402-
phys_pa = to_pa(outlet.Pback_const, getattr(outlet, "Pback_const_unit", "Pa"))
422+
if _get_field(outlet, "Pback_const") is not None and ref.refP0 not in (None, 0):
423+
phys_pa = to_pa(_get_field(outlet, "Pback_const"), _get_field(outlet, "Pback_const_unit", "Pa"))
403424
if phys_pa is not None:
404-
outlet.Pback_const = phys_pa / ref.refP0
425+
_set_field(outlet, "Pback_const", phys_pa / ref.refP0)
405426
_write_bsurf_spec(w, outlet)
406427

407428
# SLIPS / WALLS
@@ -412,57 +433,41 @@ def _dedupe_by_bc_id(objs: Iterable[Any]) -> List[Any]:
412433

413434
# GIFS (dicts or dataclasses)
414435
for pair in gif_pairs:
415-
if isinstance(pair, dict):
416-
_write_gif_from_dict(w, pair)
417-
else:
418-
name1 = getattr(pair, "Name1", f"surface {pair.GIFSurface1}")
419-
name2 = getattr(pair, "Name2", f"surface {pair.GIFSurface2}")
420-
w.write(
421-
f" &BSurf_Spec\nBSurfID={pair.GIFSurface1}, BCType={int(pair.BCType)}, "
422-
f"BSurfName='{name1}'\n &END\n\n"
423-
)
424-
w.write(
425-
f" &BSurf_Spec\nBSurfID={pair.GIFSurface2}, BCType={int(pair.BCType)}, "
426-
f"BSurfName='{name2}'\n &END\n\n"
427-
)
428-
w.write(f" &GIF_Spec\nSurfID_1={pair.GIFSurface1}, SurfID2={pair.GIFSurface2}\n &END\n\n")
436+
_write_gif_pair(w, pair)
429437

430438
# VZConditions (dict templates)
431-
volume_zone_unique = {d["contiguous_index"]: d for d in volume_zones}.values()
432-
for vz in volume_zone_unique:
433-
if isinstance(vz, dict):
439+
volume_zone_unique: Dict[Any, Any] = {}
440+
for vz in volume_zones:
441+
key = _first_field(vz, ("contiguous_index", "contiguous_id"))
442+
volume_zone_unique[key] = vz
443+
for vz in volume_zone_unique.values():
444+
if _get_field(vz, "zone_type") is not None:
434445
_write_vzconditions(w, vz)
435446
else:
436447
w.write(_export_namelist_block("VZConditions", vz)); w.write("\n")
437-
438-
# keep the *first* object for each unique obj.subtype
439-
def first_by_subtype(objs: Iterable[T], subtype_attr: str, *, include_none=False) -> List[T]:
440-
seen = set()
441-
out: List[T] = []
442-
for o in objs:
443-
# works for both objects and dicts
444-
st = getattr(o, subtype_attr, None) if not isinstance(o, dict) else o.get(subtype_attr)
445-
if st is None and not include_none:
446-
continue
447-
if st not in seen:
448-
seen.add(st)
449-
out.append(o)
450-
return out
451-
452-
inlet_bc = first_by_subtype(bc_group.Inlets,'inlet_subType')
453-
outlet_bc = first_by_subtype(bc_group.Outlets,'outlet_subType')
454-
slip_bc = first_by_subtype(bc_group.SymmetricSlips,'slip_subType')
455-
wall_bc = first_by_subtype(bc_group.Walls,'wall_subType')
456448

449+
def _sync_detail_surface_id(obj: Any, field_name: str) -> None:
450+
sid = _get_field(obj, "SurfaceID")
451+
if sid is not None:
452+
_set_field(obj, field_name, sid)
453+
457454
# Detailed BC blocks (skip meta + *_unit)
458455
exclude = {"Name", "SurfaceID", "BCType"}
459-
for inlet in inlet_bc:
456+
for inlet in bc_group.Inlets:
457+
_sync_detail_surface_id(inlet, "surfID_inlet")
458+
w.write(f"! {inlet.Name}\n")
460459
w.write(_export_namelist_block("INLET_BC", inlet, exclude_names=exclude)); w.write("\n")
461-
for outlet in outlet_bc:
460+
for outlet in bc_group.Outlets:
461+
_sync_detail_surface_id(outlet, "surfID_outlet")
462+
w.write(f"! {outlet.Name}\n")
462463
w.write(_export_namelist_block("OUTLET_BC", outlet, exclude_names=exclude)); w.write("\n")
463-
for slip in slip_bc:
464+
for slip in bc_group.SymmetricSlips:
465+
_sync_detail_surface_id(slip, "surfID_symmetricSlip")
466+
w.write(f"! {slip.Name}\n")
464467
w.write(_export_namelist_block("SLIP_BC", slip, exclude_names=exclude)); w.write("\n")
465-
for wall in wall_bc:
468+
for wall in bc_group.Walls:
469+
_sync_detail_surface_id(wall, "surfID_wall")
470+
w.write(f"! {wall.Name}\n")
466471
w.write(_export_namelist_block("WALL_BC", wall, exclude_names=exclude)); w.write("\n")
467472

468473
# ============================================================
@@ -616,11 +621,6 @@ def export_to_glennht_conn(matches:List[Dict[str, Dict[int, str]]],outer_faces:L
616621
with open(f'{filename}','w') as fp:
617622
fp.writelines(lines)
618623

619-
def ensure_extension(filename, default_ext=".txt"):
620-
base, ext = os.path.splitext(filename)
621-
if not ext: # no extension present
622-
return filename + default_ext
623-
return filename
624624
# ============================================================
625625
# ---- Quick self-test / example usage -----------------------
626626
# ============================================================

0 commit comments

Comments
 (0)