diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b8af350 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +venv/ +.git +*.egg-info diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..895abb4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,21 @@ +default: + image: python:3.6 + +build_and_test: + variables: + TEST_PROJECT_NAME: $TEST_PROJECT_NAME + GOOGLE_APPLICATION_CREDENTIALS: $GOOGLE_APPLICATION_CREDENTIALS + cache: + paths: + - requirements-dev.txt + when: 'on_success' + key: 'build_and_test' + script: + - apt-get update -y && apt-get install -y --fix-missing build-essential gfortran + - python3 -m venv test-venv + - bash test-venv/bin/activate + - git clone https://github.com/daniel-de-vries/xfoil-python.git && pip install ./xfoil-python + - pip install -r requirements-dev.txt + - coverage run -m unittest + - coverage report + coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..99101ef --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# xfoil-python only seems to work on python 3.6. +FROM python:3.6-slim-buster + +# Allow statements and log messages to immediately appear in the Knative logs on Google Cloud. +ENV PYTHONUNBUFFERED True + +ENV PROJECT_ROOT=/app +WORKDIR $PROJECT_ROOT + +RUN apt-get update -y && apt-get install -y --fix-missing build-essential gfortran git && rm -rf /var/lib/apt/lists/* + +# xfoil-python has to be installed locally from a clone (and only seems to work on python 3.6). +RUN git clone https://github.com/daniel-de-vries/xfoil-python.git && pip install ./xfoil-python + +COPY requirements-dev.txt . +COPY setup.py . +COPY . . + +RUN pip install --upgrade pip && pip install -r requirements-dev.txt + +EXPOSE $PORT + +ARG _SERVICE_ID +ENV SERVICE_ID=$_SERVICE_ID + +ARG _GUNICORN_WORKERS=1 +ENV _GUNICORN_WORKERS=$_GUNICORN_WORKERS + +ARG _GUNICORN_THREADS=8 +ENV _GUNICORN_THREADS=$_GUNICORN_THREADS + +# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling. +CMD exec gunicorn --bind :$PORT --workers $_GUNICORN_WORKERS --threads $_GUNICORN_THREADS --timeout 0 octue.cloud.deployment.google.cloud_run:app diff --git a/README.md b/README.md index a7f01d4..02b4add 100644 --- a/README.md +++ b/README.md @@ -1,107 +1,21 @@ # panel-code-twine-python A simple twine that runs panel codes. This repository is mirrored to Google Cloud Source Repositories. -## Creating a twine -First, think about: -- what data you want to flow into and out of the app -- what kinds of datasets (groups of files) the app might need to access -- what other applicaitons / twins ('children') you need to use -- what credentials you might need (e.g. if you're accessing a database or a third party API -The **twine** file secifies all these things and more. First, place an empty `twine.json` file in the root directory of the app. -See [https://twined.readthedocs.io](https://twined.readthedocs.io) for everything there is to know about how to define a twine. If you log in to [octue.com](https://www.octue.com/login) you'll find tools to help you build the twine. +### Building documents manually -*Note: this example app is not up to date with the current version of twined! Follow or comment on [this issue](https://github.com/octue/octue-app-python/issues/1).* +**If you did need to build the documentation** - -## First steps in development +Install `doxgen`. On a mac, that's `brew install doxygen`; other systems may differ. -If you've not developed python applications before, we strongly recommend the following practices: - -- Use an Integrated Development Environment (IDE) to help you. We recommend [Pycharm, by Jetbrains](https://www.jetbrains.com/pycharm/) because it's cross-platform (i.e. for Windows, Mac and Linux), very friendly, and there's a free "Community Edition" which should have all the features you need for now. -- Ensure Python 3.5 or greater is installed. (Mac users: use [pyenv](https://github.com/pyenv/pyenv), windows users could try [pyenv-win](https://github.com/pyenv-win/pyenv-win)) -- [Configure a Virtual Environment](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html) to ensure you always have a consistent python environment and packages installed. - -Once you've set yourself up with Python 3.7+, an IDE and an activated virtual environment, you're ready to go: - -- PyCharm will usually do this for you, but if not, install the project dependencies (see `requirements.txt`). -- Set up a directory containing your input data. How to do this is covered below, in 'Data Directories'. - -### Running your app (whilst developing) - -`>> python app.py`. Simple as that. You can specify a - - -### Connecting to the octue platform - - 1. Log in to [octue.com](www.octue.com), click `applications > create` in the sidebar, and follow the wizard. Simples! - - -## Data directories - -Octue uses a strict folder structure, to help separate input, output, and temporary data. The structure looks like this: +Install sphinx and other requirements for building the docs: ``` -my_data_folder - | - |- input - | | - | |- config.json - | |- manifest.json - | |- - | | | - | | |- - | | |- - | | |- - | | |- ... - | | - | |- - | | | - | | |- - | | |- - | | |- - | | |- ... - | | - | |- ... - | - |- logs - | | - | |- ... - | - |- tmp - | | - | |- ... - | - |- output - | | - | |- ... +pip install -r docs/requirements.txt ``` -- Folder **`input`** contains any input datasets (groups of files). Within each dataset - you can simply dump a load of files created by an instrument or supplied by a third party here. These files should never be altered by the application. -- Folder **`logs`** will contain log files produced while running the application. You shouldn't need to use these, as all output will be shown either in your terminal or on octue online. -- Folder **`tmp`** you can write any temporary files (e.g. large cached calculations that are reused but don't form part of the results) here. -- Folder **`output`** all output files should be saved to this directory. Any output files (like figures) produced by octue are saved here too. - -- File **``input/manifest.json``** contains a list of all the files in the input directory, with any tags that are applied (see 'generating the manifest file', below).. -- File **``input/config.json``** contains a list of options and configuration parameters to use when running the application (see 'generating the config file', below). - - -### Generating the config and manifest files - -When a user (you, or someone else) launches an application on octue, they fill in a form (which is generated from the twine). That creates a -`config.json` file automatically. You can download this for local development. - -Connecting datasets to the application creates the `manifest.json`, which you can download too. - -But, if you're just testing your own application out, its helpful to generate these files yourself. - -The `octue_app_python` repository contains a `schema.json` for the example application. -Go to [the octue schema playground](https://www.octue.com/schema/playground), and paste the entire contents of -`schema.json` into the top left box. - -Fill in the form (it's already populated with defaults) and you'll see your **config** change as you do, in the bottom -right box. This is what gets pasted into `config.json` (see `octue_app_python/example_data/config.json`). - -You can play around with schema in that playground (if you're having trouble, use the excellent -[JSON Editor Online](https://jsoneditoronline.org/) to help debug them if you run into trouble. +Run the build process: +``` +sphinx-build -b html docs/source docs/build +``` \ No newline at end of file diff --git a/app.py b/app.py index 443c992..b29bda3 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,7 @@ +import os import xfoil_module +REPOSITORY_ROOT = os.path.abspath(os.path.dirname(__file__)) def run(analysis): """ diff --git a/cloudbuild.yaml b/cloudbuild.yaml new file mode 100644 index 0000000..6d652b9 --- /dev/null +++ b/cloudbuild.yaml @@ -0,0 +1,47 @@ +steps: + - name: gcr.io/cloud-builders/docker + args: + - build + - '--no-cache' + - '-t' + - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA' + - --build-arg + - _SERVICE_ID=$_SERVICE_ID + - . + - '-f' + - Dockerfile + id: Build + - name: gcr.io/cloud-builders/docker + args: + - push + - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA' + id: Push + - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim' + args: + - run + - services + - update + - $_SERVICE_NAME + - '--platform=managed' + - '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA' + - >- + --labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID,$_LABELS + - '--region=$_DEPLOY_REGION' + - '--quiet' + id: Deploy + entrypoint: gcloud +images: + - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA' +options: + substitutionOption: ALLOW_LOOSE +substitutions: + _GCR_HOSTNAME: eu.gcr.io + _PLATFORM: managed + _SERVICE_NAME: panel-codes-twine + _LABELS: gcb-trigger-id=c11b2517-2b8b-435b-9a30-8213e322851b + _TRIGGER_ID: c11b2517-2b8b-435b-9a30-8213e322851b + _DEPLOY_REGION: europe-north1 +tags: + - gcp-cloud-build-deploy-cloud-run + - gcp-cloud-build-deploy-cloud-run-managed + - panel-codes-twine diff --git a/data/input/datasets/aerofoil_shape_file/naca_0012.dat b/data/input/aerofoil_shape_data/naca_0012.dat similarity index 100% rename from data/input/datasets/aerofoil_shape_file/naca_0012.dat rename to data/input/aerofoil_shape_data/naca_0012.dat diff --git a/data/input/datasets/aerofoil_shape_file/naca_2412.dat b/data/input/aerofoil_shape_data/naca_2412.dat similarity index 100% rename from data/input/datasets/aerofoil_shape_file/naca_2412.dat rename to data/input/aerofoil_shape_data/naca_2412.dat diff --git a/data/input/manifest.json b/data/input/manifest.json index 99e5e55..a21b35e 100644 --- a/data/input/manifest.json +++ b/data/input/manifest.json @@ -1,29 +1,32 @@ { "id": "8ead7669-8162-4f64-8cd5-4abe92509e17", + "keys": {"aerofoil_shape_data": 0}, "type" : "dataset", "datasets": [ { "id": "7ead7669-8162-4f64-8cd5-4abe92509e18", "name": "aerofoil_shape_data", - "tags": "naca_0012", + "tags": ["series:naca"], "files": [ { - "path": "input/datasets/aerofoil_shape_file/naca_2412.dat", + "path": "naca_2412.dat", "cluster": 0, "sequence": 0, "extension": "dat", - "tags": "", + "tags": ["name:naca-2412"], + "timestamp": 0, "id": "abff07bc-7c19-4ed5-be6d-a6546eae8f86", "last_modified": "2019-02-28T22:40:30.533005Z", "name": "naca_2412.dat", "size_bytes": 59684813 }, { - "path": "input/datasets/aerofoil_shape_file/naca_0012.dat", + "path": "naca_0012.dat", "cluster": 0, "sequence": 1, "extension": "dat", - "tags": "naca_0012", + "tags": ["name:naca-0012"], + "timestamp": 0, "id": "abff07bc-7c19-4ed5-be6d-a6546eae8f87", "last_modified": "2019-02-28T22:40:30.533005Z", "name": "naca_0012.dat" diff --git a/data/input/values.json b/data/input/values.json index 7e3a530..b60d464 100644 --- a/data/input/values.json +++ b/data/input/values.json @@ -1,4 +1,5 @@ { + "airfoil_name": "naca-0012", "alpha_range": [0, 6, 1], "inflow_speed": 1, "kinematic_viscosity": 1e-5, diff --git a/deployment_configuration.json b/deployment_configuration.json new file mode 100644 index 0000000..16257c2 --- /dev/null +++ b/deployment_configuration.json @@ -0,0 +1,8 @@ +{ + "app_dir": ".", + "twine": "twine.json", + "configuration_values": { + "analysis_program": "xfoil", + "max_iterations": 20 + } +} diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..a8a5878 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,4 @@ +doctrees +html +source/doxyoutput* +source/library_api* diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..2e83e84 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,6 @@ +# Required by the python script for building documentation +Sphinx>=2,<3 +sphinx-rtd-theme==0.5.0 +sphinx-tabs==1.2.1 +octue==0.1.12 +pyserial==3.5 diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 0000000..12ba99c --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,14 @@ +.. _api: + +=== +API +=== + + +.. _api_xfoil: + +X-Foil Module +============= + +.. automodule:: xfoil_module.routines + :members: \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..913c577 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- +# +# Documentation build configuration file +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import os +import subprocess +import sys +import sphinx_rtd_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../..')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', + 'sphinx_tabs.tabs', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'panel_codes_twine' +copyright = u'The Aerosense Research Partners' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +# The full version, including alpha/beta/rc tags. +os.chdir(os.path.join("..", "..")) +release = subprocess.check_output(["python3", "setup.py", "--version"]).decode().strip() +os.chdir(os.path.join("docs", "source")) + +# The short X.Y version. +version = '.'.join(release.split('.')[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = ["_themes",] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = "panel_codes_twine: Short Description" + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +html_domain_indices = True + +# If false, no index is generated. +html_use_index = True + +# If true, the index is split into individual pages for each letter. +html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libraryDoc' + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # 'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'panel_codes_twine.tex', u'panel_codes_twine', + u'OST Aerosense', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'panel_codes_twine', u'panel_codes_twine', + [u'OST Aerosense'], 1) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'panel_codes_twine', u'panel_codes_twine', + u'OST Aerosense', 'panel_codes_twine', 'Octue wrapper for panel codes.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..07c2b1d --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,28 @@ +.. ATTENTION:: + This library is in experimental stages! Please pin deployments to a specific release, and consider every release as breaking. + +================= +Panel Codes Twine +================= + +.. epigraph:: + *"Panel Codes Twine" ~ Wraps various panel codes into octue twine service.* + + +Input +===== + +Output +====== + +Configuration +============= + + + +INDEX +===== +.. toctree:: + :maxdepth: 2 + + api diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..b85fbce --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,18 @@ +# Testing +# ------------------------------------------------------------------------------ +coverage + +# ----------- Install the current app (as editable, so you can develop on it) ------------------------------------------ + +--editable . + + +# ----------- Some common libraries ----------------------------------------------------------------------------------- + +# XFOIL Python module by DARcorporavgfoiltion, uses Fortran library directly though api. +# xfoil==1.1.1 #Version 1.1.1 has a bug in setting mach number, add MINf1 = M + # after line 204 in src/api.f90! + +# VG-Foil Python - Modified version of xfoil-python, includes IWES modifications for vortex generators +# https://github.com/time-trader/vgfoil-python +# vgfoil diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5e75e1c..0000000 --- a/requirements.txt +++ /dev/null @@ -1,36 +0,0 @@ -appdirs==1.4.3 -args==0.1.0 -clint==0.5.1 -packaging==20.0 -pyparsing==2.4.6 -six==1.13.0 -octue==0.1.12 -click==7.1.2 - -# ----------- Install the current app (as editable, so you can develop on it) ------------------------------------------ - ---editable . - - -# ----------- Some common libraries ----------------------------------------------------------------------------------- - -# A numerical manipulation library -numpy - -# XFOIL Python module by DARcorporavgfoiltion, uses Fortran library directly though api. -xfoil==1.1.1 #Version 1.1.1 has a bug in setting mach number, add MINf1 = M - # after line 204 in src/api.f90! -# VG-Foil Python - Modified version of xfoil-python, includes IWES modifications for vortex generators -# https://github.com/time-trader/vgfoil-python -# vgfoil - - -# A powerful database api library. Supply it with your db's uri (through environment variables - don't commit URIs to git!!!!) and read/add data to/from databases. -# Note that results of analyses using externally managed databases as data sources cannot be guaranteed to be idempotent. -#SQLAlchemy==1.0.12 -#SQLAlchemy-Utils==0.31.6 - - -# ----------- Octue internal use only. Do not uncomment. --------------------------------------------------------------- - -# --editable ../octue-sdk-python diff --git a/setup.py b/setup.py index 6536f69..d32546a 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,16 @@ -import os from setuptools import setup -def git_version(): - return os.system('git rev-parse HEAD') - - setup( name="panel-codes-twine", - version=git_version(), + version="0.0.0", py_modules=['app'], entry_points=''' [console_scripts] octue-app=app:octue_app ''', + install_requires=[ + "numpy", + "octue>=0.1.16", + ] ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_deployment.py b/tests/test_deployment.py new file mode 100644 index 0000000..4f433e4 --- /dev/null +++ b/tests/test_deployment.py @@ -0,0 +1,64 @@ +import os + +from octue.cloud.pub_sub.service import Service +from octue.resources import Datafile, Dataset, Manifest +from octue.resources.service_backends import GCPPubSubBackend + + +def test_deployment(): + """Test that the Google Cloud Run integration works, providing a service that can be asked questions and send + responses. + """ + PROJECT_NAME = os.environ["TEST_PROJECT_NAME"] + BUCKET_NAME = "panel-codes-twine-deployment-testing" + SERVICE_ID = "octue.services.8765b5f2-1778-4a6f-809d-46b91e01bd97" + + dataset = Dataset( + files = [ + Datafile.from_cloud( + project_name=PROJECT_NAME, + bucket_name=BUCKET_NAME, + datafile_path="aerofoil_shape_data/naca_2412.dat", + id="abff07bc-7c19-4ed5-be6d-a6546eae8f86", + cluster=0, + sequence=0, + timestamp=0, + tags=["name:naca-2412"], + allow_overwrite=True + ), + Datafile.from_cloud( + project_name=PROJECT_NAME, + bucket_name=BUCKET_NAME, + datafile_path="aerofoil_shape_data/naca_0012.dat", + id="abff07bc-7c19-4ed5-be6d-a6546eae8f87", + cluster=0, + sequence=1, + timestamp=0, + tags=["name:naca-0012"], + allow_overwrite=True + ) + ] + ) + + input_manifest = Manifest(datasets=[dataset], keys={"aerofoil_shape_data": 0}) + + input_values = { + "airfoil_name": "naca-0012", + "alpha_range": [-10, 10, 5], + "inflow_speed": 1, + "kinematic_viscosity": 1e-6, + "characteristic_length": 1e-6, + "mach_number": 0, + "n_critical": 9, + "re_xtr": [5e5, 5e5] + } + + asker = Service(backend=GCPPubSubBackend(project_name=os.environ["TEST_PROJECT_NAME"])) + + subscription, _ = asker.ask(service_id=SERVICE_ID, input_values=input_values, input_manifest=input_manifest) + answer = asker.wait_for_answer(subscription, timeout=1000) + assert all(key in answer["output_values"] for key in ("cl", "cd", "cm")) + + +if __name__ == "__main__": + test_deployment() diff --git a/tests/xfoil/__init__.py b/tests/xfoil/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/xfoil/cases/naca0012/data/configuration/values.json b/tests/xfoil/cases/naca0012/data/configuration/values.json new file mode 100644 index 0000000..9da105b --- /dev/null +++ b/tests/xfoil/cases/naca0012/data/configuration/values.json @@ -0,0 +1,4 @@ +{ + "analysis_program": "xfoil", + "max_iterations":1000 +} \ No newline at end of file diff --git a/tests/xfoil/cases/naca0012/data/input/aerofoil_shape_data/naca_0012.dat b/tests/xfoil/cases/naca0012/data/input/aerofoil_shape_data/naca_0012.dat new file mode 100644 index 0000000..cd81171 --- /dev/null +++ b/tests/xfoil/cases/naca0012/data/input/aerofoil_shape_data/naca_0012.dat @@ -0,0 +1,161 @@ +NACA 0012 + 1.000000 0.1260000E-02 + 0.9916796 0.2421450E-02 + 0.9803692 0.3981369E-02 + 0.9672663 0.5761861E-02 + 0.9527169 0.7706239E-02 + 0.9371981 0.9743313E-02 + 0.9211172 0.1181512E-01 + 0.9047380 0.1388559E-01 + 0.8882062 0.1593565E-01 + 0.8715962 0.1795616E-01 + 0.8549446 0.1994301E-01 + 0.8382694 0.2189448E-01 + 0.8215796 0.2380992E-01 + 0.8048802 0.2568905E-01 + 0.7881741 0.2753174E-01 + 0.7714632 0.2933785E-01 + 0.7547492 0.3110713E-01 + 0.7380334 0.3283924E-01 + 0.7213171 0.3453371E-01 + 0.7046016 0.3618991E-01 + 0.6878882 0.3780710E-01 + 0.6711780 0.3938437E-01 + 0.6544725 0.4092067E-01 + 0.6377730 0.4241478E-01 + 0.6210807 0.4386535E-01 + 0.6043972 0.4527084E-01 + 0.5877237 0.4662956E-01 + 0.5710618 0.4793964E-01 + 0.5544131 0.4919904E-01 + 0.5377791 0.5040555E-01 + 0.5211615 0.5155676E-01 + 0.5045622 0.5265006E-01 + 0.4879829 0.5368266E-01 + 0.4714257 0.5465156E-01 + 0.4548929 0.5555352E-01 + 0.4383865 0.5638509E-01 + 0.4219094 0.5714258E-01 + 0.4054640 0.5782205E-01 + 0.3890536 0.5841929E-01 + 0.3726814 0.5892981E-01 + 0.3563512 0.5934879E-01 + 0.3400671 0.5967113E-01 + 0.3238340 0.5989134E-01 + 0.3076573 0.6000357E-01 + 0.2915433 0.6000157E-01 + 0.2754992 0.5987865E-01 + 0.2595337 0.5962761E-01 + 0.2436573 0.5924080E-01 + 0.2278824 0.5871002E-01 + 0.2122249 0.5802654E-01 + 0.1967044 0.5718119E-01 + 0.1813469 0.5616449E-01 + 0.1661868 0.5496702E-01 + 0.1512710 0.5358012E-01 + 0.1366645 0.5199727E-01 + 0.1224568 0.5021633E-01 + 0.1087684 0.4824299E-01 + 0.9575211E-01 0.4609495E-01 + 0.8358167E-01 0.4380527E-01 + 0.7242320E-01 0.4142167E-01 + 0.6239496E-01 0.3899972E-01 + 0.5353650E-01 0.3659163E-01 + 0.4580557E-01 0.3423655E-01 + 0.3910103E-01 0.3195685E-01 + 0.3329449E-01 0.2976012E-01 + 0.2825571E-01 0.2764358E-01 + 0.2386683E-01 0.2559846E-01 + 0.2002796E-01 0.2361304E-01 + 0.1665780E-01 0.2167459E-01 + 0.1369190E-01 0.1977039E-01 + 0.1108039E-01 0.1788830E-01 + 0.8785779E-02 0.1601716E-01 + 0.6781116E-02 0.1414711E-01 + 0.5048412E-02 0.1227024E-01 + 0.3577171E-02 0.1038135E-01 + 0.2362721E-02 0.8479204E-02 + 0.1403676E-02 0.6567576E-02 + 0.6990856E-03 0.4657032E-02 + 0.2435545E-03 0.2761454E-02 + 0.2599979E-04 0.9056400E-03 + 0.2599979E-04 -0.9056400E-03 + 0.2435545E-03 -0.2761454E-02 + 0.6990856E-03 -0.4657032E-02 + 0.1403676E-02 -0.6567576E-02 + 0.2362721E-02 -0.8479204E-02 + 0.3577171E-02 -0.1038135E-01 + 0.5048412E-02 -0.1227024E-01 + 0.6781116E-02 -0.1414711E-01 + 0.8785779E-02 -0.1601716E-01 + 0.1108039E-01 -0.1788830E-01 + 0.1369190E-01 -0.1977039E-01 + 0.1665780E-01 -0.2167459E-01 + 0.2002796E-01 -0.2361304E-01 + 0.2386683E-01 -0.2559846E-01 + 0.2825571E-01 -0.2764358E-01 + 0.3329449E-01 -0.2976012E-01 + 0.3910103E-01 -0.3195685E-01 + 0.4580557E-01 -0.3423655E-01 + 0.5353650E-01 -0.3659163E-01 + 0.6239496E-01 -0.3899972E-01 + 0.7242320E-01 -0.4142167E-01 + 0.8358167E-01 -0.4380527E-01 + 0.9575211E-01 -0.4609495E-01 + 0.1087684 -0.4824299E-01 + 0.1224568 -0.5021633E-01 + 0.1366645 -0.5199727E-01 + 0.1512710 -0.5358012E-01 + 0.1661868 -0.5496702E-01 + 0.1813469 -0.5616449E-01 + 0.1967044 -0.5718119E-01 + 0.2122249 -0.5802654E-01 + 0.2278824 -0.5871002E-01 + 0.2436573 -0.5924080E-01 + 0.2595337 -0.5962761E-01 + 0.2754992 -0.5987865E-01 + 0.2915433 -0.6000157E-01 + 0.3076573 -0.6000357E-01 + 0.3238340 -0.5989134E-01 + 0.3400671 -0.5967113E-01 + 0.3563512 -0.5934879E-01 + 0.3726814 -0.5892981E-01 + 0.3890536 -0.5841929E-01 + 0.4054640 -0.5782205E-01 + 0.4219094 -0.5714258E-01 + 0.4383865 -0.5638509E-01 + 0.4548929 -0.5555352E-01 + 0.4714257 -0.5465156E-01 + 0.4879829 -0.5368266E-01 + 0.5045622 -0.5265006E-01 + 0.5211615 -0.5155676E-01 + 0.5377791 -0.5040555E-01 + 0.5544131 -0.4919904E-01 + 0.5710618 -0.4793964E-01 + 0.5877237 -0.4662956E-01 + 0.6043972 -0.4527084E-01 + 0.6210807 -0.4386535E-01 + 0.6377730 -0.4241478E-01 + 0.6544725 -0.4092067E-01 + 0.6711780 -0.3938437E-01 + 0.6878882 -0.3780710E-01 + 0.7046016 -0.3618991E-01 + 0.7213171 -0.3453371E-01 + 0.7380334 -0.3283924E-01 + 0.7547492 -0.3110713E-01 + 0.7714632 -0.2933785E-01 + 0.7881741 -0.2753174E-01 + 0.8048802 -0.2568905E-01 + 0.8215796 -0.2380992E-01 + 0.8382694 -0.2189448E-01 + 0.8549446 -0.1994301E-01 + 0.8715962 -0.1795616E-01 + 0.8882062 -0.1593565E-01 + 0.9047380 -0.1388559E-01 + 0.9211172 -0.1181512E-01 + 0.9371981 -0.9743313E-02 + 0.9527169 -0.7706239E-02 + 0.9672663 -0.5761861E-02 + 0.9803692 -0.3981369E-02 + 0.9916796 -0.2421450E-02 + 1.000000 -0.1260000E-02 diff --git a/tests/xfoil/cases/naca0012/data/input/aerofoil_shape_data/naca_2412.dat b/tests/xfoil/cases/naca0012/data/input/aerofoil_shape_data/naca_2412.dat new file mode 100644 index 0000000..c778a0f --- /dev/null +++ b/tests/xfoil/cases/naca0012/data/input/aerofoil_shape_data/naca_2412.dat @@ -0,0 +1,82 @@ +NACA 2412 Airfoil M=2.0% P=40.0% T=12.0% + 1.000084 0.001257 + 0.998557 0.001575 + 0.993984 0.002524 + 0.986392 0.004086 + 0.975825 0.006231 + 0.962343 0.008922 + 0.946027 0.012110 + 0.926971 0.015740 + 0.905287 0.019752 + 0.881104 0.024079 + 0.854565 0.028653 + 0.825830 0.033404 + 0.795069 0.038260 + 0.762469 0.043149 + 0.728228 0.048000 + 0.692554 0.052741 + 0.655665 0.057302 + 0.617788 0.061615 + 0.579155 0.065609 + 0.540008 0.069220 + 0.500588 0.072381 + 0.461143 0.075034 + 0.421921 0.077122 + 0.383032 0.078574 + 0.344680 0.079198 + 0.307289 0.078941 + 0.271106 0.077802 + 0.236371 0.075794 + 0.203313 0.072947 + 0.172151 0.069309 + 0.143088 0.064941 + 0.116313 0.059918 + 0.091996 0.054325 + 0.070289 0.048257 + 0.051324 0.041808 + 0.035214 0.035076 + 0.022051 0.028152 + 0.011907 0.021120 + 0.004833 0.014049 + 0.000860 0.006997 + 0.000000 0.000000 + 0.002223 -0.006689 + 0.007479 -0.012828 + 0.015723 -0.018404 + 0.026892 -0.023408 + 0.040906 -0.027826 + 0.057669 -0.031651 + 0.077071 -0.034878 + 0.098987 -0.037507 + 0.123281 -0.039546 + 0.149805 -0.041013 + 0.178401 -0.041934 + 0.208902 -0.042346 + 0.241131 -0.042294 + 0.274904 -0.041834 + 0.310028 -0.041027 + 0.346303 -0.039941 + 0.383522 -0.038644 + 0.421644 -0.037174 + 0.460397 -0.035444 + 0.499412 -0.033493 + 0.538451 -0.031373 + 0.577279 -0.029138 + 0.615658 -0.026833 + 0.653352 -0.024500 + 0.690129 -0.022172 + 0.725762 -0.019880 + 0.760029 -0.017649 + 0.792716 -0.015499 + 0.823619 -0.013448 + 0.852541 -0.011510 + 0.879302 -0.009701 + 0.903730 -0.008033 + 0.925669 -0.006520 + 0.944979 -0.005174 + 0.961536 -0.004008 + 0.975232 -0.003035 + 0.985978 -0.002265 + 0.993705 -0.001708 + 0.998361 -0.001370 + 0.999916 -0.001257 \ No newline at end of file diff --git a/tests/xfoil/cases/naca0012/data/input/manifest.json b/tests/xfoil/cases/naca0012/data/input/manifest.json new file mode 100644 index 0000000..a21b35e --- /dev/null +++ b/tests/xfoil/cases/naca0012/data/input/manifest.json @@ -0,0 +1,37 @@ +{ + "id": "8ead7669-8162-4f64-8cd5-4abe92509e17", + "keys": {"aerofoil_shape_data": 0}, + "type" : "dataset", + "datasets": [ + { + "id": "7ead7669-8162-4f64-8cd5-4abe92509e18", + "name": "aerofoil_shape_data", + "tags": ["series:naca"], + "files": [ + { + "path": "naca_2412.dat", + "cluster": 0, + "sequence": 0, + "extension": "dat", + "tags": ["name:naca-2412"], + "timestamp": 0, + "id": "abff07bc-7c19-4ed5-be6d-a6546eae8f86", + "last_modified": "2019-02-28T22:40:30.533005Z", + "name": "naca_2412.dat", + "size_bytes": 59684813 + }, + { + "path": "naca_0012.dat", + "cluster": 0, + "sequence": 1, + "extension": "dat", + "tags": ["name:naca-0012"], + "timestamp": 0, + "id": "abff07bc-7c19-4ed5-be6d-a6546eae8f87", + "last_modified": "2019-02-28T22:40:30.533005Z", + "name": "naca_0012.dat" + } + ] + } + ] +} diff --git a/tests/xfoil/cases/naca0012/data/input/values.json b/tests/xfoil/cases/naca0012/data/input/values.json new file mode 100644 index 0000000..b60d464 --- /dev/null +++ b/tests/xfoil/cases/naca0012/data/input/values.json @@ -0,0 +1,10 @@ +{ + "airfoil_name": "naca-0012", + "alpha_range": [0, 6, 1], + "inflow_speed": 1, + "kinematic_viscosity": 1e-5, + "characteristic_length": 1, + "mach_number": 0.06, + "n_critical": 9, + "re_xtr":[5e5,5e5] +} \ No newline at end of file diff --git a/tests/xfoil/test_xfoil.py b/tests/xfoil/test_xfoil.py new file mode 100644 index 0000000..44555fe --- /dev/null +++ b/tests/xfoil/test_xfoil.py @@ -0,0 +1,32 @@ +import os +from unittest import TestCase + +from octue import Runner + +from app import REPOSITORY_ROOT + + +class TestXFoil(TestCase): + + def get_xfoil_case_path(self, xfoil_case): + """Sets XFOIL with the case""" + return os.path.join(REPOSITORY_ROOT, "tests", "xfoil", "cases", xfoil_case) + + def test_call(self): + """Test that xfoil runs NACA0012 analysis and that results are consistent with compiled version from NASA + website. + """ + case_path = self.get_xfoil_case_path("naca0012") + + runner = Runner( + app_src=REPOSITORY_ROOT, + twine=os.path.join(REPOSITORY_ROOT, "twine.json"), + configuration_values=os.path.join(case_path, "data", "configuration", "values.json") + ) + + analysis = runner.run( + input_values=os.path.join(case_path, "data", "input", "values.json"), + input_manifest=os.path.join(case_path, "data", "input", "manifest.json") + ) + + analysis.finalise(output_dir=os.path.join(case_path, "data", "output")) diff --git a/twine.json b/twine.json index b4ebf6c..64a1802 100644 --- a/twine.json +++ b/twine.json @@ -1,188 +1,192 @@ { - "title": "Panel Codes FSI twine", - "description": "Uses potential theory to solve 2D airfoils", - "configuration_values_schema": { - "type": "object", - "properties": { - "analysis_program": { - "title": "Analysis Program", - "description": "The underlying program that will be run to determine aerofoil section properties", - "type": "string", - "default": "xfoil", - "anyOf": [ - { - "type": "string", - "enum": [ - "xfoil" - ], - "title": "X-Foil" - }, - { - "type": "string", - "enum": [ - "vgfoil" - ], - "title": "VG-Foil" - }, - { - "type": "string", - "enum": [ - "viiflow" - ], - "title": "ViiFlow" - }, - { - "type": "string", - "enum": [ - "rfoil" - ], - "title": "RFoil" - } - ] - }, - "max_iterations":{ - "description": "Maxumum number of iterations", - "type": "integer", - "title": "Max Iterations", - "default": 20, - "minimum": 20, - "maximum": 10000 - } - } - }, - "input_manifest_filters": [ - { - "key": "aerofoil_shape_file", - "purpose": "A dataset containing a single shape file in .dat or tab delimited open form, describing the aerofoil shape.", - "filters": "tags:(naca_0012)" - } - ], - "input_values_schema": { - "title": "Input values schema", - "type": "object", - "properties": { - "alpha_range": { - "description": "The range of alpha values at which the solver will be run.", - "type": "array", - "title": "Alpha Range [min max step]", - "default": [-10, 10, 5], - "items": [ - { - "type": "number", - "min": -30, - "max": 30 - }, - { - "type": "number", - "min": -30, - "max": 30 - }, - { - "type": "number", - "min": 0.1, - "max": 180 - } - ], - "additionalItems": false - }, - "inflow_speed": { - "title": "U", - "description": "Inflow speed U in m/s", - "type": "number", - "default": 1, - "minimum": 1e-6, - "maximum": 330 - }, - "kinematic_viscosity": { - "title": "Kinematic Viscosity", - "description": "Kinematic visosity nu", - "type": "number", - "minimum": 1e-6, - "maximum": 0.1 - }, - "characteristic_length": { - "title": "Characteristic aerofoil length", - "description": "Chord length l in m", - "type": "number", - "minimum": 1e-6, - "maximum": 10 - }, - "mach_number": { - "title": "Mach number", - "description": "", - "type": "number", - "default": 0, - "minimum": 0, - "maximum": 0.8 - }, - "n_critical": { - "title": "N critical", - "description": "N critical amplification factor from eN method ", - "type": "number", - "default": 9, - "minimum": 0, - "maximum": 20 - }, - "re_xtr": { - "title": "Critical Reynolds number for top and bottom of the airfoil", - "description": "Reynolds number at which the transition from laminar to turbulent flow occurs [Top, Bottom]", - "type": "array", - "items": [ - { - "type": "number", - "default": 5e5, - "minimum": 1e-6, - "maximum": 1e9 - }, - { - "type": "number", - "default": 5e5, - "minimum": 1e-6, - "maximum": 1e9 - } - ], - "additionalItems": false - } - } - }, - "output_values_schema": { - "type": "object", - "properties": { - "reynolds_number": { - "description": "Reynolds number calculated from input parameters", - "type": "number", - "minimum": 0, - "maximum": 1000000000000 - }, - "cl": { - "description": "Output Cl values corresponding to the input alpha values", - "type": "array", - "title": "Cl values", - "items": { - "type": "number" + "title": "Panel Codes FSI twine", + "description": "Uses potential theory to solve 2D airfoils", + "configuration_values_schema": { + "type": "object", + "properties": { + "analysis_program": { + "title": "Analysis Program", + "description": "The underlying program that will be run to determine aerofoil section properties", + "type": "string", + "default": "xfoil", + "anyOf": [ + { + "type": "string", + "enum": [ + "xfoil" + ], + "title": "X-Foil" + }, + { + "type": "string", + "enum": [ + "vgfoil" + ], + "title": "VG-Foil" + }, + { + "type": "string", + "enum": [ + "viiflow" + ], + "title": "ViiFlow" + }, + { + "type": "string", + "enum": [ + "rfoil" + ], + "title": "RFoil" + } + ] + }, + "max_iterations":{ + "description": "Maximum number of iterations", + "type": "integer", + "title": "Max Iterations", + "default": 20, + "minimum": 20, + "maximum": 10000 + } + } + }, + "input_manifest": [ + { + "key": "aerofoil_shape_data", + "purpose": "A dataset containing shape files in .dat or tab delimited open form, describing the aerofoil shape.", + "filters": "tags:(series:naca)" } - }, - "cd": { - "description": "Output Cd values corresponding to the input alpha values", - "type": "array", - "title": "Cd values", - "items": { - "type": "number" + ], + "input_values_schema": { + "title": "Input values schema", + "type": "object", + "properties": { + "airfoil_name": { + "title": "Airfoil name", + "type": "string" + }, + "alpha_range": { + "description": "The range of alpha values at which the solver will be run.", + "type": "array", + "title": "Alpha Range [min max step]", + "default": [-10, 10, 5], + "items": [ + { + "type": "number", + "min": -30, + "max": 30 + }, + { + "type": "number", + "min": -30, + "max": 30 + }, + { + "type": "number", + "min": 0.1, + "max": 180 + } + ], + "additionalItems": false + }, + "inflow_speed": { + "title": "U", + "description": "Inflow speed U in m/s", + "type": "number", + "default": 1, + "minimum": 1e-6, + "maximum": 330 + }, + "kinematic_viscosity": { + "title": "Kinematic Viscosity", + "description": "Kinematic viscosity nu", + "type": "number", + "minimum": 1e-6, + "maximum": 0.1 + }, + "characteristic_length": { + "title": "Characteristic aerofoil length", + "description": "Chord length l in m", + "type": "number", + "minimum": 1e-6, + "maximum": 10 + }, + "mach_number": { + "title": "Mach number", + "description": "", + "type": "number", + "default": 0, + "minimum": 0, + "maximum": 0.8 + }, + "n_critical": { + "title": "N critical", + "description": "N critical amplification factor from eN method ", + "type": "number", + "default": 9, + "minimum": 0, + "maximum": 20 + }, + "re_xtr": { + "title": "Critical Reynolds number for top and bottom of the airfoil", + "description": "Reynolds number at which the transition from laminar to turbulent flow occurs [Top, Bottom]", + "type": "array", + "items": [ + { + "type": "number", + "default": 5e5, + "minimum": 1e-6, + "maximum": 1e9 + }, + { + "type": "number", + "default": 5e5, + "minimum": 1e-6, + "maximum": 1e9 + } + ], + "additionalItems": false + } } - }, - "cm": { - "description": "Output Cm values corresponding to the input alpha values", - "type": "array", - "title": "Cm values", - "items": { - "type": "number" + }, + "output_values_schema": { + "type": "object", + "properties": { + "reynolds_number": { + "description": "Reynolds number calculated from input parameters", + "type": "number", + "minimum": 0, + "maximum": 1000000000000 + }, + "cl": { + "description": "Output Cl values corresponding to the input alpha values", + "type": "array", + "title": "Cl values", + "items": { + "type": "number" + } + }, + "cd": { + "description": "Output Cd values corresponding to the input alpha values", + "type": "array", + "title": "Cd values", + "items": { + "type": "number" + } + }, + "cm": { + "description": "Output Cm values corresponding to the input alpha values", + "type": "array", + "title": "Cm values", + "items": { + "type": "number" + } + }, + "cp": { + "description": "Cp values for x and y coordinate of the airfoil", + "title": "Cp values", + "type": "array" + } } - }, - "cp": { - "description": "Cp values for x and y coordiante of the airfoil", - "title": "Cp values", - "type": "array" - } } - } -} \ No newline at end of file +} diff --git a/xfoil_module/routines.py b/xfoil_module/routines.py index ff21a68..2224c56 100644 --- a/xfoil_module/routines.py +++ b/xfoil_module/routines.py @@ -14,13 +14,14 @@ def call(analysis): - '''Calls Xfoil module''' + '''Runs analysis using Xfoil''' print("Lets run Xfoil!") - # Hardcoded airfoil names for now - # TODO add multi-processing, each section on a separate sub-process. - airfoil_name = 'naca_0012' - xf.airfoil = load_airfoil(airfoil_name) + # load airfoil shapefiles dataset + input_dataset = analysis.input_manifest.get_dataset("aerofoil_shape_data") + airfoil_file = input_dataset.get_file_by_tag("name:"+analysis.input_values["airfoil_name"]) + + xf.airfoil = load_airfoil(airfoil_file) # Reynolds number, xf.Re = set_input(analysis.input_values)[0] @@ -73,9 +74,12 @@ def set_input(_in): return reynolds, x_transition -def load_airfoil(airfoil_name): - print(airfoil_name) - with open('./data/input/datasets/aerofoil_shape_file/' + airfoil_name + '.dat') as f: +def load_airfoil(airfoil_file): + """ + Loads airfoil geometry data from .dat file + """ + print(airfoil_file.get_local_path()) + with open(airfoil_file.get_local_path()) as f: content = f.readlines() x_coord = [] @@ -90,4 +94,3 @@ def load_airfoil(airfoil_name): airfoilObj.y = np.array(y_coord) return airfoilObj -