From 7b248dc5d055e4cac5e5ba7a6edb22e9493107d0 Mon Sep 17 00:00:00 2001 From: marinlauber Date: Sat, 17 Oct 2026 10:57:29 +0200 Subject: [PATCH] feat: package as python_vpp for PyPI - move the code to src/python_vpp/ and the model coefficient data to src/python_vpp/dat/, loaded relative to the package (DATA_DIR) so the VPP runs from any working directory - ship the YD-41 righting arm curve as the fallback when no GZ is given and there is no righting_moment.json in the working directory - expose VPP, Yacht, appendages and sails at the package top level, with __version__ from the installed metadata - relative imports inside the package; drop the sys.path hacks - pyproject: wheel package path, project URLs, keywords, slim sdist - README: pip install, usage example and release steps Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01JN4y2NWa8kFMBZ5FV92jkj --- Procfile | 2 +- README.md | 38 ++++++++++++++++++- benchmark/benchmark.py | 8 ++-- "demos/pages/1_VPP_\342\233\265.py" | 7 ++-- pyproject.toml | 15 +++++++- runVPP.py | 6 +-- scripts/Resistance.py | 4 +- sphinx/conf.py | 2 +- sphinx/index.rst | 2 +- src/__init__.py | 1 - src/{ => python_vpp}/AeroMod.py | 2 +- src/{ => python_vpp}/HydroMod.py | 4 +- src/{ => python_vpp}/SailMod.py | 11 +++--- src/{ => python_vpp}/UtilsMod.py | 5 ++- src/{ => python_vpp}/VPPMod.py | 8 ++-- src/{ => python_vpp}/YachtMod.py | 14 +++++-- src/python_vpp/__init__.py | 14 +++++++ src/{ => python_vpp}/api.py | 9 ++--- .../python_vpp/dat}/ORCi_Drag_Surfaces.csv | 0 {dat => src/python_vpp/dat}/fcdmult.dat | 0 {dat => src/python_vpp/dat}/jib.dat | 0 {dat => src/python_vpp/dat}/kheff.dat | 0 {dat => src/python_vpp/dat}/kite.dat | 0 {dat => src/python_vpp/dat}/main.dat | 0 .../python_vpp/dat}/orc/asym_cl_kite.dat | 0 .../python_vpp/dat}/orc/asym_pole_kite.dat | 0 {dat => src/python_vpp/dat}/orc/jib.dat | 0 {dat => src/python_vpp/dat}/orc/jib_low.dat | 0 {dat => src/python_vpp/dat}/orc/kite.dat | 0 {dat => src/python_vpp/dat}/orc/main.dat | 0 {dat => src/python_vpp/dat}/orc/main_low.dat | 0 {dat => src/python_vpp/dat}/orc/sym_kite.dat | 0 src/python_vpp/dat/righting_moment.json | 4 ++ {dat => src/python_vpp/dat}/rrk.dat | 0 {dat => src/python_vpp/dat}/st.dat | 0 {dat => src/python_vpp/dat}/ut.dat | 0 {dat => src/python_vpp/dat}/wr.dat | 0 tests/test_aero.py | 14 +++---- tests/test_api.py | 2 +- tests/test_hydro.py | 6 +-- tests/test_resistance.py | 6 +-- tests/test_utils.py | 6 +-- tests/test_vpp.py | 14 +++---- tests/test_yacht.py | 4 +- 44 files changed, 140 insertions(+), 68 deletions(-) delete mode 100644 src/__init__.py rename src/{ => python_vpp}/AeroMod.py (99%) rename src/{ => python_vpp}/HydroMod.py (99%) rename src/{ => python_vpp}/SailMod.py (97%) rename src/{ => python_vpp}/UtilsMod.py (97%) rename src/{ => python_vpp}/VPPMod.py (98%) rename src/{ => python_vpp}/YachtMod.py (96%) create mode 100644 src/python_vpp/__init__.py rename src/{ => python_vpp}/api.py (95%) rename {dat => src/python_vpp/dat}/ORCi_Drag_Surfaces.csv (100%) rename {dat => src/python_vpp/dat}/fcdmult.dat (100%) rename {dat => src/python_vpp/dat}/jib.dat (100%) rename {dat => src/python_vpp/dat}/kheff.dat (100%) rename {dat => src/python_vpp/dat}/kite.dat (100%) rename {dat => src/python_vpp/dat}/main.dat (100%) rename {dat => src/python_vpp/dat}/orc/asym_cl_kite.dat (100%) rename {dat => src/python_vpp/dat}/orc/asym_pole_kite.dat (100%) rename {dat => src/python_vpp/dat}/orc/jib.dat (100%) rename {dat => src/python_vpp/dat}/orc/jib_low.dat (100%) rename {dat => src/python_vpp/dat}/orc/kite.dat (100%) rename {dat => src/python_vpp/dat}/orc/main.dat (100%) rename {dat => src/python_vpp/dat}/orc/main_low.dat (100%) rename {dat => src/python_vpp/dat}/orc/sym_kite.dat (100%) create mode 100644 src/python_vpp/dat/righting_moment.json rename {dat => src/python_vpp/dat}/rrk.dat (100%) rename {dat => src/python_vpp/dat}/st.dat (100%) rename {dat => src/python_vpp/dat}/ut.dat (100%) rename {dat => src/python_vpp/dat}/wr.dat (100%) diff --git a/Procfile b/Procfile index c99e5a1..6adb339 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: gunicorn src.api:app --log-file=- \ No newline at end of file +web: gunicorn --chdir src python_vpp.api:app --log-file=- \ No newline at end of file diff --git a/README.md b/README.md index 592b128..4f973d0 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,38 @@ Please see the demo hosted at [https://yacht-vpp.streamlit.app/](https://yacht-vpp.streamlit.app/) and go for a test sail! +## Installation + +Python-VPP is on PyPI and needs Python 3.11 or newer: + +```bash +pip install python-vpp +``` + +Then build a yacht and run the VPP: + +```python +import numpy as np +from python_vpp import VPP, Yacht, Keel, Rudder, Main, Jib, Kite + +yacht = Yacht( + Name="YD41", Lwl=11.90, Vol=6.05, Bwl=3.18, Tc=0.4, WSA=28.20, Tmax=2.30, + Amax=1.051, Mass=6500, Ff=1.5, Fa=1.5, Boa=4.2, Loa=12.5, + App=[Keel(Cu=1.00, Cl=0.78, Span=1.90), Rudder(Cu=0.48, Cl=0.22, Span=1.15)], + Sails=[ + Main("MN1", P=16.60, E=5.60, Roach=0.1, BAD=1.0), + Jib("J1", I=16.20, J=5.10, LPG=5.40, HBI=1.8), + Kite("A2", area=150.0, vce=9.55), + ], +) +vpp = VPP(Yacht=yacht) +vpp.set_analysis(tws_range=np.arange(4.0, 22.0, 2.0), twa_range=np.linspace(30.0, 180.0, 31)) +vpp.run() +vpp.polar(n=3, save=True) # Polars.pdf +``` + +The righting arm curve is passed with `Yacht(..., GZ={"Heel": [...], "GZ": [...]})`. Without it, `righting_moment.json` is read from the working directory, falling back to the YD-41 curve shipped with the package. The ORC sail and resistance coefficients are part of the package. + ## Using the code The project is managed with [uv](https://docs.astral.sh/uv/). Install it once (see the [uv docs](https://docs.astral.sh/uv/getting-started/installation/) for other methods): @@ -20,7 +52,7 @@ cd Python-VPP uv sync ``` -The main files that are used are `runVPP.py` and `righting_moment.json`. These have to be filled with the data of your boat. By default they are using the YD-41 (from Principle of Yacht Design). +From a clone of the repository, the main files that are used are `runVPP.py` and `righting_moment.json`. These have to be filled with the data of your boat. By default they are using the YD-41 (from Principle of Yacht Design). The code lives in `src/python_vpp/`, with the model coefficient data in `src/python_vpp/dat/`; `uv sync` installs it in editable mode. The VPP is run from the root of the repository with @@ -111,6 +143,10 @@ You can run tests with uv run pytest -vv ``` +### Release + +Bump `version` in `pyproject.toml`, then create a GitHub release with a matching tag (e.g. `v1.0.0`). The `python-publish.yml` workflow builds the package with `uv build` and uploads it to PyPI through trusted publishing. Check the build locally first with `uv build`. + You can run a benchmark against the YD-41 results from WinVPP by running the `benchmark.py` script (`-g` saves the polars as one `Figure_