From 4344c8dcddedde9ee8f122488057c6ea385ab79c Mon Sep 17 00:00:00 2001 From: Joshua Anibal Date: Fri, 15 Aug 2025 07:03:23 -0700 Subject: [PATCH 1/2] update all moment coef names and a few fixes --- config/defaults/config.LINUX_GFORTRAN.mk | 2 + optvl/optvl_class.py | 79 ++++++++++++++---------- src/aero.f | 1 + src/aoutmrf.f | 12 ++-- src/aoutput.f | 2 +- src/build/Makefile | 6 +- src/includes/AVL.INC.in | 6 +- 7 files changed, 61 insertions(+), 47 deletions(-) diff --git a/config/defaults/config.LINUX_GFORTRAN.mk b/config/defaults/config.LINUX_GFORTRAN.mk index c8f1cc2b..659e0309 100644 --- a/config/defaults/config.LINUX_GFORTRAN.mk +++ b/config/defaults/config.LINUX_GFORTRAN.mk @@ -13,3 +13,5 @@ F2PY = f2py F2PY_FF90 = gfortran PYTHON = python + +LINKER_FLAGS = \ No newline at end of file diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index b6948ac9..3273724b 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -67,8 +67,8 @@ class OVLSolver(object): "Izx": 25, "visc CL_a": 26, "visc CL_u": 27, - "visc CM_a": 28, - "visc CM_u": 29, + "visc Cm_a": 28, + "visc Cm_u": 29, } # fmt: off @@ -79,6 +79,7 @@ class OVLSolver(object): "CL": ["CASE_R", "CLTOT"], "CD": ["CASE_R", "CDTOT"], "CDv": ["CASE_R", "CDVTOT"], # viscous drag + "CDi": ["CASE_R", "CDITOT"], # viscous drag # lift and drag calculated from farfield integration "CLff": ["CASE_R", "CLFF"], @@ -120,9 +121,9 @@ class OVLSolver(object): "CX": ["CASE_R", "CXTOT_D"], "CY": ["CASE_R", "CYTOT_D"], "CZ": ["CASE_R", "CZTOT_D"], - "CR": ["CASE_R", "CRTOT_D"], - "CM": ["CASE_R", "CMTOT_D"], - "CN": ["CASE_R", "CNTOT_D"], + "Cl": ["CASE_R", "CRTOT_D"], + "Cm": ["CASE_R", "CMTOT_D"], + "Cn": ["CASE_R", "CNTOT_D"], } # This dict has the following structure: @@ -132,22 +133,27 @@ class OVLSolver(object): "CL": ["SURF_R", "CLSURF"], "CD": ["SURF_R", "CDSURF"], "CDv": ["SURF_R", "CDVSURF"], # viscous drag + "CDi": ["SURF_R", "CDISURF"], # inviscid drag - # non-dimensionalized forces - "CX": ["SURF_R", "CXSURF"], - "CY": ["SURF_R", "CYSURF"], - "CZ": ["SURF_R", "CZSURF"], + # geometric + "area": ["SURF_R", "SSURF"], + "average chord": ["SURF_R", "CAVESURF"], - # non-dimensionalized moments (body frame) - "CR": ["SURF_R", "CRSURF"], - "CM": ["SURF_R", "CMSURF"], - "CN": ["SURF_R", "CNSURF"], + # non-dimensionalized forces + "CX ": ["SURF_R", "CXSURF"], + "C Y": ["SURF_R", "CYSURF"], + " CZ": ["SURF_R", "CZSURF"], + + # non-dimensionalized momen ts (body frame) + "Cl": ["SURF_R", "CRSURF" ], + "Cm": ["SURF_R", "CMSUR F"], + "Cn": ["SURF_R", "CNSURF"], # forces non-dimentionalized by surface quantities # uses surface area instead of sref and takes moments about leading edge "CL surf" : ["SURF_R", "CL_SRF"], "CD surf" : ["SURF_R", "CD_SRF"], - "CMLE surf" : ["SURF_R", "CMLE_SRF"], + "CmLE surf" : ["SURF_R", "CMLE_SRF"], #TODO: add CF_SRF(3,NFMAX), CM_SRF(3,NFMAX) } @@ -246,9 +252,9 @@ def __init__(self, geo_file:str, mass_file: Optional[str]=None, debug:Optional[b "yaw rate": 4, "CL": 5, "CY": 6, - "CR BA": 7, - "CM": 8, - "CR": 9, + "Cl": 7, + "Cm": 8, + "Cl'": 9, } # control surfaces added in __init__ @@ -724,7 +730,7 @@ def get_constraint(self, con_key: str) -> float: """get the value of a constraint Args: - con_key: name of the constraint. Options are ["alpha","beta","roll rate","pitch rate","yaw rate","CL","CY","CR BA","CM","CR"] + con_key: name of the constraint. Options are ["alpha","beta","roll rate","pitch rate","yaw rate","CL","CY","Cl","Cm","Cl'"] Returns: con_val: value of the constraint @@ -797,18 +803,18 @@ def get_hinge_moments(self) -> Dict[str, float]: def get_strip_forces(self) -> Dict[str, Dict[str, np.ndarray]]: """get force data for each strip (chordwise segment) of the mesh. - Returns: - strip_data: dictionary of strip data. The keys are ["chord", "width", "X LE", "Y LE", "Z LE", "twist","CL", "CD", "CDv", "downwash", "CX", "CY", "CZ","CM", "CN", "CR","CL strip", "CD strip", "CF strip", "CM strip","CL perp","CM c/4,"CM LE"] + Returns: + strip_data: dictionary of strip data. The keys are ["chord", "width", "X LE", "Y LE", "Z LE", "twist","CL", "CD", "CDv", "downwash", "CX", "CY", "CZ","Cm", "Cn", "Cl","CL strip", "CD strip", "CF strip", "Cm strip","CL perp","Cm c/4,"Cm LE"] """ # fmt: off var_to_fort_var = { # geometric quantities - "chord": ["STRP_R", "CHORD"], - "width": ["STRP_R", "WSTRIP"], "X LE": ["STRP_R", "RLE", (slice(None), 0)], # control point leading edge coordinates "Y LE": ["STRP_R", "RLE", (slice(None), 1)], # control point leading edge coordinates "Z LE": ["STRP_R", "RLE", (slice(None), 2)], # control point leading edge coordinates + "chord": ["STRP_R", "CHORD"], + "width": ["STRP_R", "WSTRIP"], "twist": ["STRP_R", "AINC"], # strip contributions to total lift and drag from strip integration @@ -824,21 +830,21 @@ def get_strip_forces(self) -> Dict[str, Dict[str, np.ndarray]]: "CZ": ["STRP_R", "CZSTRP"], # strip contributions to total moments (body frame) - "CM": ["STRP_R", "CMSTRP"], - "CN": ["STRP_R", "CNSTRP"], - "CR": ["STRP_R", "CRSTRP"], + "Cl": ["STRP_R", "CRSTRP"], + "Cm": ["STRP_R", "CMSTRP"], + "Cn": ["STRP_R", "CNSTRP"], # forces non-dimentionalized by strip quantities "CL strip" : ["STRP_R", "CL_LSTRP"], "CD strip" : ["STRP_R", "CD_LSTRP"], "CF strip" : ["STRP_R", "CF_STRP"], # forces in 3 directions - "CM strip" : ["STRP_R", "CM_STRP"], # moments in 3 directions + "Cm strip" : ["STRP_R", "CM_STRP"], # moments in 3 directions # additional forces and moments "CL perp" : ["STRP_R", "CLTSTRP"], # strip CL referenced to Vperp, - "CM c/4" : ["STRP_R","CMC4"], # strip pitching moment about c/4 and - "CM LE" : ["STRP_R","CMLE"], # strip pitching moment about LE vector + "Cm c/4" : ["STRP_R","CMC4"], # strip pitching moment about c/4 and + "Cm LE" : ["STRP_R","CMLE"], # strip pitching moment about LE vector "spanloading" : ["STRP_R","CNC"], # strip spanloading } @@ -857,11 +863,17 @@ def get_strip_forces(self) -> Dict[str, Dict[str, np.ndarray]]: idx_srp_beg, idx_srp_end = self._get_surface_strip_indices(idx_surf) strip_data[surf_name][key] = vals[idx_srp_beg:idx_srp_end] - - # convert the twist to degrees + # process the data + # add a few more pieces of data that are output on the fortran layer for surf_key in strip_data: - # add sectional lift and drag + # convert the twist to degrees strip_data[surf_key]["twist"] = 180/np.pi *strip_data[surf_key]["twist"] + # add the area of each strip + strip_data[surf_key]["area"] = strip_data[surf_key]["width"]*strip_data[surf_key]["chord"] + + # formula is directly from AVL + xcp = 0.25 - strip_data[surf_key]["Cm c/4"]/strip_data[surf_key]["CL perp"] + strip_data[surf_key]["CP x/c"] = xcp # get length of along the surface of each strip for idx_surf, surf_key in enumerate(strip_data): @@ -890,8 +902,8 @@ def get_strip_forces(self) -> Dict[str, Dict[str, np.ndarray]]: # add sectional lift and drag strip_data[surf_key]["lift dist"] = strip_data[surf_key]["CL"] * strip_data[surf_key]["chord"] / cref strip_data[surf_key]["drag dist"] = strip_data[surf_key]["CD"] * strip_data[surf_key]["chord"] / cref - strip_data[surf_key]["roll dist"] = strip_data[surf_key]["CN"] * (strip_data[surf_key]["chord"] / cref)**2 - strip_data[surf_key]["yaw dist"] = strip_data[surf_key]["CY"] * strip_data[surf_key]["chord"]**2 / (bref*cref) + strip_data[surf_key]["roll dist"] = strip_data[surf_key]["Cl"] * (strip_data[surf_key]["chord"] / cref)**2 + strip_data[surf_key]["yaw dist"] = strip_data[surf_key]["Cn"] * strip_data[surf_key]["chord"]**2 / (bref*cref) return strip_data @@ -1926,7 +1938,6 @@ def set_body_axis_derivs_ad_seeds(self, body_axis_deriv_seeds: Dict[str, Dict[st var += self.ad_suffix val = body_axis_deriv_seeds[func_key] * scale - self.set_avl_fort_arr(blk, var, val, slicer=slicer) diff --git a/src/aero.f b/src/aero.f index fc53482b..c260312b 100644 --- a/src/aero.f +++ b/src/aero.f @@ -1182,6 +1182,7 @@ SUBROUTINE SFFORC C C C------------------------------------------------- + CDISURF(IS) = CDSURF(IS) - CDVSURF(IS) IF(LFLOAD(IS)) THEN C------- Total forces summed from surface forces... C- normalized to configuration reference quantities diff --git a/src/aoutmrf.f b/src/aoutmrf.f index 0709a8d4..7e6911bf 100644 --- a/src/aoutmrf.f +++ b/src/aoutmrf.f @@ -280,12 +280,12 @@ SUBROUTINE MRFSTRP(LUN) & SSURF(N),CAVESURF(N), & '| Surface area Ssurf, Ave. chord Cave' C - CDISURF = CDSURF(N)-CDVSURF(N) + ! CDISURF = CDSURF(N)-CDVSURF(N) WRITE(LUN,'(8(ES23.15),3X,A,A,A)') & CLSURF(N),DIR*CRSURF(N), & CYSURF(N), CMSURF(N), & CDSURF(N),DIR*CNSURF(N), - & CDISURF,CDVSURF(N), + & CDISURF(N),CDVSURF(N), & '| CLsurf, Clsurf, CYsurf, Cmsurf, ', & 'CDsurf, Cnsurf, CDisurf, CDvsurf', & '; Forces referred to Sref, Cref, Bref about Xref, Yref, Zref' @@ -301,13 +301,13 @@ SUBROUTINE MRFSTRP(LUN) DO JJ = 1, NS J = J1 + JJ-1 ASTRP = WSTRIP(J)*CHORD(J) - XCP = 999. - IF(CL_LSTRP(J).NE.0.) XCP = 0.25 - CMC4(J)/CL_LSTRP(J) + XCPSTRP = 999. + IF(CL_LSTRP(J).NE.0.) XCPSTRP = 0.25 - CMC4(J)/CL_LSTRP(J) WRITE(LUN,'(I4,14(ES23.15))') & J,RLE(1,J),RLE(2,J),RLE(3,J), & CHORD(J),ASTRP,CNC(J),DWWAKE(J), & CLTSTRP(J),CL_LSTRP(J),CD_LSTRP(J),CDV_LSTRP(J), - & CMC4(J),CMLE(J),XCP + & CMC4(J),CMLE(J),XCPSTRP END DO END DO C @@ -350,7 +350,7 @@ SUBROUTINE MRFELE(LUN) & SSURF(N),CAVESURF(N), & '| Surface area, Ave. chord' C - CDISURF = CDSURF(N)-CDVSURF(N) + ! CDISURF = CDSURF(N)-CDVSURF(N) WRITE(LUN,'(8(ES23.15),3X,A,A)') & CLSURF(N),DIR*CRSURF(N), & CYSURF(N), CMSURF(N), diff --git a/src/aoutput.f b/src/aoutput.f index 7a3878ff..c699aaec 100644 --- a/src/aoutput.f +++ b/src/aoutput.f @@ -169,7 +169,7 @@ SUBROUTINE OUTSURF(LUN) CALL STRIP(STITLE(N),NT) WRITE (LUN,211) N,SSURF(N),CLSURF(N),CDSURF(N),CMSURF(N), & CYSURF(N),DIR*CNSURF(N),DIR*CRSURF(N), - & CDSURF(N)-CDVSURF(N),CDVSURF(N), + & CDISURF(N),CDVSURF(N), & STITLE(N)(1:NT) END DO cc WRITE(LUN,212) diff --git a/src/build/Makefile b/src/build/Makefile index 9acbe02d..9750d8f3 100644 --- a/src/build/Makefile +++ b/src/build/Makefile @@ -41,7 +41,7 @@ OFILES=$(f90Files:%.f90=%.o) $(F90Files:%.F90=%.o) $(f77FilesNoDir:%.f=%.o) $(cF default: lib ../f2py/libavl.pyf # Generate Python inlude directory - $(eval PYTHON_INCLUDES = $(shell python3-config --includes)) + $(eval PYTHON_INCLUDES = $(shell python-config --includes)) @echo "#------------------------------------------------------#" @echo Python Inclue Flags $(PYTHON_INCLUDES) @echo "#------------------------------------------------------#" @@ -72,10 +72,10 @@ default: lib ../f2py/libavl.pyf -c $(F2PY_ROOT)/src/fortranobject.c -o fortranobject.o # Compiled f2py-generated wrapper file - $(FF90) $(FF90_ALL_FLAGS) -I ../includes -I./ -c libavl-f2pywrappers.f + $(FF90) $(FF90_ALL_FLAGS) -I../includes -I./ -c libavl-f2pywrappers.f # Final Link: - $(FF90) -shared fortranobject.o libavlmodule.o libavl-f2pywrappers.o libavl.a $(LINKER_ALL_FLAGS) -o libavl.so + $(FF90) $(LINKER_FLAGS) -shared fortranobject.o libavlmodule.o libavl-f2pywrappers.o libavl.a -o libavl.so $(PYTHON) importTest.py libavl mv libavl.*so ../../optvl/libavl.so diff --git a/src/includes/AVL.INC.in b/src/includes/AVL.INC.in index 3bf487b4..c8050c62 100644 --- a/src/includes/AVL.INC.in +++ b/src/includes/AVL.INC.in @@ -365,7 +365,7 @@ cc#endif REAL(kind=avl_real) CDSURF,CLSURF REAL(kind=avl_real) CXSURF,CYSURF,CZSURF REAL(kind=avl_real) CRSURF,CNSURF,CMSURF - REAL(kind=avl_real) CDVSURF + REAL(kind=avl_real) CDVSURF, CDISURF REAL(kind=avl_real) CDS_A, CLS_A REAL(kind=avl_real) CDS_U, CLS_U REAL(kind=avl_real) CXS_U, CYS_U, CZS_U @@ -385,8 +385,8 @@ C Surface forces and moments referenced to SREF,CREF,BREF about XREF,YREF,ZREF & CDSURF(NFMAX),CLSURF(NFMAX), ! surface CD,CL & CXSURF(NFMAX),CYSURF(NFMAX),CZSURF(NFMAX), ! surface Cx,Cy,Cz & CRSURF(NFMAX),CNSURF(NFMAX),CMSURF(NFMAX), ! surface Cl,Cm,Cn - & CDVSURF(NFMAX), ! surface viscous CD - & CDS_A(NFMAX), CLS_A(NFMAX), ! alpha sens. + & CDVSURF(NFMAX),CDISURF(NFMAX), ! surface viscous/invisid CD + & CDS_A(NFMAX), CLS_A(NFMAX), ! alpha sens. & CDS_U(NFMAX,NUMAX), CLS_U(NFMAX,NUMAX), & CXS_U(NFMAX,NUMAX), CYS_U(NFMAX,NUMAX), CZS_U(NFMAX,NUMAX), ! velocity and rotation sens. & CRS_U(NFMAX,NUMAX), CNS_U(NFMAX,NUMAX), CMS_U(NFMAX,NUMAX), From 44ed4bbc62c9ad658ba268a0abe2df3b8cf61db1 Mon Sep 17 00:00:00 2001 From: Joshua Anibal Date: Thu, 18 Sep 2025 17:56:41 -0700 Subject: [PATCH 2/2] api tweaks --- docs/making_a_script.md | 40 ++- docs/optimization_setup_om.md | 2 +- docs/optimization_setup_scipy.md | 34 +-- docs/optvl_api.md | 6 +- docs/pyavl_changes.md | 2 +- examples/plot_aircraft.py | 2 +- examples/plot_planform_results.py | 2 +- examples/plot_sectional_data.py | 8 +- examples/run_aero_sweeps.py | 12 +- examples/run_analysis_body.py | 2 +- examples/run_basic.py | 11 +- examples/run_body_axis_derivs.py | 2 +- examples/run_modes.py | 2 +- examples/run_opt_clmax.py | 16 +- examples/run_opt_custom_param.py | 2 +- examples/run_opt_scipy.py | 17 +- examples/run_opt_trim_scipy.py | 10 +- examples/run_param_sweep.py | 2 +- examples/run_param_sweep_planform.py | 2 +- examples/run_stability_derivs.py | 4 +- examples/run_write_tecplot.py | 2 +- optvl/om_wrapper.py | 15 +- optvl/optvl_class.py | 241 +++++++++++++++--- tests/test_analysis.py | 39 +-- tests/test_body_axis_derivs.py | 15 +- tests/test_body_axis_derivs_partial_derivs.py | 4 +- ...test_contraints.py => test_constraints.py} | 12 +- tests/test_consurf_partial_derivs.py | 8 +- tests/test_new_subroutines.py | 8 +- tests/test_om_wrapper.py | 4 +- tests/test_partial_derivs.py | 8 +- tests/test_stab_derivs.py | 12 +- tests/test_stab_derivs_partial_derivs.py | 8 +- tests/test_surf_geom.py | 10 +- tests/test_total_derivs.py | 8 +- tools/wheels/cibw_test_command.sh | 2 +- 36 files changed, 379 insertions(+), 195 deletions(-) rename tests/{test_contraints.py => test_constraints.py} (91%) diff --git a/docs/making_a_script.md b/docs/making_a_script.md index 479aaa91..6437bd0d 100644 --- a/docs/making_a_script.md +++ b/docs/making_a_script.md @@ -17,34 +17,48 @@ Like AVL, you can also add a mass file as well. ovl = OVLSolver(geo_file="aircraft.avl", mass_file="aircraft.mass") ``` - -## Constraints +## Setting variables and control deflections After initializing, you can set up various constraints directly. You can set `alpha`, `beta`, `roll rate`, `pitch rate`, and `yaw rate` as well as any control surface in this way. ```python -ovl.set_constraint("alpha", 0.00) +ovl.set_variable("alpha", 0.00) +``` +You can also set the deflection of any control surface for a run. +The control surfaces are specified using the names in the geometry file. +```python +ovl.set_control_deflection("Elevator", 0.00) +``` + +## Setting parameters +You can also set parameters of the run case. +The list of parameters you can set are `CD0`, `bank`, `elevation`, `heading`, `Mach`, `velocity`, `density`, `grav.acc.`, `turn rad.`, `load fac.`, `X cg`, `Y cg`, `Z cg`, `mass`, `Ixx`, `Iyy`, `Izz`, `Ixy`, `Iyz`, `Izx`, `visc CL_a`, `visc CL_u`, `visc Cm_a`, `visc Cm_u`, +```python +# set the flow parameters like mach numbers +ovl.set_parameter("Mach", 0.3) ``` + +## Setting constraints You can also set a variable in order to meet a specific constraint value. -The valid constraint options are `CL`, `CY`, `Cl roll moment`, `Cm pitch moment`, `Cn yaw moment`. +The valid constraint options are `CL`, `CY`, `Cl`, `Cm`, `Cn`. +The roll moment coefficients have lower case letters just like in AVL. + +!!! Warning + Note the difference in capitalization between the coefficient of lift, CL, and the roll moment coefficient, `Cl`. !!! Warning - Be careful to state a constraint variable, `con_var`, that is affected by the input. For example if you accidentally specify that the pitching moment should be trimmed by the rudder the analysis will not converge. + Be careful to state a constraint variable that is affected by the input. For example if you accidentally specify that the pitching moment should be trimmed by the rudder the analysis will not converge. ```python # set the Elevator to trim Cm to zero -ovl.set_constraint("Elevator", 0.00, con_var="Cm pitch moment") +ovl.set_constraint("alpha", "CL", 0.5) +# set the Elevator to trim Cm to zero +ovl.set_constraint("Elevator", "Cm", 0.00) # set the Rudder to trim Cn to zero -ovl.set_constraint("Rudder", 0.00, con_var="Cn yaw moment") +ovl.set_constraint("Rudder", "Cn", 0.00) ``` -You can also set parameters of the run case. -The list of parameters you can set are `CD0`, `bank`, `elevation`, `heading`, `Mach`, `velocity`, `density`, `grav.acc.`, `turn rad.`, `load fac.`, `X cg`, `Y cg`, `Z cg`, `mass`, `Ixx`, `Iyy`, `Izz`, `Ixy`, `Iyz`, `Izx`, `visc CL_a`, `visc CL_u`, `visc CM_a`, `visc CM_u`, -```python -# set the flow parameters like mach numbers -ovl.set_parameter("Mach", 0.3) -``` ## Running Analysis diff --git a/docs/optimization_setup_om.md b/docs/optimization_setup_om.md index 3e27a06b..f140d4a0 100644 --- a/docs/optimization_setup_om.md +++ b/docs/optimization_setup_om.md @@ -25,7 +25,7 @@ To turn on other inputs such as the reference values and case parameters, use th ```python model.add_subsystem("ovlsolver", OVLGroup(geom_file="aircraft.avl",input_param_vals=True, input_ref_vals=True)) ``` -The force coefficients such as `CL`, `CD`, and `CM` are automatically added as outputs. +The force coefficients such as `CL`, `CD`, and `Cm` are automatically added as outputs. To add stability derivatives or control surface derivatives as outputs, just use the `output_stability_derivs` and `output_con_surf_derivs` keyword arguments to the group to turn them on. ```python model.add_subsystem("ovlsolver", OVLGroup(geom_file="aircraft.avl", output_stability_derivs=True, output_con_surf_derivs=True)) diff --git a/docs/optimization_setup_scipy.md b/docs/optimization_setup_scipy.md index 3ffc008d..bb54c30a 100644 --- a/docs/optimization_setup_scipy.md +++ b/docs/optimization_setup_scipy.md @@ -8,34 +8,24 @@ To use SciPy's SLSQP, we will need to supply it with custom objective and constr These functions need to take in the design variables and apply them to our OptVL solver. The snippet below provides an example of an objective function. ```python - def objective_function(x): - ovl.set_constraint("Elevator", x[0]) - ovl.set_surface_params({"Wing":{"aincs":x[1:]}}) - - ovl.execute_run() - cd = ovl.get_total_forces()['CD'] - print(x, cd) - - return cd +{% + include-markdown "../examples/run_opt_scipy.py" + start="# obj-start" + end="# obj-end" +%} ``` + Note: the objective function is specified by the return value of the function. If you wanted to save data about each iteration or write output, the objective function would be a good place to add that functionality. To supply the gradient information to SLSQP, we have to define another function that returns the gradients for a given design variable vector. ```python -def objective_gradient(x): - # Partial derivatives of the objective_function - ovl.set_constraint("Elevator", x[0]) - ovl.set_surface_params({"Wing":{"aincs":x[1:]}}) - - ovl.execute_run() - - sens = ovl.execute_run_sensitivities(['CD']) - dcd_dele = sens['CD']['Elevator'] - dcd_daincs = sens['CD']['Wing']['aincs'] - - # concatinate the two and return the derivs - return np.concatenate(([dcd_dele], dcd_daincs)) +{% + include-markdown "../examples/run_opt_scipy.py" + start="# objgrad-start" + end="# objgrad-end" +%} ``` + The function `ovl.execute_run_sensitivities(['CD'])` does all the necessary work to compute the derivatives for the given list of functions. We just need to parse the `sens` dictionary for the derivatives with respect to the design variables we are interested in. diff --git a/docs/optvl_api.md b/docs/optvl_api.md index c70d07fe..668629be 100644 --- a/docs/optvl_api.md +++ b/docs/optvl_api.md @@ -41,9 +41,9 @@ The commands from the oper and mode menus are available |action| AVL's "OPER" command| OptVL API call| |-----|--|--| -|setting the angle of attack|a a | ovl.set_constraint("alpha", )| -| set variable such that constraint = val | | ovl.set_constraint(, , con_var=) | -| set CL constraint| c1; c 1.3| ovl.set_trim_condition("CL", 1.3)| +|setting the angle of attack|a a | ovl.set_variable("alpha", )| +| set variable such that constraint = val | | ovl.set_constraint(, , ) | +| set CL constraint| c1; c 1.3| ovl.set_constraint("alpha","CL", ) or ovl.set_trim_condition("CL", 1.3)| | run an analysis | x | ovl.execute_run() | | after an analysis | FT | ovl.get_total_forces() | | get strip force data | ST | ovl.get_strip_forces() | diff --git a/docs/pyavl_changes.md b/docs/pyavl_changes.md index 316b5155..937218ff 100644 --- a/docs/pyavl_changes.md +++ b/docs/pyavl_changes.md @@ -18,7 +18,7 @@ The table below lists the changes. | `set_case_parameter` | `set_parameter` | | `get_case_constraint` | `get_constraint` | | `get_strip_data` | `get_strip_forces` | -| `add_constraint` | `set_constraint` | +| `add_constraint` | split into `set_constraint`, `set_variable`, `set_control_deflection`| | `add_trim_condition` | `set_trim_condition` | | `executeRun` | use `execute_run` instead | diff --git a/examples/plot_aircraft.py b/examples/plot_aircraft.py index d47b2716..8a0c738c 100644 --- a/examples/plot_aircraft.py +++ b/examples/plot_aircraft.py @@ -6,7 +6,7 @@ ovl_solver = OVLSolver(geo_file="aircraft.avl", debug=False) ovl_solver.plot_geom() -ovl_solver.set_constraint("alpha", 5.00) +ovl_solver.set_variable("alpha", 5.00) ovl_solver.execute_run() ovl_solver.plot_cp() diff --git a/examples/plot_planform_results.py b/examples/plot_planform_results.py index 02d7138c..aab819d3 100644 --- a/examples/plot_planform_results.py +++ b/examples/plot_planform_results.py @@ -10,7 +10,7 @@ driver_cases = cr.list_cases('driver',out_stream=None) obj_arr = np.zeros(len(driver_cases)) for idx_case in range(len(driver_cases)): - obj_arr[idx_case] = cr.get_case(driver_cases[idx_case])['glide.duration'] + obj_arr[idx_case] = cr.get_case(driver_cases[idx_case])['glide.duration'][0] plt.plot(obj_arr) plt.xlabel('iteration') diff --git a/examples/plot_sectional_data.py b/examples/plot_sectional_data.py index 8491dede..32a22d8b 100644 --- a/examples/plot_sectional_data.py +++ b/examples/plot_sectional_data.py @@ -3,8 +3,8 @@ import matplotlib.pyplot as plt ovl = OVLSolver(geo_file="aircraft.avl", debug=False) -ovl.set_constraint('alpha', 5.0) -ovl.set_constraint('beta', 10.0) +ovl.set_variable('alpha', 5.0) +ovl.set_variable('beta', 10.0) ovl.execute_run() # keys-start @@ -38,8 +38,8 @@ strip_data = ovl.get_strip_forces() for surf_key in strip_data: span_distance = strip_data[surf_key]['Y LE'] - plt.plot(span_distance, strip_data[surf_key]['CN'], color='C0') - plt.plot(span_distance, strip_data[surf_key]['CR'], color='C1') + plt.plot(span_distance, strip_data[surf_key]['Cn'], color='C0') + plt.plot(span_distance, strip_data[surf_key]['Cl'], color='C1') plt.legend(['roll distribution', 'yaw distribution']) plt.title('roll and yaw spanwise data') diff --git a/examples/run_aero_sweeps.py b/examples/run_aero_sweeps.py index 145b296a..ebe6d1eb 100644 --- a/examples/run_aero_sweeps.py +++ b/examples/run_aero_sweeps.py @@ -4,10 +4,10 @@ ovl = OVLSolver(geo_file="aircraft.avl", debug=False) # set the angle of attack -ovl.set_constraint("alpha", 0.00) +ovl.set_variable("alpha", 0.00) # set the deflection of the elevator to trim the pitching moment -ovl.set_constraint("Elevator", 0.00, con_var="Cm pitch moment") +ovl.set_constraint("Elevator", "Cm", 0.00) ovl.set_parameter("Mach", 0.3) @@ -16,26 +16,26 @@ print("----------------- alpha sweep ----------------") print(" Angle Cl Cd Cdi Cdv Cm") for alpha in range(10): - ovl.set_constraint("alpha", alpha) + ovl.set_variable("alpha", alpha) ovl.execute_run() run_data = ovl.get_total_forces() print( f' {alpha:10.6f} {run_data["CL"]:10.6f} {run_data["CD"]:10.6f} {run_data["CDi"]:10.6f} {run_data["CDv"]:10.6f} {run_data["Cm"]:10.6f}' ) -ovl.set_constraint("alpha", 0.00) +ovl.set_variable("alpha", 0.00) print("----------------- beta sweep ----------------") print(" Angle Cl Cd Cdi Cdv Cm") for beta in range(10): - ovl.set_constraint("beta", beta) + ovl.set_variable("beta", beta) ovl.execute_run() run_data = ovl.get_total_forces() print( f' {beta:10.6f} {run_data["CL"]:10.6f} {run_data["CD"]:10.6f} {run_data["CDi"]:10.6f} {run_data["CDv"]:10.6f} {run_data["Cm"]:10.6f}' ) -ovl.set_constraint("beta", 0.00) +ovl.set_variable("beta", 0.00) print("----------------- Mach sweep ----------------") print(" Mach Cl Cd Cdi Cdv Cm") diff --git a/examples/run_analysis_body.py b/examples/run_analysis_body.py index 16d0e397..4fa74357 100644 --- a/examples/run_analysis_body.py +++ b/examples/run_analysis_body.py @@ -8,7 +8,7 @@ print("----------------- alpha sweep ----------------") print(" Angle Cl Cd Cdi Cdv Cm") for alpha in range(10): - ovl_solver.set_constraint("alpha", alpha) + ovl_solver.set_variable("alpha", alpha) ovl_solver.execute_run() run_data = ovl_solver.get_total_forces() print( diff --git a/examples/run_basic.py b/examples/run_basic.py index 12033efb..23e594d1 100644 --- a/examples/run_basic.py +++ b/examples/run_basic.py @@ -1,17 +1,20 @@ from optvl import OVLSolver -ovl = OVLSolver(geo_file="aircraft.avl", debug=False) +ovl = OVLSolver(geo_file="aircraft.avl") # look at the geometry to see that everything is right ovl.plot_geom() # set the angle of attack -ovl.set_constraint("alpha", 0.00) +ovl.set_variable("alpha", 1.23) +# modify the mach number +ovl.set_parameter("Mach", 0.3) # set the deflection of the elevator to trim the pitching moment -ovl.set_constraint("Elevator", 0.00, con_var="Cm pitch moment") +ovl.set_constraint("Elevator", "Cm", 0.00) + +ovl.set_control_deflection("Elevator", 10.0) -ovl.set_parameter("Mach", 0.3) # This is the method that acutally runs the analysis ovl.execute_run() diff --git a/examples/run_body_axis_derivs.py b/examples/run_body_axis_derivs.py index 13059f07..ff6031eb 100644 --- a/examples/run_body_axis_derivs.py +++ b/examples/run_body_axis_derivs.py @@ -2,7 +2,7 @@ ovl_solver = OVLSolver(geo_file="aircraft.avl", debug=False) alpha = 3.0 -ovl_solver.set_constraint("alpha", alpha) +ovl_solver.set_variable("alpha", alpha) ovl_solver.execute_run() derivs = ovl_solver.get_body_axis_derivs() diff --git a/examples/run_modes.py b/examples/run_modes.py index 390c3551..5cf72259 100644 --- a/examples/run_modes.py +++ b/examples/run_modes.py @@ -12,7 +12,7 @@ weight = mass * g cl = weight / (0.5 * dens * vel**2) ovl.set_trim_condition("CL", cl) -ovl.set_constraint("Elevator", 0.00, con_var="Cm pitch moment") +ovl.set_constraint("Elevator", "Cm", 0.00) ovl.execute_eigen_mode_calc() diff --git a/examples/run_opt_clmax.py b/examples/run_opt_clmax.py index 30304fb4..ff05f285 100644 --- a/examples/run_opt_clmax.py +++ b/examples/run_opt_clmax.py @@ -27,9 +27,9 @@ def objective_function(dvs): Scipy's minimize function tries to minimize this value. """ alpha = dvs[0] - ovl_solver.set_constraint("alpha", alpha) + ovl_solver.set_variable("alpha", alpha) def_elev = dvs[1] - ovl_solver.set_constraint("Elevator", def_elev) + ovl_solver.set_control_deflection("Elevator", def_elev) ovl_solver.execute_run() @@ -46,9 +46,9 @@ def cl_con(dvs): Returns a value >= 0 if the constraint is met (1.75 - max_cl_sectional). """ alpha = dvs[0] - ovl_solver.set_constraint("alpha", alpha) + ovl_solver.set_variable("alpha", alpha) def_elev = dvs[1] - ovl_solver.set_constraint("Elevator", def_elev) + ovl_solver.set_control_deflection("Elevator", def_elev) ovl_solver.execute_run() strip_forces = ovl_solver.get_strip_forces() @@ -62,9 +62,9 @@ def cl_con(dvs): def cm_con(dvs): alpha = dvs[0] - ovl_solver.set_constraint("alpha", alpha) + ovl_solver.set_variable("alpha", alpha) def_elev = dvs[1] - ovl_solver.set_constraint("Elevator", def_elev) + ovl_solver.set_control_deflection("Elevator", def_elev) ovl_solver.execute_run() cm = ovl_solver.get_total_forces()['Cm'] @@ -106,8 +106,8 @@ def cm_con(dvs): # Verification run at the optimized alpha to double-check AVL results print("\nVerification run at optimized alpha:") -ovl_solver.set_constraint("alpha", optimized_alpha) -ovl_solver.set_constraint("Elevator", optimized_def_elev) +ovl_solver.set_variable("alpha", optimized_alpha) +ovl_solver.set_control_deflection("Elevator", optimized_def_elev) # Recalculate max sectional Cl at the optimal alpha for verification diff --git a/examples/run_opt_custom_param.py b/examples/run_opt_custom_param.py index e4ed8020..1414af5e 100644 --- a/examples/run_opt_custom_param.py +++ b/examples/run_opt_custom_param.py @@ -97,4 +97,4 @@ def compute(self, inputs, outputs): # prob.check_totals() -prob.model.ovlsolver.solver.avl.write_geom_file('opt_airplane.avl') +prob.model.ovlsolver.solver.ovl.write_geom_file('opt_airplane.avl') diff --git a/examples/run_opt_scipy.py b/examples/run_opt_scipy.py index bcac2c5f..10cf8b67 100644 --- a/examples/run_opt_scipy.py +++ b/examples/run_opt_scipy.py @@ -8,9 +8,10 @@ # setup OptVL ovl_solver.set_parameter("Mach", 0.0) +# obj-start # Define your custom objective function with outputs from OptVL def objective_function(x): - ovl_solver.set_constraint("Elevator", x[0]) + ovl_solver.set_control_deflection("Elevator", x[0]) ovl_solver.set_surface_params({"Wing":{"aincs":x[1:]}}) ovl_solver.execute_run() @@ -18,14 +19,15 @@ def objective_function(x): print(x, cd) return cd - +# obj-end +# objgrad-start def objective_gradient(x): # Partial derivatives of the objective_function # we are trusting that the design variables have already been applied # and propogated through by the objective_function. - ovl_solver.set_constraint("Elevator", x[0]) + ovl_solver.set_control_deflection("Elevator", x[0]) ovl_solver.set_surface_params({"Wing":{"aincs":x[1:]}}) ovl_solver.execute_run() @@ -36,11 +38,12 @@ def objective_gradient(x): # concatinate the two and return the derivs return np.concatenate(([dcd_dele], dcd_daincs)) +# objgrad-end - +# eq-start # Define equality constraint: h(x) = 0 def eq_constraint(x): - ovl_solver.set_constraint("Elevator", x[0]) + ovl_solver.set_control_deflection("Elevator", x[0]) ovl_solver.set_surface_params({"Wing":{"aincs":x[1:]}}) ovl_solver.execute_run() @@ -55,7 +58,8 @@ def eq_constraint(x): cm_con = coeff['Cm'] - cm_target return np.array([cl_con, cm_con]) - +# eq-end +# eqgrad-start # Define the gradient of the equality constraint def eq_constraint_jac(x): sens = ovl_solver.execute_run_sensitivities(['CL', 'Cm']) @@ -69,6 +73,7 @@ def eq_constraint_jac(x): # concatinate the two and return the derivs return np.array([dcl_dx, dcm_dx]) +# eqgrad-end num_sec = 5 # Initial guess for the variables diff --git a/examples/run_opt_trim_scipy.py b/examples/run_opt_trim_scipy.py index 28d6981d..29f27bc1 100644 --- a/examples/run_opt_trim_scipy.py +++ b/examples/run_opt_trim_scipy.py @@ -7,12 +7,12 @@ # setup OptVL ovl_solver.set_parameter("Mach", 0.0) -# ovl_solver.set_constraint("alpha", 5.0) +# ovl_solver.set_variable("alpha", 5.0) # Define your custom objective function with outputs from OptVL def custom_function(x): - ovl_solver.set_constraint("Elevator", x[0]) - ovl_solver.set_constraint("alpha", x[1]) + ovl_solver.set_control_deflection("Elevator", x[0]) + ovl_solver.set_variable("alpha", x[1]) ovl_solver.execute_run() cd = ovl_solver.get_total_forces()['CD'] @@ -31,8 +31,8 @@ def custom_gradient(x): cm_target = 0.0 # Define equality constraint: h(x) = 0 def eq_constraint(x): - ovl_solver.set_constraint("Elevator", x[0]) - ovl_solver.set_constraint("alpha", x[1]) + ovl_solver.set_control_deflection("Elevator", x[0]) + ovl_solver.set_variable("alpha", x[1]) ovl_solver.execute_run() # the objective must always be run first diff --git a/examples/run_param_sweep.py b/examples/run_param_sweep.py index c2923c8e..4853a3d4 100644 --- a/examples/run_param_sweep.py +++ b/examples/run_param_sweep.py @@ -6,7 +6,7 @@ ovl_solver = OVLSolver(geo_file="aircraft.avl", debug=False, timing=False) # set the angle of attack -ovl_solver.set_constraint("alpha", 5.00) +ovl_solver.set_variable("alpha", 5.00) for idx_scale, y_scale in enumerate(np.linspace(0.5, 1.5, 5)): ovl_solver.set_surface_params({"Wing":{"scale":np.array([1, y_scale, 1])}}) diff --git a/examples/run_param_sweep_planform.py b/examples/run_param_sweep_planform.py index 035c218e..dc5ea6e7 100644 --- a/examples/run_param_sweep_planform.py +++ b/examples/run_param_sweep_planform.py @@ -7,7 +7,7 @@ ovl_solver = OVLSolver(geo_file="rectangle.avl", debug=False, timing=False) # set the angle of attack -# ovl_solver.set_constraint("alpha", 5.00) +# ovl_solver.set_variable("alpha", 5.00) yles = ovl_solver.get_surface_param('Wing', 'yles') xles = ovl_solver.get_surface_param('Wing', 'xles') zles = ovl_solver.get_surface_param('Wing', 'zles') diff --git a/examples/run_stability_derivs.py b/examples/run_stability_derivs.py index 9a2a9d15..cb9eb655 100644 --- a/examples/run_stability_derivs.py +++ b/examples/run_stability_derivs.py @@ -3,14 +3,14 @@ ovl_solver = OVLSolver(geo_file="aircraft.avl", debug=False) alpha = 3.0 -ovl_solver.set_constraint("alpha", alpha) +ovl_solver.set_variable("alpha", alpha) ovl_solver.execute_run() run_data = ovl_solver.get_total_forces() stab_derivs = ovl_solver.get_stab_derivs() print('stability deriv', stab_derivs['dCL/dalpha']) step = 1e-6 -ovl_solver.set_constraint("alpha", alpha + step) +ovl_solver.set_variable("alpha", alpha + step) ovl_solver.execute_run() run_data_p = ovl_solver.get_total_forces() print("fd", (run_data_p["CL"] - run_data["CL"]) / step) diff --git a/examples/run_write_tecplot.py b/examples/run_write_tecplot.py index 1ec92abd..eeeca464 100644 --- a/examples/run_write_tecplot.py +++ b/examples/run_write_tecplot.py @@ -3,6 +3,6 @@ import matplotlib.pyplot as plt ovl_solver = OVLSolver(geo_file="aircraft.avl", debug=False) -ovl_solver.set_constraint("alpha", 5.00) +ovl_solver.set_variable("alpha", 5.00) ovl_solver.execute_run() ovl_solver.write_tecplot('test') \ No newline at end of file diff --git a/optvl/om_wrapper.py b/optvl/om_wrapper.py index cfb4738e..4a173fc3 100644 --- a/optvl/om_wrapper.py +++ b/optvl/om_wrapper.py @@ -154,10 +154,10 @@ def om_surf_dict_to_input(surf_dict): def om_set_avl_inputs(sys, inputs): for c_name in sys.control_names: - sys.ovl.set_constraint(c_name, inputs[c_name][0]) + sys.ovl.set_control_deflection(c_name, inputs[c_name][0]) - sys.ovl.set_constraint("alpha", inputs["alpha"][0]) - sys.ovl.set_constraint("beta", inputs["beta"][0]) + sys.ovl.set_variable("alpha", inputs["alpha"][0]) + sys.ovl.set_variable("beta", inputs["beta"][0]) # add the parameters to the run for param in sys.ovl.param_idx_dict: @@ -424,9 +424,6 @@ def setup(self): def compute(self, inputs, outputs): # self.ovl.set_gamma(inputs['gamma']) - # for c_name in self.control_names: - # self.ovl.set_constraint(c_name, inputs[c_name][0]) - # def_dict = self.ovl.get_control_deflections() # TODO: set_constraint does not correctly do derives yet start_time = time.time() @@ -567,7 +564,7 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): for func_key in self.ovl.case_stab_derivs_to_fort_var: if func_key in d_outputs: stab_derivs_seeds[func_key] = d_outputs[func_key] - + if np.abs(stab_derivs_seeds[func_key]) > 0.0: # print(var_name, stab_derivs_seeds[func_key]) print(f' running rev mode derivs for {func_key}') @@ -576,6 +573,7 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): for func_key in self.ovl.case_body_derivs_to_fort_var: if func_key in d_outputs: body_axis_seeds[func_key] = d_outputs[func_key] + print(func_key, type(body_axis_seeds[func_key])) if np.abs(body_axis_seeds[func_key]) > 0.0: # print(var_name, body_axis_seeds[func_key]) @@ -656,9 +654,6 @@ def setup(self): def compute(self, inputs, outputs): # self.ovl.set_gamma(inputs['gamma']) - # for c_name in self.control_names: - # self.ovl.set_constraint(c_name, inputs[c_name][0]) - # def_dict = self.ovl.get_control_deflections() om_set_avl_inputs(self, inputs) diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 3273724b..ac1299cd 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -14,6 +14,7 @@ import glob from typing import Optional import platform +from collections import OrderedDict # ============================================================================= # External Python modules @@ -267,9 +268,11 @@ def __init__(self, geo_file:str, mass_file: Optional[str]=None, debug:Optional[b control_names = self.get_control_names() - self.control_variables = {} + self.dindex_to_con_surf = OrderedDict() + self.con_surf_to_dindex = OrderedDict() for idx_c_var, c_name in enumerate(control_names): - self.control_variables[c_name] = f"D{idx_c_var+1}" + self.dindex_to_con_surf[f"D{idx_c_var+1}"] = c_name + self.con_surf_to_dindex[c_name] = f"D{idx_c_var+1}" # set control surface constraint indecies in to con val dict idx_control_start = np.max([x for x in self.conval_idx_dict.values()]) + 1 @@ -312,7 +315,7 @@ def __init__(self, geo_file:str, mass_file: Optional[str]=None, debug:Optional[b # for var in var_to_suffix: for idx_var, var in enumerate(["u","v", "w", "p", "q", "r"]): deriv_key =self._get_deriv_key(var, func) - self.case_body_derivs_to_fort_var[deriv_key] = ["CASE_R", f"{func_to_prefix[func]}TOT_U_BA", (idx_var,)] + self.case_body_derivs_to_fort_var[deriv_key] = ["CASE_R", f"{func_to_prefix[func]}TOT_U_BA", idx_var] # the case parameters are stored in a 1d array, # these indices correspond to the position of each parameter in that arra @@ -446,14 +449,112 @@ def execute_run(self, tol:float=0.00002): """ self.set_avl_fort_arr('CASE_R', 'EXEC_TOL', tol) self.avl.oper() + + def set_variable(self, var:str, val:float): + """set a variable for the run case (equivalent to setting a variable in AVL's OPER menu) + Args: + var: variable to be constrained ["alpha"", "beta"", "roll rate", "pitch rate", "yaw rate"] or any control surface. + val: target value of `con_var` + """ + avl_variables = { + "alpha": ("CASE_R","ALFA"), + "beta": ("CASE_R","BETA"), + "roll rate": ("CASE_R","WROT", 0), + "pitch rate": ("CASE_R","WROT", 1), + "yaw rate": ("CASE_R","WROT", 2), + } + ref_data = self.get_reference_data() + dtr = self.get_avl_fort_arr("CASE_R", "DTR") + bref = ref_data['Bref'] + cref = ref_data['Cref'] + + vars_factors = { + "alpha": dtr, + "beta": dtr, + "roll rate": 2/bref, + "pitch rate": 2/cref, + "yaw rate": 2/bref, + } + + + + + if var in avl_variables: + # save the name of the avl_var 0 + avl_var = avl_variables[var] + else: + raise ValueError( + f"specified variable `{var}` not a valid option. Must be one of the following variables{[key for key in avl_variables]} or control surface name or index{[item for item in self.con_surf_to_dindex.items()]}. Constraints that must be implicitly satisfied (such as `CL`) are set with `add_trim_constraint`." + ) + + # check that the type of val is correct + if isinstance(val, (int, float, np.floating, np.integer)): + pass + elif isinstance(val, np.ndarray): + if val.size != 1: + raise TypeError(f"variable value must be can only be an np.ndarray if it has size = 1. Got {val}") + else: + raise TypeError(f"variable value must be a int or float for contraint {var}. Got {val}") + + slicer = (avl_var[2],) if len(avl_var) == 3 else None + self.set_avl_fort_arr(avl_var[0], avl_var[1], val*vars_factors[var], slicer) + + # set the contraint value so that the set value is used in analysis + self.set_avl_fort_arr("CASE_R", "CONVAL", val, (self.conval_idx_dict[var],)) + + + def get_variable(self, var:str): + """set a variable for the run case (equivalent to setting a variable in AVL's OPER menu) + Args: + var: variable to be constrained ["alpha"", "beta"", "roll rate", "pitch rate", "yaw rate"] or any control surface. + val: target value of `con_var` + """ + avl_variables = { + "alpha": ("CASE_R","ALFA"), + "beta": ("CASE_R","BETA"), + "roll rate": ("CASE_R","WROT", 0), + "pitch rate": ("CASE_R","WROT", 1), + "yaw rate": ("CASE_R","WROT", 2), + } + + ref_data = self.get_reference_data() + dtr = self.get_avl_fort_arr("CASE_R", "DTR") + bref = ref_data['Bref'] + cref = ref_data['Cref'] + + vars_factors = { + "alpha": dtr, + "beta": dtr, + "roll rate": 2/bref, + "pitch rate": 2/cref, + "yaw rate": 2/bref, + } + + + # Check that the variable is valid + if var in avl_variables: + # save the name of the avl_var + var_key = avl_variables[var] + else: + raise ValueError( + f"specified variable `{var}` not a valid option. Must be one of the following variables{[key for key in avl_variables]} or control surface name or index{[item for item in self.con_surf_to_dindex.items()]}." + ) + + slicer = var_key[2] if len(var_key) == 3 else None + + val = copy.deepcopy(self.get_avl_fort_arr(var_key[0], var_key[1],slicer)) + val /= vars_factors[var] + + return val + - def set_constraint(self, var:str, val:float, con_var:str=None): - """Set the constraints on the analysis case (equivalent to setting a variable in AVL's OPER menu) + def set_constraint(self, var:str, con_var:str, val:float): + """Set the constraints on the analysis case (equivalent to setting a constraint in AVL's OPER menu) Args: var: variable to be constrained ["alpha"", "beta"", "roll rate", "pitch rate", "yaw rate"] or any control surface. val: target value of `con_var` - con_var: variable output that needs to be constrained. It could be any value for `var` plus ["CL", "CY", "Cl roll moment", "Cm pitch moment", "Cn yaw moment"]. If None, than `var` is also the `con_var` + con_var: variable output that needs to be constrained. It could be any value for `var` plus ["CL", "CY", "Cl", "Cm", "Cn"]. If None, than `var` is also the `con_var` """ avl_variables = { @@ -469,35 +570,35 @@ def set_constraint(self, var:str, val:float, con_var:str=None): { "CL": "C ", "CY": "S ", - "Cl roll moment": "RM", - "Cm pitch moment":"PM", - "Cn yaw moment": "YM", + "Cl": "RM", + "Cm":"PM", + "Cn": "YM", } ) if var in avl_variables: # save the name of the avl_var avl_var = avl_variables[var] - elif var in self.control_variables.keys(): - avl_var = self.control_variables[var] - elif var in self.control_variables.values(): + elif var in self.con_surf_to_dindex: + avl_var = self.con_surf_to_dindex[var] + elif var in self.dindex_to_con_surf: avl_var = var else: raise ValueError( - f"specified variable `{var}` not a valid option. Must be one of the following variables{[key for key in avl_variables]} or control surface name or index{[item for item in self.control_variables.items()]}. Constraints that must be implicitly satisfied (such as `CL`) are set with `add_trim_constraint`." + f"specified key `{var}` not a valid option. Must be one of the following variables{[key for key in avl_variables]} or control surface name or index{[item for item in self.con_surf_to_dindex.items()]}." ) if con_var is None: avl_con_var = avl_var elif con_var in avl_con_variables: avl_con_var = avl_con_variables[con_var] - elif con_var in self.control_variables.keys(): - avl_con_var = self.control_variables[con_var] - elif con_var in self.control_variables.values(): + elif con_var in self.con_surf_to_dindex: + avl_con_var = self.con_surf_to_dindex[con_var] + elif con_var in self.dindex_to_con_surf: avl_con_var = con_var else: raise ValueError( - f"specified contraint variable `{con_var}` not a valid option. Must be one of the following variables{[key for key in avl_variables]} or control surface name or index{[item for item in self.control_variables.items()]}." + f"specified contraint variable `{con_var}` not a valid option. Must be one of the following variables{[key for key in avl_variables]} or control surface name or index{[item for item in self.con_surf_to_dindex.items()]}." ) # check that the type of val is correct @@ -657,7 +758,7 @@ def set_avl_fort_arr(self, common_block:str, variable:str, val:float, slicer:Opt slicer: slice applied to the common block variable to return a subset of the data. i.e. (100) or slice(2, 5) """ - # convert from fortran ordering to c ordering + # convert from c ordering to fortran ordering if isinstance(val, np.ndarray): val = val.ravel(order="C").reshape(val.shape[::-1], order="F") @@ -670,11 +771,24 @@ def set_avl_fort_arr(self, common_block:str, variable:str, val:float, slicer:Opt if slicer is None: setattr(common_block_obj, variable.upper(), val) else: - # flip the order of the slicer to match the cordinates of the val - new_slicer = slicer[::-1] + if isinstance(slicer, int): + if isinstance(val, np.ndarray): + if val.size == 1: + # convert it to a float + fort_val = val.flatten()[0] + else: + raise ValueError(f"slicer {slicer} is integer, but value {val} isn't size 1" ) + else: + fort_val = val + else: + # the slicer is multidimensional + # flip the order of the slicer to match the cordinates of the val + slicer = slicer[::-1] + fort_val = val + original_val = getattr(common_block_obj, variable.upper()) - original_val[new_slicer] = val + original_val[slicer] = fort_val setattr(common_block_obj, variable.upper(), original_val) return @@ -783,7 +897,55 @@ def get_control_deflections(self) -> Dict[str, float]: def_dict[con_surf] = def_arr[idx_con] return def_dict + + def get_control_deflection(self, con_surf) -> Dict[str, float]: + """get the deflections of the control surfaces + + Returns: + val: deflection of control surface + """ + control_surfaces = self.get_control_names() + idx_surf = control_surfaces.index(con_surf) + + def_arr = copy.deepcopy(self.get_avl_fort_arr("CASE_R", "DELCON")) + val = def_arr[idx_surf] + + return val + + def set_control_deflection(self, con_surf, val) -> Dict[str, float]: + """set the deflections of the control surfaces + + args: + con_surf : Name or D value (D1, D2, etc.) of the control surface + """ + con_surf_names = list(self.con_surf_to_dindex.keys()) + con_surf_dindex = list(self.dindex_to_con_surf.keys()) + + if con_surf in con_surf_names: + idx_con_surf = con_surf_names.index(con_surf) + elif con_surf in con_surf_dindex: + idx_con_surf = con_surf_dindex.index(con_surf) + con_surf = self.dindex_to_con_surf[con_surf] + + vars_idx = self.conval_idx_dict[con_surf] + + self.set_avl_fort_arr("CASE_R", "CONVAL", val, (vars_idx,)) + self.set_avl_fort_arr("CASE_R", "DELCON", val, slicer=(idx_con_surf,)) + + def set_control_deflections(self, def_dict:Dict[str, float]): + """get the deflections of all the control surfaces + + args: + def_dict: dictionary of control surfaces as the keys and deflections as the values + """ + control_surfaces = self.get_control_names() + + for con in def_dict: + idx_con = control_surfaces.index(con) + self.set_avl_fort_arr("CASE_R", "DELCON", def_dict[con], slicer=idx_con) + + def get_hinge_moments(self) -> Dict[str, float]: """get the hinge moments from the fortran layer and return them as a dictionary @@ -830,9 +992,9 @@ def get_strip_forces(self) -> Dict[str, Dict[str, np.ndarray]]: "CZ": ["STRP_R", "CZSTRP"], # strip contributions to total moments (body frame) - "Cl": ["STRP_R", "CRSTRP"], - "Cm": ["STRP_R", "CMSTRP"], - "Cn": ["STRP_R", "CNSTRP"], + "Cl": ["STRP_R", "CRSTRP"], # previously CR + "Cm": ["STRP_R", "CMSTRP"], # previously CM + "Cn": ["STRP_R", "CNSTRP"], # previously CN # forces non-dimentionalized by strip quantities @@ -847,6 +1009,8 @@ def get_strip_forces(self) -> Dict[str, Dict[str, np.ndarray]]: "Cm LE" : ["STRP_R","CMLE"], # strip pitching moment about LE vector "spanloading" : ["STRP_R","CNC"], # strip spanloading + # TODO: add + # & CF_STRP(3,NSMAX), CM_STRP(3,NSMAX), ! strip forces in body axes referenced to strip area and 1/4 chord } # fmt: on @@ -1596,7 +1760,7 @@ def _get_deriv_key(self, var: str, func : str) -> str: # --------------------------- # --- input ad seeds --- - def get_constraint_ad_seeds(self) -> Dict[str, float]: + def get_variable_ad_seeds(self) -> Dict[str, float]: con_seeds = {} for con in self.con_var_to_fort_var: idx_con = self.conval_idx_dict[con] @@ -1609,7 +1773,7 @@ def get_constraint_ad_seeds(self) -> Dict[str, float]: return con_seeds - def set_constraint_ad_seeds(self, con_seeds: Dict[str, Dict[str, float]], mode: str = "AD", scale=1.0) -> None: + def set_variable_ad_seeds(self, con_seeds: Dict[str, Dict[str, float]], mode: str = "AD", scale=1.0) -> None: for con in con_seeds: # determine the proper index @@ -1628,14 +1792,19 @@ def set_constraint_ad_seeds(self, con_seeds: Dict[str, Dict[str, float]], mode: self.set_avl_fort_arr(blk, var, val, slicer=slicer) elif mode == "FD": - # reverse lookup in the con_var_to_fort_var dict - - val = self.get_constraint(con) + # # reverse lookup in the con_var_to_fort_var dict + if con in self.con_surf_to_dindex: + val = self.get_control_deflection(con) + else: + val = self.get_variable(con) val += con_seed_arr * scale - # use the contraint API to adjust the value - self.set_constraint(con, val) + if con in self.con_surf_to_dindex: + self.set_control_deflection(con, val) + else: + self.set_variable(con, val) + def set_parameter_ad_seeds(self, parm_seeds: Dict[str, float], mode: str = "AD", scale=1.0) -> None: for param_key in parm_seeds: @@ -2067,7 +2236,7 @@ def _execute_jac_vec_prod_fwd( if mode == "AD": # set derivative seeds # self.clear_ad_seeds() - self.set_constraint_ad_seeds(con_seeds) + self.set_variable_ad_seeds(con_seeds) self.set_geom_ad_seeds(geom_seeds) self.set_gamma_ad_seeds(gamma_seeds) self.set_gamma_d_ad_seeds(gamma_d_seeds) @@ -2089,7 +2258,7 @@ def _execute_jac_vec_prod_fwd( res_d_seeds = self.get_residual_d_ad_seeds() res_u_seeds = self.get_residual_u_ad_seeds() - self.set_constraint_ad_seeds(con_seeds, scale=0.0) + self.set_variable_ad_seeds(con_seeds, scale=0.0) self.set_geom_ad_seeds(geom_seeds, scale=0.0) self.set_gamma_ad_seeds(gamma_seeds, scale=0.0) self.set_gamma_d_ad_seeds(gamma_d_seeds, scale=0.0) @@ -2101,7 +2270,7 @@ def _execute_jac_vec_prod_fwd( self.set_avl_fort_arr("VRTX_R_DIFF", "GAM_DIFF", gamma_seeds * 0.0, slicer=res_slice) if mode == "FD": - self.set_constraint_ad_seeds(con_seeds, mode="FD", scale=step) + self.set_variable_ad_seeds(con_seeds, mode="FD", scale=step) self.set_geom_ad_seeds(geom_seeds, mode="FD", scale=step) self.set_gamma_ad_seeds(gamma_seeds, mode="FD", scale=step) self.set_gamma_d_ad_seeds(gamma_d_seeds, mode="FD", scale=step) @@ -2125,7 +2294,7 @@ def _execute_jac_vec_prod_fwd( res_u_peturbed = copy.deepcopy(self.get_avl_fort_arr("VRTX_R", "RES_U", slicer=res_u_slice)) - self.set_constraint_ad_seeds(con_seeds, mode="FD", scale=-1 * step) + self.set_variable_ad_seeds(con_seeds, mode="FD", scale=-1 * step) self.set_geom_ad_seeds(geom_seeds, mode="FD", scale=-1 * step) self.set_gamma_ad_seeds(gamma_seeds, mode="FD", scale=-1 * step) self.set_gamma_d_ad_seeds(gamma_d_seeds, mode="FD", scale=-1 * step) @@ -2271,7 +2440,7 @@ def _execute_jac_vec_prod_rev( time_last = time.time() # extract derivatives seeds and set the output dict of functions - con_seeds = self.get_constraint_ad_seeds() + con_seeds = self.get_variable_ad_seeds() geom_seeds = self.get_geom_ad_seeds() gamma_seeds = self.get_gamma_ad_seeds() gamma_d_seeds = self.get_gamma_d_ad_seeds() diff --git a/tests/test_analysis.py b/tests/test_analysis.py index 768d3816..c322d8a3 100644 --- a/tests/test_analysis.py +++ b/tests/test_analysis.py @@ -25,8 +25,8 @@ def setUp(self): self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file, timing=False, debug=False) def test_constrained_alpha_sweep(self): - self.ovl_solver.set_constraint("Elevator", 0.00, con_var="Cm pitch moment") - self.ovl_solver.set_constraint("Rudder", 0.00, con_var="Cn yaw moment") + self.ovl_solver.set_constraint("Elevator", "Cm", 0.00, ) + self.ovl_solver.set_constraint("Rudder", "Cn", 0.00, ) alpha_array = np.arange(0, 10) cl_ref_arr = np.array( @@ -58,7 +58,7 @@ def test_constrained_alpha_sweep(self): ] ) for idx_alpha, alpha in enumerate(alpha_array): - self.ovl_solver.set_constraint("alpha", alpha) + self.ovl_solver.set_variable("alpha", alpha) self.ovl_solver.execute_run() run_data = self.ovl_solver.get_total_forces() @@ -80,8 +80,8 @@ def test_constrained_alpha_sweep(self): ) def test_constrained_cl_sweep(self): - self.ovl_solver.set_constraint("Elevator", 0.00, con_var="Cm pitch moment") - self.ovl_solver.set_constraint("Rudder", 0.00, con_var="Cn yaw moment") + self.ovl_solver.set_constraint("Elevator", "Cm", 0.00, ) + self.ovl_solver.set_constraint("Rudder", "Cn", 0.00, ) cd_ref_arr = np.array( [ @@ -127,7 +127,7 @@ def setUp(self): self.ovl_solver = OVLSolver(geo_file="supra.avl",debug=False) def test_coefs(self): - self.ovl_solver.set_constraint("alpha", 5.00) + self.ovl_solver.set_variable("alpha", 5.00) self.ovl_solver.execute_run() coef_data = self.ovl_solver.get_total_forces() @@ -141,8 +141,8 @@ def setUp(self): self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) def test_con_surf_mom(self): - self.ovl_solver.set_constraint("Elevator", 10.00) - self.ovl_solver.set_constraint("Rudder", 0.00) + self.ovl_solver.set_control_deflection("Elevator", 10.00) + self.ovl_solver.set_control_deflection("Rudder", 0.00) self.ovl_solver.execute_run() mom_data = self.ovl_solver.get_hinge_moments() @@ -150,8 +150,8 @@ def test_con_surf_mom(self): np.testing.assert_allclose(mom_data["Elevator"], -0.04381216304, rtol=1e-8) np.testing.assert_allclose(mom_data["Rudder"], 0.0, atol=1e-8) - self.ovl_solver.set_constraint("Elevator", 0.00) - self.ovl_solver.set_constraint("Rudder", 10.00) + self.ovl_solver.set_control_deflection("Elevator", 0.00) + self.ovl_solver.set_control_deflection("Rudder", 10.00) self.ovl_solver.execute_run() mom_data = self.ovl_solver.get_hinge_moments() @@ -166,7 +166,7 @@ def setUp(self) -> None: self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") def test_coefs_wrt_con_surfs(self): - self.ovl_solver.set_constraint("alpha", 45.00) + self.ovl_solver.set_variable("alpha", 45.00) self.ovl_solver.execute_run() run_data = self.ovl_solver.get_total_forces() coef_derivs = self.ovl_solver.get_control_stab_derivs() @@ -182,7 +182,7 @@ def test_alpha_set(self): Test that setting the alpha works """ - self.ovl_solver.set_constraint("alpha", 10.00) + self.ovl_solver.set_variable("alpha", 10.00) self.ovl_solver.execute_run() alfa_new = self.ovl_solver.get_parameter("alpha") np.testing.assert_allclose(alfa_new, 10.00, rtol=1e-15) @@ -192,13 +192,22 @@ def test_con_surf_set(self): Test that setting the control surface works """ - self.ovl_solver.set_constraint("Elevator", 10.00) - self.ovl_solver.set_constraint("alpha", 10.00) + self.ovl_solver.set_control_deflection("Elevator", 10.00) + self.ovl_solver.set_variable("alpha", 10.00) self.ovl_solver.execute_run() alfa_new = self.ovl_solver.get_parameter("alpha") np.testing.assert_allclose(alfa_new, 10.00, rtol=1e-15) + ele_def = self.ovl_solver.get_control_deflection("Elevator") + np.testing.assert_allclose(ele_def, 10.00, rtol=1e-15) + def_dict = self.ovl_solver.get_control_deflections() - np.testing.assert_allclose(def_dict["Elevator"], 10.00, rtol=1e-15) + for key in def_dict: + def_dict[key] += 1.0 + + self.ovl_solver.set_control_deflections(def_dict) + + ele_def = self.ovl_solver.get_control_deflection("Elevator") + np.testing.assert_allclose(ele_def, 11.00, rtol=1e-15) if __name__ == "__main__": diff --git a/tests/test_body_axis_derivs.py b/tests/test_body_axis_derivs.py index 721f3b8b..411f85df 100644 --- a/tests/test_body_axis_derivs.py +++ b/tests/test_body_axis_derivs.py @@ -31,8 +31,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file="rect.avl") # HACK: we have to use alpha/beta=0 here so the stability and body axis are the same - self.ovl_solver.set_constraint("alpha", 0.0) - self.ovl_solver.set_constraint("beta", 0.0) + self.ovl_solver.set_variable("alpha", 0.0) + self.ovl_solver.set_variable("beta", 0.0) self.ovl_solver.execute_run() @@ -48,7 +48,7 @@ def finite_dif(self, con_list, geom_seeds, step=1e-7): for con in con_list: con_seeds[con] = 1.0 - self.ovl_solver.set_constraint_ad_seeds(con_seeds, mode="FD", scale=step) + self.ovl_solver.set_variable_ad_seeds(con_seeds, mode="FD", scale=step) self.ovl_solver.set_geom_ad_seeds(geom_seeds, mode="FD", scale=step) self.ovl_solver.avl.update_surfaces() @@ -61,7 +61,7 @@ def finite_dif(self, con_list, geom_seeds, step=1e-7): coef_data_peturb = self.ovl_solver.get_total_forces() consurf_derivs_peturb = self.ovl_solver.get_control_body_axis_derivs() - self.ovl_solver.set_constraint_ad_seeds(con_seeds, mode="FD", scale=-step) + self.ovl_solver.set_variable_ad_seeds(con_seeds, mode="FD", scale=-step) self.ovl_solver.set_geom_ad_seeds(geom_seeds, mode="FD", scale=-step) self.ovl_solver.execute_run() @@ -85,7 +85,6 @@ def finite_dif(self, con_list, geom_seeds, step=1e-7): def test_deriv_values(self): # compare the analytical gradients with finite difference for each constraint and function - import pprint base_data = self.ovl_solver.get_total_forces() # pprint.pprint(base_data) @@ -119,11 +118,11 @@ def test_deriv_values(self): for con_key in con_keys: h = 1e-10 - val = self.ovl_solver.get_constraint(con_key) - self.ovl_solver.set_constraint(con_key, val + h) + val = self.ovl_solver.get_variable(con_key) + self.ovl_solver.set_variable(con_key, val + h) self.ovl_solver.execute_run() perb_data = self.ovl_solver.get_total_forces() - self.ovl_solver.set_constraint(con_key, val) + self.ovl_solver.set_variable(con_key, val) for func_key in func_keys: key = self.ovl_solver._get_deriv_key(con_to_var[con_key], func_to_key[func_key]) diff --git a/tests/test_body_axis_derivs_partial_derivs.py b/tests/test_body_axis_derivs_partial_derivs.py index 710378e4..ca86b100 100644 --- a/tests/test_body_axis_derivs_partial_derivs.py +++ b/tests/test_body_axis_derivs_partial_derivs.py @@ -28,8 +28,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 45.0) - self.ovl_solver.set_constraint("beta", 45.0) + self.ovl_solver.set_variable("alpha", 45.0) + self.ovl_solver.set_variable("beta", 45.0) self.ovl_solver.execute_run() self.ovl_solver.clear_ad_seeds_fast() diff --git a/tests/test_contraints.py b/tests/test_constraints.py similarity index 91% rename from tests/test_contraints.py rename to tests/test_constraints.py index 4fd7c9d5..5d78d901 100644 --- a/tests/test_contraints.py +++ b/tests/test_constraints.py @@ -30,8 +30,8 @@ def setUp(self): # def test_rates(self): def test_angles(self): - self.ovl_solver.set_constraint("alpha", 6.00) - self.ovl_solver.set_constraint("beta", 2.00) + self.ovl_solver.set_variable("alpha", 6.00) + self.ovl_solver.set_variable("beta", 2.00) self.ovl_solver.execute_run() np.testing.assert_allclose( @@ -62,8 +62,8 @@ def test_angles(self): ) def test_control_surfaces(self): - self.ovl_solver.set_constraint("D1", 10.00) - self.ovl_solver.set_constraint("D2", 5.00) + self.ovl_solver.set_control_deflection("D1", 10.00) + self.ovl_solver.set_control_deflection("D2", 5.00) self.ovl_solver.execute_run() run_data = self.ovl_solver.get_total_forces() @@ -85,8 +85,8 @@ def test_control_surfaces(self): def test_control_surfaces_names(self): """test that the control surface names are can be used as well""" - self.ovl_solver.set_constraint("Elevator", 10.00) - self.ovl_solver.set_constraint("Rudder", 5.00) + self.ovl_solver.set_control_deflection("Elevator", 10.00) + self.ovl_solver.set_control_deflection("Rudder", 5.00) self.ovl_solver.execute_run() run_data = self.ovl_solver.get_total_forces() np.testing.assert_allclose( diff --git a/tests/test_consurf_partial_derivs.py b/tests/test_consurf_partial_derivs.py index d91030c0..09ec9db6 100644 --- a/tests/test_consurf_partial_derivs.py +++ b/tests/test_consurf_partial_derivs.py @@ -28,8 +28,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 25.0) - self.ovl_solver.set_constraint("beta", 5.0) + self.ovl_solver.set_variable("alpha", 25.0) + self.ovl_solver.set_variable("beta", 5.0) self.ovl_solver.execute_run() def tearDown(self): @@ -190,8 +190,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 45.0) - self.ovl_solver.set_constraint("beta", 45.0) + self.ovl_solver.set_variable("alpha", 45.0) + self.ovl_solver.set_variable("beta", 45.0) self.ovl_solver.execute_run() self.ovl_solver.clear_ad_seeds_fast() diff --git a/tests/test_new_subroutines.py b/tests/test_new_subroutines.py index f79d0643..2b3af218 100644 --- a/tests/test_new_subroutines.py +++ b/tests/test_new_subroutines.py @@ -25,7 +25,7 @@ class TestNewSubroutines(unittest.TestCase): def setUp(self): self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl", debug=False) - self.ovl_solver.set_constraint("alpha", 25.0) + self.ovl_solver.set_variable("alpha", 25.0) def test_residual(self): self.ovl_solver.avl.get_res() @@ -72,9 +72,9 @@ def test_residual(self): ) def test_new_solve(self): - self.ovl_solver.set_constraint("Elevator", 10.00) - self.ovl_solver.set_constraint("alpha", 10.00) - self.ovl_solver.set_constraint("beta", 10.00) + self.ovl_solver.set_control_deflection("Elevator", 10.00) + self.ovl_solver.set_variable("alpha", 10.00) + self.ovl_solver.set_variable("beta", 10.00) self.ovl_solver.avl.exec_rhs() diff --git a/tests/test_om_wrapper.py b/tests/test_om_wrapper.py index 139f25cb..d70222f7 100644 --- a/tests/test_om_wrapper.py +++ b/tests/test_om_wrapper.py @@ -173,14 +173,14 @@ def test_CM_solve(self): om_val = prob.get_val(f"ovlsolver.alpha") - self.ovl_solver.set_constraint("alpha", 0.00, con_var="Cm pitch moment") + self.ovl_solver.set_constraint("alpha", "Cm", 0.00) self.ovl_solver.execute_run() alpha = self.ovl_solver.get_parameter("alpha") np.testing.assert_allclose(om_val, alpha, rtol=1e-5, - err_msg=f"solved alpha", + err_msg="solved alpha", ) def test_OM_total_derivs(self): diff --git a/tests/test_partial_derivs.py b/tests/test_partial_derivs.py index 39dbe389..731482ad 100644 --- a/tests/test_partial_derivs.py +++ b/tests/test_partial_derivs.py @@ -29,8 +29,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) # self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 25.0) - self.ovl_solver.set_constraint("beta", 5.0) + self.ovl_solver.set_variable("alpha", 25.0) + self.ovl_solver.set_variable("beta", 5.0) self.ovl_solver.execute_run() def tearDown(self): @@ -349,8 +349,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 25.0) - self.ovl_solver.set_constraint("beta", 5.0) + self.ovl_solver.set_variable("alpha", 25.0) + self.ovl_solver.set_variable("beta", 5.0) self.ovl_solver.execute_run() process = psutil.Process() mb_memory = process.memory_info().rss / (1024 * 1024) # Convert bytes to MB diff --git a/tests/test_stab_derivs.py b/tests/test_stab_derivs.py index 7924dccb..206b618c 100644 --- a/tests/test_stab_derivs.py +++ b/tests/test_stab_derivs.py @@ -29,8 +29,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 5.0) - # self.ovl_solver.set_constraint("beta", 0.0) + self.ovl_solver.set_variable("alpha", 5.0) + # self.ovl_solver.set_variable("beta", 0.0) self.ovl_solver.execute_run() def tearDown(self): @@ -45,7 +45,7 @@ def finite_dif(self, con_list, geom_seeds, step=1e-7): for con in con_list: con_seeds[con] = 1.0 - self.ovl_solver.set_constraint_ad_seeds(con_seeds, mode="FD", scale=step) + self.ovl_solver.set_variable_ad_seeds(con_seeds, mode="FD", scale=step) self.ovl_solver.set_geom_ad_seeds(geom_seeds, mode="FD", scale=step) self.ovl_solver.avl.update_surfaces() @@ -58,7 +58,7 @@ def finite_dif(self, con_list, geom_seeds, step=1e-7): coef_data_peturb = self.ovl_solver.get_total_forces() consurf_derivs_peturb = self.ovl_solver.get_control_stab_derivs() - self.ovl_solver.set_constraint_ad_seeds(con_seeds, mode="FD", scale=-step) + self.ovl_solver.set_variable_ad_seeds(con_seeds, mode="FD", scale=-step) self.ovl_solver.set_geom_ad_seeds(geom_seeds, mode="FD", scale=-step) self.ovl_solver.execute_run() @@ -99,10 +99,10 @@ def test_deriv_values(self): for con_key in con_keys: h = 1e-8 val = self.ovl_solver.get_constraint(con_key) - self.ovl_solver.set_constraint(con_key, val + h) + self.ovl_solver.set_variable(con_key, val + h) self.ovl_solver.execute_run() perb_data = self.ovl_solver.get_total_forces() - self.ovl_solver.set_constraint(con_key, val) + self.ovl_solver.set_variable(con_key, val) for func_key in func_keys: key = self.ovl_solver._get_deriv_key(con_to_var[con_key], func_key) diff --git a/tests/test_stab_derivs_partial_derivs.py b/tests/test_stab_derivs_partial_derivs.py index 237077af..e5b8615e 100644 --- a/tests/test_stab_derivs_partial_derivs.py +++ b/tests/test_stab_derivs_partial_derivs.py @@ -27,8 +27,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 25.0) - self.ovl_solver.set_constraint("beta", 5.0) + self.ovl_solver.set_variable("alpha", 25.0) + self.ovl_solver.set_variable("beta", 5.0) self.ovl_solver.execute_run() def tearDown(self): @@ -204,8 +204,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 45.0) - self.ovl_solver.set_constraint("beta", 45.0) + self.ovl_solver.set_variable("alpha", 45.0) + self.ovl_solver.set_variable("beta", 45.0) self.ovl_solver.execute_run() self.ovl_solver.clear_ad_seeds_fast() diff --git a/tests/test_surf_geom.py b/tests/test_surf_geom.py index bb721d3d..a667c943 100644 --- a/tests/test_surf_geom.py +++ b/tests/test_surf_geom.py @@ -57,8 +57,8 @@ def test_surface_params(self): err_msg=f"Surface `{surf}` key `{key}` does not match reference data", ) - self.ovl_solver.set_constraint("alpha", 6.00) - self.ovl_solver.set_constraint("beta", 2.00) + self.ovl_solver.set_variable("alpha", 6.00) + self.ovl_solver.set_variable("beta", 2.00) self.ovl_solver.execute_run() assert self.ovl_solver.get_num_surfaces() == 5 @@ -90,8 +90,8 @@ def test_surface_params(self): assert self.ovl_solver.get_num_strips() == 90 assert self.ovl_solver.get_mesh_size() == 780 - self.ovl_solver.set_constraint("alpha", 6.00) - self.ovl_solver.set_constraint("beta", 2.00) + self.ovl_solver.set_variable("alpha", 6.00) + self.ovl_solver.set_variable("beta", 2.00) self.ovl_solver.execute_run() np.testing.assert_allclose( @@ -121,7 +121,7 @@ def test_surface_mirroring(self): }, } - self.ovl_solver.set_constraint("alpha", 10.00) + self.ovl_solver.set_variable("alpha", 10.00) self.ovl_solver.set_surface_params(new_data) self.ovl_solver.execute_run() diff --git a/tests/test_total_derivs.py b/tests/test_total_derivs.py index 97c86369..9fad19be 100644 --- a/tests/test_total_derivs.py +++ b/tests/test_total_derivs.py @@ -30,8 +30,8 @@ def setUp(self): # self.ovl_solver = OVLSolver(geo_file="aircraft_L1.avl") self.ovl_solver = OVLSolver(geo_file="aircraft_L1_trans.avl") # self.ovl_solver = OVLSolver(geo_file="rect.avl") - self.ovl_solver.set_constraint("alpha", 5.0) - self.ovl_solver.set_constraint("beta", 0.0) + self.ovl_solver.set_variable("alpha", 5.0) + self.ovl_solver.set_variable("beta", 0.0) self.ovl_solver.execute_run() def tearDown(self): @@ -47,7 +47,7 @@ def finite_dif(self, con_list, geom_seeds, param_seeds, ref_seeds, step=1e-7): for con in con_list: con_seeds[con] = 1.0 - self.ovl_solver.set_constraint_ad_seeds(con_seeds, mode="FD", scale=step) + self.ovl_solver.set_variable_ad_seeds(con_seeds, mode="FD", scale=step) self.ovl_solver.set_geom_ad_seeds(geom_seeds, mode="FD", scale=step) self.ovl_solver.set_parameter_ad_seeds(param_seeds, mode="FD", scale=step) self.ovl_solver.set_reference_ad_seeds(ref_seeds, mode="FD", scale=step) @@ -65,7 +65,7 @@ def finite_dif(self, con_list, geom_seeds, param_seeds, ref_seeds, step=1e-7): stab_deriv_derivs_peturb = self.ovl_solver.get_stab_derivs() body_axis_deriv_petrub = self.ovl_solver.get_body_axis_derivs() - self.ovl_solver.set_constraint_ad_seeds(con_seeds, mode="FD", scale=-1*step) + self.ovl_solver.set_variable_ad_seeds(con_seeds, mode="FD", scale=-1*step) self.ovl_solver.set_geom_ad_seeds(geom_seeds, mode="FD", scale=-1*step) self.ovl_solver.set_parameter_ad_seeds(param_seeds, mode="FD", scale=-1*step) self.ovl_solver.set_reference_ad_seeds(ref_seeds, mode="FD", scale=-1*step) diff --git a/tools/wheels/cibw_test_command.sh b/tools/wheels/cibw_test_command.sh index 839369bd..7e397a0b 100644 --- a/tools/wheels/cibw_test_command.sh +++ b/tools/wheels/cibw_test_command.sh @@ -25,7 +25,7 @@ python -m unittest -v test_tear_down.py python -m unittest -v test_parameters.py python -m unittest -v test_analysis.py python -m unittest -v test_surf_geom.py -python -m unittest -v test_contraints.py +python -m unittest -v test_constraints.py python -m unittest -v test_stab_derivs.py python -m unittest -v test_body_axis_derivs.py # test eigenmode analysis