Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
23624f5
Add mesh output to OM reader
sabakhshi Aug 8, 2025
3b99ca4
Initial commit of direct mesh setting
sabakhshi Oct 24, 2025
bd25ced
Implemented python interface and setting basic meshes works
sabakhshi Oct 27, 2025
4462a65
minor fixes for adjust_mesh_spacing
sabakhshi Oct 28, 2025
85135d3
Fixes for the automatic section slicing routines
sabakhshi Oct 28, 2025
26820d2
Fixes for using nspans to define sections
sabakhshi Oct 28, 2025
83512c4
Fix direct spec of iploc and fix numerous issues with controls
sabakhshi Oct 28, 2025
b443660
tweak f2py interface to pass size explicitly
joanibal Oct 28, 2025
419d72e
Fix broken ainc interp and fix broken camber slope interp
sabakhshi Oct 28, 2025
ca41ba4
Fixed multiple surfaces not being handled correct with custom meshes.…
sabakhshi Oct 29, 2025
dc03dec
fix tecplot file writing
sabakhshi Oct 30, 2025
3728fd3
start figuring out an update routine
sabakhshi Oct 30, 2025
10ac86b
hacked in a way to update surfaces without store or allocating anythi…
sabakhshi Oct 31, 2025
455fe81
WIP rework
sabakhshi Nov 4, 2025
27d8289
Wip stuff
sabakhshi Nov 4, 2025
0514f65
Wip
sabakhshi Nov 5, 2025
488a312
Finally finished the flat index rework for direct mesh
sabakhshi Nov 17, 2025
b283efc
Implement flat mesh setting in python layer initialization. fix some …
sabakhshi Nov 19, 2025
0967bce
Implement new normal calcs for custom meshes
sabakhshi Nov 21, 2025
4c5e34b
Implemented mesh flattening
sabakhshi Dec 16, 2025
e264a5f
start cleaning up for PR
sabakhshi Jan 12, 2026
cc67879
integrated encalc routine for custom meshes into the main one
sabakhshi Jan 13, 2026
426e43f
Added plotting features
sabakhshi Jan 16, 2026
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
13 changes: 13 additions & 0 deletions optvl/om_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,16 @@ def add_ovl_geom_vars(self, ovl, add_as="inputs", include_airfoil_geom=False):
elif add_as == "outputs":
self.add_output(geom_key, val=surf_data[surf][key], tags="geom")

def add_ovl_mesh_out_as_output(self, ovl):
surf_data = ovl.get_surface_params()

meshes,_ = ovl.get_cp_data()

for surf in surf_data:
idx_surf = ovl.surface_names.index(surf)
out_name = f"{surf}:mesh"
self.add_output(out_name, val=meshes[idx_surf], tags="geom_mesh")

def add_ovl_conditions_as_inputs(sys, ovl):
# TODO: add all the condition constraints

Expand Down Expand Up @@ -697,14 +706,18 @@ class OVLMeshReader(om.ExplicitComponent):
def initialize(self):
self.options.declare("geom_file", types=str)
self.options.declare("mass_file", default=None)
self.options.declare("mesh_output",default=False)

def setup(self):
geom_file = self.options["geom_file"]
mass_file = self.options["mass_file"]
mesh_output = self.options["mesh_output"]

avl = OVLSolver(geo_file=geom_file, mass_file=mass_file, debug=False)
add_ovl_geom_vars(self, avl, add_as="outputs", include_airfoil_geom=True)

if mesh_output:
add_ovl_mesh_out_as_output(self,avl)

class Differencer(om.ExplicitComponent):
def setup(self):
Expand Down
470 changes: 439 additions & 31 deletions optvl/optvl_class.py

Large diffs are not rendered by default.

