Skip to content

Commit

Permalink
Merge pull request #3 from mayankchetan/switch2Hatch
Browse files Browse the repository at this point in the history
Hatch, Cmake and GitHub actions
  • Loading branch information
mayankchetan committed Aug 26, 2024
2 parents 09775e1 + 692ddb2 commit 8830377
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 3,590 deletions.
48 changes: 47 additions & 1 deletion .github/workflows/automated-dev-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,8 @@ jobs:
- name: Run Interface / API tests
working-directory: ${{runner.workspace}}/openfast/build
run: |
ctest -VV -L "cpp|python|fastlib"
ctest -VV -L "cpp|python|fastlib" \
-LE "openfast_io"
- name: Failing test artifacts
uses: actions/upload-artifact@v4
if: failure()
Expand Down Expand Up @@ -600,6 +601,51 @@ jobs:
!${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI
!${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline
rtest-openfast_io:
runs-on: ubuntu-22.04
needs: build-openfast-release
steps:
- name: Cache the workspace
uses: actions/cache@v4
with:
path: ${{runner.workspace}}
key: build-openfast-release-${{ github.sha }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
sudo apt-get update -y
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
- name: Install openfast_io
working-directory: ${{runner.workspace}}/openfast/openfast_io
run: |
pip install -e .
- name: Configure Tests
working-directory: ${{runner.workspace}}/openfast/build
run: |
cmake \
-DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \
-DBUILD_TESTING:BOOL=ON \
-DCTEST_PLOT_ERRORS:BOOL=ON \
${GITHUB_WORKSPACE}
cmake --build . --target regression_test_controllers
- name: Run openfast_io tests
working-directory: ${{runner.workspace}}/openfast/build
run: |
ctest -VV -j4 \
-L openfast_io
- name: Failing test artifacts
uses: actions/upload-artifact@v4
if: failure()
with:
name: rtest-openfast_io
path: |
${{runner.workspace}}/openfast/build/reg_tests/openfast_io
rtest-OF-simulink:
runs-on: ubuntu-22.04
Expand Down
37 changes: 26 additions & 11 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
# repository. The build cache is stored in GitHub actions.
name: deploy

on:
workflow_dispatch:
# on:
# workflow_dispatch:

release:
types:
- released
# release:
# types:
# - released
on:
push:

jobs:
# publish-to-pypi:
Expand Down Expand Up @@ -43,17 +45,30 @@ jobs:
# jobs:
publish-to-test-pypi:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Build and publish to pypi
uses: JRubics/poetry-publish@v2.0

- name: Set up Python
uses: actions/setup-python@v4
with:
pypi_token: ${{ secrets.PYPI_TOKEN }}
package_directory: "openfast_io"
repository_name: "openfast_io"
repository_url: "https://test.pypi.org/legacy/"
python-version: '3.10'
cache: 'pip'

- name: Install Hatch
uses: pypa/hatch@install


- name: Build package
run: hatch build
working-directory: openfast_io

- name: Publish to PyPI
env:
HATCH_INDEX_USER: __token__
HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }}
run: hatch publish -r test
working-directory: openfast_io

docker-build-and-push:
runs-on: ubuntu-latest
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,4 @@ varcache
*.slxc

# Python cache files
__pycache__/
openfast_io/dist/
26 changes: 13 additions & 13 deletions openfast_io/openfast_io/FAST_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,8 +786,8 @@ def write_AeroDyn15(self):
self.write_AeroDyn15Coord()

if self.fst_vt['AeroDyn15']['Wake_Mod'] == 3:
if self.fst_vt['AeroDyn15']['UAMod'] == 2:
raise Exception('OLAF is called with unsteady airfoil aerodynamics, but OLAF currently only supports UAMod == 1') #TODO: need to check if this holds true now
if self.fst_vt['AeroDyn15']['UA_Mod'] == 2:
raise Exception('OLAF is called with unsteady airfoil aerodynamics, but OLAF currently only supports UA_Mod == 1') #TODO: need to check if this holds true now
self.write_OLAF()

# Generate AeroDyn v15.03 input file
Expand Down Expand Up @@ -1013,7 +1013,7 @@ def write_AeroDyn15Polar(self):
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['alpha0'], 'alpha0', '! 0-lift angle of attack, depends on airfoil.\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['alpha1'], 'alpha1', '! Angle of attack at f=0.7, (approximately the stall angle) for AOA>alpha0. (deg)\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['alpha2'], 'alpha2', '! Angle of attack at f=0.7, (approximately the stall angle) for AOA<alpha0. (deg)\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['eta_e'], 'eta_e', '! Recovery factor in the range [0.85 - 0.95] used only for UAMOD=1, it is set to 1 in the code when flookup=True. (-)\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['eta_e'], 'eta_e', '! Recovery factor in the range [0.85 - 0.95] used only for UA_Mod=1, it is set to 1 in the code when flookup=True. (-)\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['C_nalpha'], 'C_nalpha', '! Slope of the 2D normal force coefficient curve. (1/rad)\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['T_f0']) + ' {:<11} {:}'.format('T_f0', '! Initial value of the time constant associated with Df in the expression of Df and f''. [default = 3]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['T_V0']) + ' {:<11} {:}'.format('T_V0', '! Initial value of the time constant associated with the vortex lift decay process; it is used in the expression of Cvn. It depends on Re,M, and airfoil class. [default = 6]\n'))
Expand All @@ -1025,22 +1025,22 @@ def write_AeroDyn15Polar(self):
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['A1']) + ' {:<11} {:}'.format('A1', '! Constant in the expression of phi_alpha^c and phi_q^c. This value is relatively insensitive for thin airfoils, but may be different for turbine airfoils. [from experimental results, defaults to 0.3]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['A2']) + ' {:<11} {:}'.format('A2', '! Constant in the expression of phi_alpha^c and phi_q^c. This value is relatively insensitive for thin airfoils, but may be different for turbine airfoils. [from experimental results, defaults to 0.7]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['A5']) + ' {:<11} {:}'.format('A5', "! Constant in the expression of K'''_q,Cm_q^nc, and k_m,q. [from experimental results, defaults to 1]\n"))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S1'], 'S1', '! Constant in the f curve best-fit for alpha0<=AOA<=alpha1; by definition it depends on the airfoil. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S2'], 'S2', '! Constant in the f curve best-fit for AOA> alpha1; by definition it depends on the airfoil. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S3'], 'S3', '! Constant in the f curve best-fit for alpha2<=AOA< alpha0; by definition it depends on the airfoil. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S4'], 'S4', '! Constant in the f curve best-fit for AOA< alpha2; by definition it depends on the airfoil. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S1'], 'S1', '! Constant in the f curve best-fit for alpha0<=AOA<=alpha1; by definition it depends on the airfoil. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S2'], 'S2', '! Constant in the f curve best-fit for AOA> alpha1; by definition it depends on the airfoil. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S3'], 'S3', '! Constant in the f curve best-fit for alpha2<=AOA< alpha0; by definition it depends on the airfoil. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['S4'], 'S4', '! Constant in the f curve best-fit for AOA< alpha2; by definition it depends on the airfoil. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['Cn1'], 'Cn1', '! Critical value of C0n at leading edge separation. It should be extracted from airfoil data at a given Mach and Reynolds number. It can be calculated from the static value of Cn at either the break in the pitching moment or the loss of chord force at the onset of stall. It is close to the condition of maximum lift of the airfoil at low Mach numbers.\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['Cn2'], 'Cn2', '! As Cn1 for negative AOAs.\n'))
# f.write('{: 22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi]['St_sh'], 'St_sh', "! Strouhal's shedding frequency constant. [default = 0.19]\n"))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['St_sh']) + ' {:<11} {:}'.format('St_sh', "! Strouhal's shedding frequency constant. [default = 0.19]\n"))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['Cd0'], 'Cd0', '! 2D drag coefficient value at 0-lift.\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['Cm0'], 'Cm0', '! 2D pitching moment coefficient about 1/4-chord location, at 0-lift, positive if nose up. [If the aerodynamics coefficients table does not include a column for Cm, this needs to be set to 0.0]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k0'], 'k0', '! Constant in the \\hat(x)_cp curve best-fit; = (\\hat(x)_AC-0.25). [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k1'], 'k1', '! Constant in the \\hat(x)_cp curve best-fit. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k2'], 'k2', '! Constant in the \\hat(x)_cp curve best-fit. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k3'], 'k3', '! Constant in the \\hat(x)_cp curve best-fit. [ignored if UAMod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k1_hat'], 'k1_hat', '! Constant in the expression of Cc due to leading edge vortex effects. [ignored if UAMod<>1]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['x_cp_bar']) + ' {:<11} {:}'.format('x_cp_bar', '! Constant in the expression of \\hat(x)_cp^v. [ignored if UAMod<>1, default = 0.2]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k0'], 'k0', '! Constant in the \\hat(x)_cp curve best-fit; = (\\hat(x)_AC-0.25). [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k1'], 'k1', '! Constant in the \\hat(x)_cp curve best-fit. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k2'], 'k2', '! Constant in the \\hat(x)_cp curve best-fit. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k3'], 'k3', '! Constant in the \\hat(x)_cp curve best-fit. [ignored if UA_Mod<>1]\n'))
f.write('{:<22f} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['k1_hat'], 'k1_hat', '! Constant in the expression of Cc due to leading edge vortex effects. [ignored if UA_Mod<>1]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['x_cp_bar']) + ' {:<11} {:}'.format('x_cp_bar', '! Constant in the expression of \\hat(x)_cp^v. [ignored if UA_Mod<>1, default = 0.2]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['UACutout']) + ' {:<11} {:}'.format('UACutout', '! Angle of attack above which unsteady aerodynamics are disabled (deg). [Specifying the string "Default" sets UACutout to 45 degrees]\n'))
f.write(float_default_out(self.fst_vt['AeroDyn15']['af_data'][afi][tab]['filtCutOff']) + ' {:<11} {:}'.format('filtCutOff', '! Cut-off frequency (-3 dB corner frequency) for low-pass filtering the AoA input to UA, as well as the 1st and 2nd derivatives (Hz) [default = 20]\n'))

Expand Down
6 changes: 6 additions & 0 deletions openfast_io/openfast_io/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
try:
from ._version import __version__, __version_tuple__

except ImportError:
__version__ = "undefined"
__version_tuple__ = None # type: ignore
16 changes: 16 additions & 0 deletions openfast_io/openfast_io/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# file generated by setuptools_scm
# don't change, don't track in version control
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Tuple, Union
VERSION_TUPLE = Tuple[Union[int, str], ...]
else:
VERSION_TUPLE = object

version: str
__version__: str
__version_tuple__: VERSION_TUPLE
version_tuple: VERSION_TUPLE

__version__ = version = '4.0.0a1'
__version_tuple__ = version_tuple = (4, 0, 0)
24 changes: 24 additions & 0 deletions openfast_io/openfast_io/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest
import os.path as osp
import platform

# looking up OS for the correct executable extension
mactype = platform.system().lower()
if mactype in ["linux", "linux2", "darwin"]:
exeExt = ""
elif mactype in ["win32", "windows", "cygwin"]: #NOTE: platform.system()='Windows', sys.platform='win32'
libext = '.exe'
else:
raise ValueError('Unknown platform type: '+mactype)

REPOSITORY_ROOT = osp.dirname(osp.dirname(osp.dirname(osp.dirname(__file__))))
BUILD_DIR = osp.join(REPOSITORY_ROOT, "build/reg_tests")

# Path to the OpenFAST executable
OF_PATH = osp.join(REPOSITORY_ROOT,"build/glue-codes/openfast",f"openfast{exeExt}")

def pytest_addoption(parser):
parser.addoption("--executable", action="store", default=OF_PATH, help="Path to the OpenFAST executable")
parser.addoption("--source_dir", action="store", default=REPOSITORY_ROOT, help="Path to the openfast repository")
parser.addoption("--build_dir", action="store", default=BUILD_DIR, help="Path to the test data directory")

Loading

0 comments on commit 8830377

Please sign in to comment.