diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index bf099c60..85850f9f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -28,8 +28,8 @@ jobs: # working - [windows-2025, win, AMD64] - [ubuntu-22.04, manylinux, x86_64] - - [macos-13, macosx, x86_64, openblas, "10.13"] - [macos-14, macosx, arm64, openblas, "12.3"] + - [macos-15-intel, macosx, x86_64, openblas, "10.14"] python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"], ["cp312", "3.12"], ["cp313", "3.13"]] @@ -54,6 +54,7 @@ jobs: echo "c:\rtools40\ucrt64\bin;" >> $env:GITHUB_PATH if: ${{ runner.os == 'Windows' }} + - name: Setup macOS if: startsWith( matrix.buildplat[0], 'macos-' ) run: | @@ -65,41 +66,45 @@ jobs: echo "PATH=$PATH" >> "$GITHUB_ENV" LIB_PATH=$(dirname $(gfortran --print-file-name libgfortran.dylib)) fi - # Add libraries installed by cibw_before_build_macos.sh to path - if [[ ${{ matrix.buildplat[2] }} == 'arm64' ]]; then - LIB_PATH=$LIB_PATH:/opt/arm64-builds/lib - else - LIB_PATH=$LIB_PATH:/usr/local/lib - fi - if [[ ${{ matrix.buildplat[4] }} == '10.13' ]]; then - # 20241017 macos-13 images span Xcode 14.1-->15.2 - XCODE_VER='14.1' - else - XCODE_VER='15.2' - fi - CIBW="sudo xcode-select -s /Applications/Xcode_${XCODE_VER}.app" - echo "CIBW_BEFORE_ALL=$CIBW" >> $GITHUB_ENV + # XCODE_VER='16.0' + # CIBW="sudo xcode-select -s /Applications/Xcode_${XCODE_VER}.app" + # echo "CIBW_BEFORE_ALL=$CIBW" >> $GITHUB_ENV # setting SDKROOT necessary when using the gfortran compiler # installed in cibw_before_build_macos.sh - sudo xcode-select -s /Applications/Xcode_${XCODE_VER}.app + # sudo xcode-select -s /Applications/Xcode_${XCODE_VER}.app CIBW="MACOSX_DEPLOYMENT_TARGET=${{ matrix.buildplat[4] }}\ - LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH\ - PKG_CONFIG_PATH=$LIB_PATH/pkgconfig\ - SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" - echo "CIBW_ENVIRONMENT_MACOS=$CIBW" >> "$GITHUB_ENV" + SDKROOT=$(xcrun --sdk macosx --show-sdk-path)\ + PKG_CONFIG_PATH=${{ github.workspace }}" + echo "CIBW_ENVIRONMENT=$CIBW" >> "$GITHUB_ENV" echo "REPAIR_PATH=$LIB_PATH" >> "$GITHUB_ENV" - GFORTRAN_LIB="\$(dirname \$(gfortran --print-file-name libgfortran.dylib))" - CIBW="DYLD_LIBRARY_PATH=$GFORTRAN_LIB:$LIB_PATH delocate-listdeps {wheel} &&\ - DYLD_LIBRARY_PATH=$GFORTRAN_LIB:$LIB_PATH delocate-wheel --require-archs \ - {delocate_archs} -w {dest_dir} {wheel}" - # Rename x86 Accelerate wheel to test on macOS 13 runner - if [[ ${{ matrix.buildplat[0] }} == 'macos-13' && ${{ matrix.buildplat[4] }} == '14.0' ]]; then - CIBW+=" && mv {dest_dir}/\$(basename {wheel}) \ - {dest_dir}/\$(echo \$(basename {wheel}) | sed 's/14_0/13_0/')" + + PREFIX=DYLD_LIBRARY_PATH="\$(dirname \$(gfortran --print-file-name libgfortran.dylib))" + # remove libgfortran from location used for linking (if any), to + # check wheel has bundled things correctly and all tests pass without + # needing installed gfortran + POSTFIX=" sudo rm -rf /opt/gfortran-darwin-x86_64-native &&\ + sudo rm -rf /usr/local/gfortran/lib" + CIBW="$PREFIX delocate-listdeps -d {wheel} && echo "-----------" &&\ + $PREFIX delocate-wheel -v $EXCLUDE --require-archs \ + {delocate_archs} -w {dest_dir} {wheel} && echo "-----------" &&\ + delocate-listdeps -d {dest_dir}/*.whl && echo "-----------" &&\ + $POSTFIX" + + # macos-arm64-openblas wheels that target macos-12 need a + # MACOS_DEPLOYMENT_TARGET of 12.3 otherwise delocate complains. + # Unclear of cause, possibly build tool related. + # This results in wheels that have 12_3 in their name. Since Python + # has no concept of minor OS versions in packaging land rename the + # wheel back to 12. + if [[ ${{ matrix.buildplat[0] }} == 'macos-14' && ${{ matrix.buildplat[4] }} == '12.3' ]]; then + CIBW+=" && echo \$(ls {dest_dir}) && \ + mv {dest_dir}/*.whl \$(find {dest_dir} -type f -name '*.whl' | sed 's/12_3/12_0/')" fi echo "CIBW_REPAIR_WHEEL_COMMAND_MACOS=$CIBW" >> "$GITHUB_ENV" + + - name: Build wheels uses: pypa/cibuildwheel@v3.2.1 env: diff --git a/examples/run_modes.py b/examples/run_modes.py index 93a572b4..c08ed932 100644 --- a/examples/run_modes.py +++ b/examples/run_modes.py @@ -3,7 +3,7 @@ import matplotlib.pyplot as plt -def syssho(asys): +def syssho(asys,bsys): """ Prints out state-system matrix A in an organized manner. @@ -13,26 +13,32 @@ def syssho(asys): State matrix A. """ nsys = asys.shape[0] + + consurf_names = ovl.get_control_names() + num_consurf = len(consurf_names) # Header state_labels = ["u", "w", "q", "the", "v", "p", "r", "phi", "x", "y", "z", "psi"] header = " ".join(f"{lab:>10}" for lab in state_labels) + " |" + header += " ".join(f"{lab:>10}" for lab in consurf_names) print(header) + # Rows for i in range(nsys): row_str = "".join(f"{val:11.4f}" for val in asys[i, :12]) + row_str += "".join(f"{val:11.4f}" for val in bsys[i, :num_consurf]) print(row_str) -ovl = OVLSolver(geo_file="../geom_files/aircraft.avl", mass_file="../geom_files/aircraft.mass", debug=False) +ovl = OVLSolver(geo_file="../geom_files/aircraft.avl", mass_file="../geom_files/aircraft.mass", debug=True) ovl.set_trim_condition("velocity", 10.0) ovl.set_constraint("Elevator", "Cm", 0.00) ovl.execute_eigen_mode_calc() -Amat = ovl.get_system_matrix(in_body_axis=True) -syssho(Amat) +Amat, Bmat, _ = ovl.get_system_matrices(in_body_axis=True) +syssho(Amat,Bmat) vals_ovl = ovl.get_eigenvalues() diff --git a/meson.build b/meson.build index 127395f0..b6242840 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'optvl', 'c', - version: '2.0.1', + version: '2.1.0', license: 'GPL-3.0', meson_version: '>= 0.64.0', default_options: [ diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 27481cd9..fb97aba1 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -1975,29 +1975,46 @@ def get_eigenvectors(self) -> np.ndarray: return eig_vecs def get_system_matrix(self, in_body_axis=False) -> np.ndarray: - """returns the system matrix used for the eigenmode calculation + """ returns just the A system matrix used for the eigenmode calculation""" + # this routine is mostly to not introduce breaking chnages + + # call the routine for getting them all, but just ignore the B and R parts + Asys, _, _ = self.get_system_matrices(in_body_axis=in_body_axis) + + return Asys + + def get_system_matrices(self, in_body_axis=False) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """returns the A,B, and R system matrices used in amode.f args: in_body_axis: apply the sign changes to the matrix to put it in the body axis Returns: - asys: 2D array representing the system matrix for the eigen value analysis + Asys: 2D array representing the system matrix for the eigen value analysis + Bsys: 2D array representing the system matrix for control surfaces + Rsys: 1D array representing the RHS of the dynamics equation """ # get the dimesion of the A matrix from the eig_vals eig_vals = self.get_avl_fort_arr("CASE_Z", "EVAL") jemax = eig_vals.shape[1] - asys = np.zeros((jemax,jemax), order="F") + Asys = np.zeros((jemax,jemax), order="F") + Bsys = np.zeros((jemax,self.NDMAX), order="F") + Rsys = np.zeros((jemax), order="F") # 1 because optvl only supports 1 run case and we are using fortran base 1 indexing irun_case = 1 - self.avl.get_system_matrix(irun_case,asys) + self.avl.get_system_matrices(irun_case,Asys, Bsys, Rsys) - def apply_state_signs(asys): + num_controls = self.get_num_control_surfs() + # trim the columns of the Bsys matrix + Bsys = Bsys[:, 0:num_controls] + + def apply_state_signs(Asys, Bsys, Rsys): """ Apply sign changes to the state matrix A and return the modified version. """ - nsys = asys.shape[0] + nsys = Asys.shape[0] # Indices for sign flip jeu = 0 @@ -2019,19 +2036,26 @@ def apply_state_signs(asys): usgn[idx] = -1.0 # Allocate result - asys_signed = np.zeros_like(asys) + Asys_signed = np.zeros_like(Asys) + Bsys_signed = np.zeros_like(Bsys) + Rsys_signed = np.zeros_like(Rsys) # Apply row/column sign flips explicitly for i in range(nsys): for j in range(nsys): - asys_signed[i, j] = asys[i, j] * usgn[i] * usgn[j] + Asys_signed[i, j] = Asys[i, j] * usgn[i] * usgn[j] + + for j in range(num_controls): + Bsys_signed[i,j] = Bsys[i, j] * usgn[i] + + Rsys_signed = Rsys[i]*usgn[i] - return asys_signed + return Asys_signed, Bsys_signed, Rsys_signed if in_body_axis: - asys = apply_state_signs(asys) + Asys, Bsys, Rsys = apply_state_signs(Asys, Bsys, Rsys) - return asys + return Asys, Bsys, Rsys # region --- geometry api def get_control_names(self) -> List[str]: diff --git a/pyproject.toml b/pyproject.toml index d8ded305..0e7873b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "numpy>=1.19", ] readme = "README.md" -version = "2.0.1" # this automatically updates __init__.py and setup_deprecated.py +version = "2.1.0" # this automatically updates __init__.py and setup_deprecated.py [tool.cibuildwheel] diff --git a/src/amode.f b/src/amode.f index adb7439d..8b82a09f 100644 --- a/src/amode.f +++ b/src/amode.f @@ -2293,21 +2293,22 @@ subroutine execute_eigenmode_calc() end subroutine execute_eigenmode_calc - subroutine get_system_matrix(ir, ASYS) + subroutine get_system_matrices(ir, ASYS, BSYS, RSYS) INCLUDE 'AVL.INC' ! input/output REAL*8 :: ASYS(JEMAX,JEMAX) + REAL*8 :: BSYS(JEMAX,NDMAX) + REAL*8 :: RSYS(JEMAX) ! working - REAL*8 :: BSYS(JEMAX,NDMAX),RSYS(JEMAX) REAL*8 :: ETOL integer :: NSYS, i CALL SYSMAT(IR,ASYS,BSYS,RSYS,NSYS) - end subroutine + end subroutine get_system_matrices C diff --git a/src/f2py/libavl.pyf b/src/f2py/libavl.pyf index fb0f6f89..97262d1a 100644 --- a/src/f2py/libavl.pyf +++ b/src/f2py/libavl.pyf @@ -129,11 +129,13 @@ python module libavl ! in subroutine execute_eigenmode_calc end subroutine execute_eigenmode_calc - subroutine get_system_matrix(ir, asys) + subroutine get_system_matrices(ir, asys, bsys, rsys) include '../includes/AVL.INC' integer :: ir real*8, intent(inout) :: asys(jemax,jemax) - end subroutine get_system_matrix + real*8, intent(inout) :: bsys(jemax,ndmax) + real*8, intent(inout) :: rsys(jemax) + end subroutine get_system_matrices !subroutine getcam(x, y, n, xc, yc, tc, nc, lnorm) ! in :libavl:airutil.f !integer, intent(in) :: n