49 changes: 48 additions & 1 deletion optvl/utils/check_surface_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ def pre_check_input_dict(input_dict: dict):
"nspans", # number of spanwise elements vector, overriden by nspans
"sspaces", # spanwise spacing vector (for each section), overriden by sspace
"use surface spacing", # surface spacing set under the surface heeading (known as LSURFSPACING in AVL)
# Geometery: Mesh
"mesh",
"iptloc",
"flatten_mesh",
# Control Surfaces
# "dname" # IMPLEMENT THIS
"icontd", # control variable index
Expand Down Expand Up @@ -193,24 +197,67 @@ def pre_check_input_dict(input_dict: dict):
stacklevel=2,
)
input_dict[key] = np.sign(input_dict[key])

# Check for keys not implemented
if key not in keys_implemented_general:
warnings.warn(
"Key `{}` in input dict is (likely) not supported in OptVL and will be ignored".format(key),
category=RuntimeWarning,
stacklevel=2,
)

total_global_control = 0
total_global_design_var = 0
if "surfaces" in input_dict.keys():
if len(input_dict["surfaces"]) > 0:
for surface in input_dict["surfaces"].keys():

# Check if we are directly providing a mesh
if "mesh" in input_dict["surfaces"][surface].keys():
# Check if sections are specified
if "num_sections" in input_dict["surfaces"][surface].keys():
# Check if the section indices are provided
if "iptloc" in input_dict["surfaces"][surface].keys():
# If they are make sure we provide one for every section
if len(input_dict["surfaces"][surface]["iptloc"]) != input_dict["surfaces"][surface]["num_sections"]:
raise ValueError("iptloc vector length does not match num_sections")
# Check if the user provided nspans instead
elif "nspans" in input_dict["surfaces"][surface].keys():
# setting iptloc to 0 is how we tell the Fortran layer to use nspans
input_dict["surfaces"][surface]["iptloc"] = np.zeros(input_dict["surfaces"][surface]["num_sections"])
# The OptVL class will have to call the fudging routine to try and auto cut the mesh into sections
else:
warnings.warn(
"Mesh provided for surface dict `{}` for {} sections but locations not defined.\n OptVL will automatically define section locations as close to equally as possible.".format(
surface, input_dict["surfaces"][surface]["num_sections"]
),
category=RuntimeWarning,
stacklevel=2,
)
else:
# Assume we have two sections at the ends of mesh and inform the user
warnings.warn(
"Mesh provided for surface dict `{}` but no sections provided.\n Assuming 2 sections at tips.".format(
surface
),
category=RuntimeWarning,
stacklevel=2,
)
input_dict["surfaces"][surface]["iptloc"] = np.array([0,input_dict["surfaces"][surface]["mesh"].shape[1]-1],dtype=np.int32)
input_dict["surfaces"][surface]["num_sections"] = 2

# Verify at least two section
if input_dict["surfaces"][surface]["num_sections"] < 2:
raise RuntimeError("Must have at least two sections per surface!")

# if no controls are specified then fill it in with 0s
if "num_controls" not in input_dict["surfaces"][surface].keys():
input_dict["surfaces"][surface]["num_controls"] = np.zeros(input_dict["surfaces"][surface]["num_sections"],dtype=np.int32)

# if no dvs are specified then fill it in with 0s
if "num_design_vars" not in input_dict["surfaces"][surface].keys():
input_dict["surfaces"][surface]["num_design_vars"] = np.zeros(input_dict["surfaces"][surface]["num_sections"],dtype=np.int32)

#Checks to see that at most only one of the options in af_load_ops or one of the options in manual_af_override is selected
if len(airfoil_spec_keys & input_dict["surfaces"][surface].keys()) > 1:
raise RuntimeError(
Expand Down
5 changes: 5 additions & 0 deletions src/aic.f
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ SUBROUTINE VVOR(BETM,IYSYM,YSYM,IZSYM,ZSYM,VRCORE,
& RV2(1,J),RV2(2,J),RV2(3,J),
& BETM,U,V,W,RCORE)
C
! print *, "Influence of", J, "on", I
! print *, "U:", U
! print *, "V:", V
! print *, "W:", W
! print *, "MARK"
IF(IYSYM.NE.0) THEN
C... Calculate the influence of the y-IMAGE vortex
LBOUND = .TRUE.
Expand Down
Loading