From 02cf042c86f2d10e2bc41e2bc6686f042686e1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20A=2E=20Michel=C3=A9n=20Str=C3=B6fer?= Date: Wed, 11 Oct 2023 17:47:12 -0400 Subject: [PATCH 1/6] Static cases (no optimization). Closes #249 (#277) * allow zero length x_opt * Update wecopttool/core.py --- wecopttool/core.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/wecopttool/core.py b/wecopttool/core.py index 1a1f0b42..e3d5d4ce 100644 --- a/wecopttool/core.py +++ b/wecopttool/core.py @@ -629,7 +629,7 @@ def solve(self, callback: Optional[TStateFunction] = None, ) -> tuple[Dataset, Dataset, OptimizeResult]: """Simulate WEC dynamics using a pseudo-spectral solution - method and returns the raw results dictionary produced by + method and returns the raw results dictionary produced by :py:func:`scipy.optimize.minimize`. Parameters @@ -692,7 +692,7 @@ def solve(self, If the optimizer fails for any reason other than maximum number of states, i.e. for exit modes other than 0 or 9. See :py:mod:`scipy.optimize` for exit mode details. - + Examples -------- The :py:meth:`wecopttool.WEC.solve` method only returns the @@ -801,10 +801,11 @@ def scaled_resid_fun(x): if callback is None: def callback_scipy(x): x_wec, x_opt = self.decompose_state(x) + max_x_opt = np.nan if np.size(x_opt)==0 else np.max(np.abs(x_opt)) _log.info("[max(x_wec), max(x_opt), obj_fun(x)]: " + f"[{np.max(np.abs(x_wec)):.2e}, " - + f"{np.max(np.abs(x_opt)):.2e}, " - + f"{np.max(obj_fun_scaled(x)):.2e}]") + + f"{max_x_opt:.2e}, " + + f"{obj_fun_scaled(x):.2e}]") else: def callback_scipy(x): x_wec, x_opt = self.decompose_state(x) @@ -867,7 +868,7 @@ def post_process(self, Dynamic responses in the frequency-domain. results_td Dynamic responses in the time-domain. - + Examples -------- The :py:meth:`wecopttool.WEC.solve` method only returns the @@ -1861,7 +1862,7 @@ def check_linear_damping( degree of freedom is frequency dependent or not. If :python:`True`, the damping correction is applied to :python:`friction` and shifts the damping for all frequencies. If :python:`False`, the damping correction - is applied to :python:`radiation_damping` and only shifts the + is applied to :python:`radiation_damping` and only shifts the damping for frequencies with negative damping values. Default is :python:`True`. """ From f154b1f6210c89c050f88bcf168a521ac02ecab5 Mon Sep 17 00:00:00 2001 From: Michael Devin Date: Wed, 11 Oct 2023 16:21:52 -0600 Subject: [PATCH 2/6] Fix CI random failures (#275) * added handling for subsets with multiple values * removed no-longer-relevant docstring change --- wecopttool/core.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/wecopttool/core.py b/wecopttool/core.py index e3d5d4ce..19d0c0e9 100644 --- a/wecopttool/core.py +++ b/wecopttool/core.py @@ -2402,18 +2402,16 @@ def subset_close( raise ValueError("Elements in set_b not unique") ind = [] - tmp_result = [False for _ in range(len(set_a))] - for subset_element in set_a: - for set_element in set_b: - if np.isclose(subset_element, set_element, rtol, atol, equal_nan): - tmp_set_ind = np.where( - np.isclose(set_element, set_b , rtol, atol, equal_nan)) - tmp_subset_ind = np.where( - np.isclose(subset_element, set_a , rtol, atol, - equal_nan)) - ind.append( int(tmp_set_ind[0]) ) - tmp_result[ int(tmp_subset_ind[0]) ] = True - subset = all(tmp_result) + for el in set_a: + a_in_b = np.isclose(set_b, el, + rtol=rtol, atol=atol, equal_nan=equal_nan) + if np.sum(a_in_b) == 1: + ind.append(np.flatnonzero(a_in_b)[0]) + if np.sum(a_in_b) > 1: + _log.warning('Multiple matching elements in subset, ' + + 'selecting closest match.') + ind.append(np.argmin(np.abs(a_in_b - el))) + subset = len(set_a) == len(ind) ind = ind if subset else [] return subset, ind From ca587ad05e29dfe20c21c238fd0275cb50b2d710 Mon Sep 17 00:00:00 2001 From: Michael Devin Date: Thu, 12 Oct 2023 09:27:39 -0600 Subject: [PATCH 3/6] Allowing Python 3.11 (#278) * added Python 3.11 to CI workflow * updated supported versions in README * updated GitHub workflows to default to 3.11 * updated example developer installation to use 3.11 * remove Python 3.9 as a supported version --- .github/CONTRIBUTING.md | 4 ++-- .github/workflows/push.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- README.md | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6436edd9..5697d656 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -10,7 +10,7 @@ Community contributions are welcomed! 🎊 Using `conda` this looks like: ```bash -conda create -n wecopttool python=3.10 +conda create -n wecopttool python=3.11 conda activate wecopttool conda install -c conda-forge capytaine wavespectra git clone git@github.com:/WecOptTool.git @@ -22,7 +22,7 @@ And using `pip`: ```bash git clone git@github.com:/WecOptTool.git cd WecOptTool -python3.10 -m venv .venv +python3.11 -m venv .venv . .venv/bin/activate pip install -e .[dev] ``` diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 8a8c623b..b8cf15ca 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] - python-version: ["3.9", "3.10"] # CHANGE: Python version + python-version: ["3.10", "3.11"] # CHANGE: Python version steps: # Checkout the WecOptTool repo @@ -126,7 +126,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: '3.10' # CHANGE: Python version + python-version: '3.11' # CHANGE: Python version - name: Install dependencies run: sudo apt-get install libglu1 pandoc gifsicle diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7116888..8586d38b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' - name: Build a binary wheel and a source tarball run: | @@ -47,7 +47,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' - name: Install dependencies run: sudo apt-get install libglu1 pandoc gifsicle diff --git a/README.md b/README.md index 5d075128..88667295 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The Wave Energy Converter Design Optimization Toolbox (WecOptTool) allows users Refer to [WecOptTool documentation](https://sandialabs.github.io/WecOptTool/) for more information, including project overview, tutorials, theory, and API documentation. ## Getting started -WecOptTool requires Python >= 3.8. Python 3.9 & 3.10 are supported. +WecOptTool requires Python >= 3.8. Python 3.10 & 3.11 are supported. It is strongly recommended you create a dedicated virtual environment (e.g., using `conda`, `venv`, etc.) before installing `wecopttool`. **Option 1** - using `Conda` (requires having `conda-forge` added as a channel in your environment, see instructions [here](https://conda-forge.org/docs/user/introduction.html#how-can-i-install-packages-from-conda-forge)): From 21c1eccdaa96da5c327e59988c6e61ec2448102d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20A=2E=20Michel=C3=A9n=20Str=C3=B6fer?= Date: Thu, 12 Oct 2023 16:04:44 -0400 Subject: [PATCH 4/6] Make residual function more accessible. Closes #253 (#276) --- tests/test_integration.py | 14 +++++++------- wecopttool/core.py | 23 +++++++++++++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index d837064f..46ed235e 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -44,7 +44,7 @@ def p_controller_pto(): @pytest.fixture(scope='module') def pi_controller_pto(): - """Basic PTO: proportional-integral (PI) controller, 1 DOF, mechanical + """Basic PTO: proportional-integral (PI) controller, 1 DOF, mechanical power.""" ndof = 1 pto = wot.pto.PTO(ndof=ndof, kinematics=np.eye(ndof), @@ -181,7 +181,7 @@ def my_callback(my_wec, x_wec, x_opt, wave): [Bounds(lb=kplim, ub=0), ((kplim, 0),)]) def test_solve_bounds(bounds_opt, wec_from_bem, regular_wave, p_controller_pto): - """Confirm that bounds are not violated and scale correctly when + """Confirm that bounds are not violated and scale correctly when passing bounds argument as both as Bounds object and a tuple""" # replace unstructured controller with propotional controller @@ -212,9 +212,9 @@ def test_same_wec_init(wec_from_bem, x_wec_0 = np.random.randn(wec_from_bem.nstate_wec) np.random.seed(1) x_opt_0 = np.random.randn(wec_from_bem.nstate_wec) - bem_res = wec_from_bem._resid_fun(x_wec_0, x_opt_0, waves) - fb_res = wec_from_floatingbody._resid_fun(x_wec_0, x_opt_0, waves) - imp_res = wec_from_impedance._resid_fun(x_wec_0, x_opt_0, waves) + bem_res = wec_from_bem.residual(x_wec_0, x_opt_0, waves) + fb_res = wec_from_floatingbody.residual(x_wec_0, x_opt_0, waves) + imp_res = wec_from_impedance.residual(x_wec_0, x_opt_0, waves) assert fb_res == approx(bem_res, rel=0.01) assert imp_res == approx(bem_res, rel=0.01) @@ -249,7 +249,7 @@ def test_p_controller_resonant_wave(self, mass, hstiff, hydro_impedance): - """Proportional controller should match optimum for natural resonant + """Proportional controller should match optimum for natural resonant wave""" f_add = {"PTO": p_controller_pto.force_on_wec} @@ -320,7 +320,7 @@ def test_unstructured_controller_irregular_wave(self, mass, hstiff, hydro_impedance): - """Unstructured (numerical optimal) controller matches optimal for any + """Unstructured (numerical optimal) controller matches optimal for any irregular wave when unconstrained""" f_add = {"PTO": pto.force_on_wec} diff --git a/wecopttool/core.py b/wecopttool/core.py index 19d0c0e9..0ac3e025 100644 --- a/wecopttool/core.py +++ b/wecopttool/core.py @@ -601,7 +601,21 @@ def from_impedance( inertia_in_forces=True, ndof=shape[0]) return wec - def _resid_fun(self, x_wec, x_opt, waves): + def residual(self, x_wec: ndarray, x_opt: ndarray, waves: Dataset, + ) -> float: + """ + Return the residual of the dynamic equation (r = m⋅a-ÎŁf). + + Parameters + ---------- + x_wec + WEC state vector. + x_opt + Optimization (control) state. + waves + :py:class:`xarray.Dataset` with the structure and elements + shown by :py:mod:`wecopttool.waves`. + """ if not self.inertia_in_forces: ri = self.inertia(self, x_wec, x_opt, waves) else: @@ -767,7 +781,7 @@ def new_fun(x): def scaled_resid_fun(x): x_s = x/scale x_wec, x_opt = self.decompose_state(x_s) - return self._resid_fun(x_wec, x_opt, waves) + return self.residual(x_wec, x_opt, waves) eq_cons = {'type': 'eq', 'fun': scaled_resid_fun} if use_grad: @@ -802,13 +816,14 @@ def scaled_resid_fun(x): def callback_scipy(x): x_wec, x_opt = self.decompose_state(x) max_x_opt = np.nan if np.size(x_opt)==0 else np.max(np.abs(x_opt)) - _log.info("[max(x_wec), max(x_opt), obj_fun(x)]: " + _log.info("Scaled [max(x_wec), max(x_opt), obj_fun(x)]: " + f"[{np.max(np.abs(x_wec)):.2e}, " + f"{max_x_opt:.2e}, " + f"{obj_fun_scaled(x):.2e}]") else: def callback_scipy(x): - x_wec, x_opt = self.decompose_state(x) + x_s = x/scale + x_wec, x_opt = self.decompose_state(x_s) return callback(self, x_wec, x_opt, waves) # optimization problem From 8935e9e7164fd3a561c9564699171cef3d1f3757 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Thu, 12 Oct 2023 19:20:14 -0600 Subject: [PATCH 5/6] Documentation improvements/updates (#267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * typographical errors * move MATLAB version note to end (not so relevant anymore) * add recent papers * add volume, issue, page to Michelen2023 * more explicit guidance on conda environments * add new/missing papers * links to webinars + companion notebooks * minor typos * how to disable docs build link check + notebooks * note mamba is an option * ignore link check for Sandia webinars pages * removed disclaimer for Windows capytaine install * fixed broken GitHub link on Releasing documentation page * fixed typo in derivative docstrings * added expanded installation instructions * Fixed markdown levels in installation instructions * minor formatting/grammar fixes * Update INSTALLATION.md Co-authored-by: Carlos A. MichelĂ©n Ströfer * rewrote Mac install instructions, lots of cleanup * Update README.md --------- Co-authored-by: mcdevin Co-authored-by: Michael Devin Co-authored-by: Carlos A. MichelĂ©n Ströfer --- .github/CONTRIBUTING.md | 15 +++++++++ .github/RELEASING.md | 2 +- INSTALLATION.md | 45 +++++++++++++++++++++++++ README.md | 12 +++++-- docs/source/conf.py | 3 +- docs/source/index.rst | 6 ++-- docs/source/references.rst | 18 +++++++++- docs/source/theory.rst | 13 ++++---- docs/source/tutorials.rst | 13 +++----- docs/source/wecopttool_refs.bib | 58 ++++++++++++++++++++++++--------- wecopttool/core.py | 6 ++-- 11 files changed, 150 insertions(+), 41 deletions(-) create mode 100644 INSTALLATION.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5697d656..d6ddbcc2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -76,6 +76,21 @@ The documentation uses the Jupyter notebook tutorials in the `examples` director When building the documentation locally you will need to have installed [pandoc](https://pandoc.org/installing.html) and [gifsicle](https://github.com/kohler/gifsicle). We recommend installing pandoc using its Anaconda distribution: `conda install -c conda-forge pandoc`. +**NOTE:** it may be expedient at times to: + + 1. **Avoid running the tutorial notebooks:** Add [`nbsphinx_execute = 'never'`](https://nbsphinx.readthedocs.io/en/0.9.3/configuration.html#nbsphinx_execute) to `docs/source/conf.py` + 2. **Disable the link check operation:** Comment out the `linkcheck` call in `docs/build_docs.py` + +```python +if __name__ == '__main__': + source.make_theory_animations + # linkcheck() + html() + cleanup() +``` + +Make sure not to commit these changes! + ### Editing the tutorials The tutorials are used as part of the Documentation. Before pushing any changes make sure that the saved version of the notebooks are clear (no cells run and no results). diff --git a/.github/RELEASING.md b/.github/RELEASING.md index 3839a422..15d38664 100644 --- a/.github/RELEASING.md +++ b/.github/RELEASING.md @@ -24,7 +24,7 @@ For details see the [Python packaging user guide](https://packaging.python.org/e The PyPI package is created and uploaded automatically to [TestPyPI](https://test.pypi.org/) and [PyPI](https://pypi.org/) on every GitHub release. This is done sequentially, so that if *TestPyPi* fails the package is not pushed to `PyPi`. -See the [GitHub workflow](https://github.com/sandialabs/WecOptTool/blob/main/.github/workflows/publish-to-pypi.yml). +See the [GitHub release workflow](https://github.com/sandialabs/WecOptTool/blob/main/.github/workflows/release.yml). **NOTE:** While GitHub lets you delete a release and then create a new one with the same name, PyPI does not. You can delete releases but you cannot upload a package with the same version as a previous one (even a deleted one). diff --git a/INSTALLATION.md b/INSTALLATION.md new file mode 100644 index 00000000..57a2c07d --- /dev/null +++ b/INSTALLATION.md @@ -0,0 +1,45 @@ +# Installation for users + +## Software requirements +WecOptTool is supported on Windows, MacOS, and Linux. It requires Python 3.8 or higher. [Xcode](https://developer.apple.com/xcode/) may also be required on Mac. + + +## Creating a virtual environment +WecOptTool depends on many other Python packages, which can be organized into a *virtual environment*. Setting up a dedicated virtual environment allows for easier and more organized management of Python packages for your projects. The instructions below will walk you through creating a dedicated virtual environment and installing WecOptTool. + +Several tools exist that can both manage virtual environment and install Python pacakges. We provide instructions for two such tools: + +* If you are brand new to Python, or currently use Conda and want to try a much faster alternative, [click here](#installing-using-mamba) for installation instructions using **Mamba**. +* If you already have Anaconda/Miniconda installed on your computer, [click here](#installing-using-conda) for instructions using **Conda**. + +### Installing using Mamba +1. Download Miniforge3 (which contains Mamba) for your operating system [here](https://github.com/conda-forge/miniforge#download). +2. Double-click on the file you just downloaded and follow the prompts on the new window to install Miniforge3. When the "Advanced Installation Options" prompt comes up, check the box next to "Add Miniforge3 to my PATH environment variable". All the other default selections should work. +3. After installation completes, open a command prompt or terminal window and copy/paste the following code to confirm Mamba installed correctly. If installed correctly, the terminal should print both a Mamba and Conda version number (since Conda is used for some Mamba functions): + ```bash + mamba --version + ``` +4. Copy/paste the following code to create a new virtual environment named `wot`, activate the environment, and install WecOptTool and its dependencies in the environment. Feel free to replace `wot` in the first two lines with a different environment name if you would like: + ```bash + mamba create -n wot + mamba activate wot + mamba install wecopttool jupyter + pip install gmsh pygmsh meshio + ``` + +### Installing using Conda +1. Download Miniconda3 (which contains Conda) for your operating system [here](https://docs.conda.io/projects/miniconda/en/latest/index.html). +2. Double-click on the file you just downloaded and follow the prompts on the new window to install Miniconda3. When the "Advanced Installation Options" prompt comes up, check the box next to "Add Miniforge3 to my PATH environment variable". All the other default selections should work. +3. After installation completes, open a command prompt or terminal window (close any command/terminal windows you had open previously) and copy/paste the following code to confirm Conda installed correctly. If installed correctly, the terminal should print a Conda version number: + ```bash + conda --version + ``` +4. Copy/paste the following code to create a new virtual environment named `wot`, activate the environment, and install WecOptTool and its dependencies in the environment. Feel free to replace `wot` in the third and fourth lines with a different environment name if you would like: + ```bash + conda config --add channels conda-forge + conda config --set channel_priority strict + conda create -n wot + conda activate wot + conda install wecopttool jupyter + pip install gmsh pygmsh meshio + ``` \ No newline at end of file diff --git a/README.md b/README.md index 88667295..392e8cb4 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,12 @@ The Wave Energy Converter Design Optimization Toolbox (WecOptTool) allows users Refer to [WecOptTool documentation](https://sandialabs.github.io/WecOptTool/) for more information, including project overview, tutorials, theory, and API documentation. ## Getting started +**If you are brand new to Python and/or want detailed installation instructions, [click here](https://github.com/sandialabs/WecOptTool/INSTALLATION.md).** + WecOptTool requires Python >= 3.8. Python 3.10 & 3.11 are supported. -It is strongly recommended you create a dedicated virtual environment (e.g., using `conda`, `venv`, etc.) before installing `wecopttool`. +It is strongly recommended you create a dedicated virtual environment (e.g., using [`conda`](https://www.anaconda.com/), [`mamba`](https://mamba.readthedocs.io/en/latest/), `venv`, etc.) before installing WecOptTool. + +From your dedicated environment, you can install WecOptTool via `conda`, `pip`, or `mamba`: **Option 1** - using `Conda` (requires having `conda-forge` added as a channel in your environment, see instructions [here](https://conda-forge.org/docs/user/introduction.html#how-can-i-install-packages-from-conda-forge)): @@ -25,7 +29,11 @@ conda install -c conda-forge wecopttool pip install wecopttool ``` -This approach is not recommended for Windows users since compiling `capytaine` on Windows requires [extra steps](https://github.com/capytaine/capytaine/issues/115). +**Option 3** - using `Mamba`: + +```bash +mamba install wecopttool +``` **Geometry module and tutorials** diff --git a/docs/source/conf.py b/docs/source/conf.py index a79ef7f6..ef13e3ec 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,7 +20,7 @@ project = 'WecOptTool' copyright = ( '2020 National Technology & Engineering Solutions of Sandia, ' + - 'LLC(NTESS). ' + + 'LLC (NTESS). ' + 'Under the terms of Contract DE-NA0003525 with NTESS, the U.S. ' + 'Government retains certain rights in this software' ) @@ -62,6 +62,7 @@ def setup(app): 'https://doi.org/10.2172/1330189', 'https://sandialabs.github.io/WecOptTool/*', 'https://doi.org/10.1080/17445302.2015.1089052', + 'https://digitalops.sandia.gov/*', ] linkcheck_request_headers = { diff --git a/docs/source/index.rst b/docs/source/index.rst index abccb971..2bb0b048 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,9 +18,6 @@ This allows for the optimization study (e.g., to find the WEC geometry that resu The code is written to support arbitrary optimization studies, control strategies, and constraints. The code is written as a Python package and the source code can be found in the `GitHub repository`_. -.. note:: - A MATLAB version of WecOptTool was previously released and, while no longer being developed, is still available on GitHub: `WecOptTool-MATLAB`_. - Getting Started =============== See installation instructions in the `GitHub repository`_. @@ -33,6 +30,9 @@ WecOptTool is developed by `Sandia National Laboratories`_. The developers would like to acknowledge funding support from the US Department of Energy's Water Power Technologies Office. The developers would also like to acknowledge benefit from past collaborations with `Data Only Greater`_ and the `Oregon State University Design Engineering Lab`_. +.. note:: + A MATLAB version of WecOptTool was previously released and, while no longer being developed, is still available on GitHub: `WecOptTool-MATLAB`_. + Sandia National Laboratories is a multi-mission laboratory managed and operated by National Technology and Engineering Solutions of Sandia, LLC., a wholly owned subsidiary of Honeywell International, Inc., for the U.S. Department of Energy's National Nuclear Security Administration under contract DE-NA0003525. .. _GitHub repository: https://github.com/sandialabs/WecOptTool diff --git a/docs/source/references.rst b/docs/source/references.rst index 99be4d74..dcda36f8 100644 --- a/docs/source/references.rst +++ b/docs/source/references.rst @@ -1,7 +1,23 @@ References ========== + +General resources +----------------- + + * Companion notebooks to published papers: + * `Control Co-Design of Power Take-off Systems for Wave Energy Converters using WecOptTool `_ (:cite:t:`Michelen2023`:) + * `Incorporating empirical nonlinear efficiency into control co-optimization of a real world heaving point absorber using WECOPTTOOL `_ (:cite:t:`Gaebele:2023wf`:) + * `Control co-design and uncertainty analysis of the LUPA's PTO using WecOptTool `_ (:cite:t:`Strofer:2023vw`:) + * Webinar recordings: + * `October, 2022 `_ + * `February, 2022 `_ + +Bibliography +------------ .. bibliography:: wecopttool_refs.bib :style: unsrt Falnes2002 - Michelen2023 \ No newline at end of file + Grasberger:2023aa + Strofer:2023vw + Coe2020Initial diff --git a/docs/source/theory.rst b/docs/source/theory.rst index f316d6e0..c5b9f59c 100644 --- a/docs/source/theory.rst +++ b/docs/source/theory.rst @@ -3,14 +3,13 @@ Theory & Practice .. note:: This theory section is intended to give a very high-level understanding of key concepts for WecOptTool. - For a more detailed explanation, please see :cite:`Bacelli2014Optimal,Bacelli2014Numerical,Coe2020Initial`. - A journal paper will be available soon. + For a more detailed explanation, please see :cite:`Michelen2023,Bacelli2014Optimal,Bacelli2014Numerical`. Basic concept ------------- -WecOptTool uses a pseudo-spectral method :cite:`Elnagar1995pseudospectral` to perform two tasks synchronously: +WecOptTool uses a pseudo-spectral method :cite:`Elnagar1995pseudospectral` to perform two tasks simultaneously: 1. Optimize the solution for the desired objective function (e.g. power generation) 2. Simulate the wave energy converter (WEC) dynamics @@ -83,7 +82,7 @@ When creating this frequency array, consider: * Exciting frequencies of the wave and, if you expect a nonlinear response, superharmonics of the exciting frequencies * Power absorption occurs at two times the exciting frequencies (only important for visualization) - * The fundamental frequency is also the frequency step (:math:`f_1=\Delta f`); set this sufficiently small to resolve the wave spectra and frequency response functios of interest + * The fundamental frequency is also the frequency step (:math:`f_1=\Delta f`); set this sufficiently small to resolve the wave spectra and frequency response functions of interest Automatic differentiation ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +126,7 @@ Here, the kinematics matrix, :math:`K`, is defined as the linear transformation p = K x :label: kinematics -The relationship :math:`p(x)` is typically referred to as the *backward kinematics*, in the field of robotics. If the WEC were considered to be a robot it's hydrodynamic body would be equivalent to an endeffector represented in a global coordinate frame. The PTO positions would be equivalent to joint positions in local coordinates. +The relationship :math:`p(x)` is typically referred to as the *backward kinematics*, in the field of robotics. If the WEC were considered to be a robot it's hydrodynamic body would be equivalent to an end effector represented in a global coordinate frame. The PTO positions would be equivalent to joint positions in local coordinates. The matrix :math:`K` has a size equal to the number of DOFs of the PTOs times the number of DOFs of the WEC. Note, however that the real kinematics might not be linear. Equation :eq:`kinematics` represents a linearization of :math:`p(x)` about the mean :math:`x=0` position, with the matrix :math:`K` being the inverse Jacobian of :math:`p(x)` at :math:`x=0`. @@ -138,7 +137,7 @@ The transpose of :math:`K` is used to transform the PTO forces in PTO frame, :ma f_w = K^T f_p :label: k -This relationship can be derived from conservation of energy in both frames, and using the definition in Equation :eq:`kinematics`: +This relationship can be derived from conservation of energy in both frames, and using the definition in :eq:`kinematics`: .. math:: f_w^T x = f_p^T p \\ @@ -149,7 +148,7 @@ This relationship can be derived from conservation of energy in both frames, and Troubleshooting --------------- -If your simlation is not behaving as expected, consider some of the general troubleshooting steps below: +If your simulation is not behaving as expected, consider some of the general troubleshooting steps below: * Check that the hydrodynamic coefficients are displaying expected behavior for high frequencies: diff --git a/docs/source/tutorials.rst b/docs/source/tutorials.rst index 5ec1b6a4..3fd20495 100644 --- a/docs/source/tutorials.rst +++ b/docs/source/tutorials.rst @@ -1,6 +1,6 @@ Tutorials ========= -This section presents two tutorials illustrating the application of WecOptTool. +This section presents tutorials illustrating the application of WecOptTool. The tutorials are written as Jupyter Notebooks and are available in the `GitHub repository`_. The first tutorial uses the `WaveBot`_ WEC, which is a single-body WEC developed at Sandia. @@ -8,18 +8,15 @@ The tutorial has three sequential parts of increased complexity. The first and second parts solve only the inner optimization loop for optimal mechanical and electrical power, respectively. The third part builds on the second to solve a design optimization problem, using both the inner and outer optimization loops, and is more reflective of the optimization problems WecOptTool is designed to solve. - - :doc:`_examples/tutorial_1_WaveBot`: Three part example of using the inner and outer optimization loops for a simple control co-design study. +The second and third tutorials use the `AquaHarmonics`_ and `LUPA`_ WECs, respectively, and provide more robust optimization examples illustrating more complex cases of the WEC body, power take-off, applied forces, and constraints. +These tutorials each have two parts, which are similar in structure to the second and third parts of Tutorial 1. -The second and third tutorials uses the `AquaHarmonics`_ and `LUPA`_ WECs respectively, and provides more robust optimization examples illustrating more complex cases of the WEC body, power take-off, applied forces, and constraints. -The tutorials each have two parts, which are similar in structure to the second and third parts of Tutorial 1. - - - - :doc:`_examples/tutorial_2_AquaHarmonics`: Two part example with a realistic power take-off system and co-design study. + - :doc:`_examples/tutorial_2_AquaHarmonics`: Two part example with a realistic power take-off system and co-design study. You can find an extended version - :doc:`_examples/tutorial_3_LUPA`: Two part example with multiple bodies, multiple degrees of freedom, irregular waves, a mooring system, and realistic constraints. -The fourth tutorial uses the `Pioneer` WEC model, which includes a unique pitch resonator PTO system. This tutorial illustrates how to use WecOptTool to implement and optimize control strategies for less common PTO archetypes. +The fourth tutorial uses the `Pioneer WEC` model, which includes a unique pitch resonator PTO system. This tutorial illustrates how to use WecOptTool to implement and optimize control strategies for less common PTO archetypes. - :doc:`_examples/tutorial_4_Pioneer`: Example with custom PTO physics and modeling both hydrodynamic and non-hydrodynamic degrees of freedom. diff --git a/docs/source/wecopttool_refs.bib b/docs/source/wecopttool_refs.bib index 8b9ea6cf..fe4cf264 100644 --- a/docs/source/wecopttool_refs.bib +++ b/docs/source/wecopttool_refs.bib @@ -1,12 +1,46 @@ + +@inproceedings{Gaebele:2023wf, + address = {Melbourne, Australia}, + author = {Daniel T. Gaebele and Carlos A Michel{\'e}n~Str{\"o}fer and Michael C. Devin and Jeff T. Grasberger and Ryan G. Coe and Giorgio Bacelli}, + booktitle = {Proceedings of the ASME 2023 42nd International Conference on Ocean, Offshore and Arctic Engineering (OMAE2023)}, + date-added = {2023-01-12 14:02:25 -0700}, + date-modified = {2023-10-03 08:41:16 -0600}, + month = {June}, + series = {International Conference on Ocean, Offshore and Arctic Engineering}, + title = {INCORPORATING EMPIRICAL NONLINEAR EFFICIENCY INTO CONTROL CO-OPTIMIZATION OF A REAL WORLD HEAVING POINT ABSORBER USING {WECOPTTOOL}}, + year = {2023}} + +@inproceedings{Strofer:2023vw, + address = {Bilbao, Spain}, + author = {Carlos A Michel{\'e}n~Str{\"o}fer and Ryan G. Coe and others}, + booktitle = {Proceedings of the 15th European Wave and Tidal Energy Conference (EWTEC2023)}, + date-added = {2023-02-09 07:51:06 -0700}, + date-modified = {2023-09-08 08:38:43 -0600}, + doi = {10.36688/ewtec-2023-288}, + month = {September}, + title = {Control co-design and uncertainty analysis of the {LUPA}'s {PTO} using {WecOptTool}}, + year = {2023}} + +@inproceedings{Grasberger:2023aa, + address = {Bilbao, Spain}, + author = {Jeff T. Grasberger and Ryan G. Coe and Jonathan Bird and Giorgio Bacelli and Alex Hagm{\"u}ller and Carlos Michel{\'e}n~Str{\"o}fer}, + booktitle = {Proceedings of the 15th European Wave and Tidal Energy Conference (EWTEC2023)}, + date-added = {2023-02-22 13:15:35 -0700}, + date-modified = {2023-09-08 08:40:15 -0600}, + doi = {10.36688/ewtec-2023-510}, + month = {September}, + title = {Maximizing Wave Energy Converter Power Extraction by Utilizing a Variable Negative Stiffness Magnetic Spring}, + year = {2023}} + @article{Michelen2023, author={Ströfer, Carlos A. MichelĂ©n and Gaebele, Daniel T. and Coe, Ryan G. and Bacelli, Giorgio}, journal={IEEE Transactions on Sustainable Energy}, - title={Control Co-Design of Power Take-off Systems for Wave Energy Converters using WecOptTool}, + title={{Control Co-Design of Power Take-off Systems for Wave Energy Converters using WecOptTool}}, year={2023}, - volume={}, - number={}, - pages={1-11}, + number = {4}, + pages = {2157-2167}, + volume = {14}, doi={10.1109/TSTE.2023.3272868}} @phdthesis{Bacelli2014Optimal, @@ -18,8 +52,7 @@ @phdthesis{Bacelli2014Optimal title = {Optimal control of wave energy converters}, type = {{PhD}}, url = {http://mural.maynoothuniversity.ie/6753/}, - year = {2014}, - bdsk-url-1 = {http://mural.maynoothuniversity.ie/6753/}} + year = {2014}} @article{Elnagar1995pseudospectral, author = {Elnagar, G. and Kazemi, M.A. and Razzaghi, M.}, @@ -31,8 +64,7 @@ @article{Elnagar1995pseudospectral pages = {1793-1796}, title = {The pseudospectral Legendre method for discretizing optimal control problems}, volume = {40}, - year = {1995}, - bdsk-url-1 = {https://doi.org/10.1109/9.467672}} + year = {1995}} @article{Coe2020Initial, author = {Ryan G. Coe and Giorgio Bacelli and Sterling Olson and Vincent S. Neary and Mathew B. R. Topper}, @@ -45,9 +77,7 @@ @article{Coe2020Initial pages = {441--449}, title = {{Initial conceptual demonstration of control co-design for WEC optimization}}, volume = {6}, - year = {2020}, - abstract = {While some engineering fields have benefited from systematic design optimization studies, wave energy converters have yet to successfully incorporate such analyses into practical engineering workflows. The current iterative approach to wave energy converter design leads to sub-optimal solutions. This short paper presents an open-source MATLAB toolbox for performing design optimization studies on wave energy converters where power take-off behavior and realistic constraints can be easily included. This tool incorporates an adaptable control co-design approach, in that a constrained optimal controller is used to simulate device dynamics and populate an arbitrary objective function of the user's choosing. A brief explanation of the tool's structure and underlying theory is presented. To demonstrate the capabilities of the tool, verify its functionality, and begin to explore some basic wave energy converter design relationships, three conceptual case studies are presented. In particular, the importance of considering (and constraining) the magnitudes of device motion and forces in design optimization is shown.}, - bdsk-url-1 = {https://doi.org/10.36227/techrxiv.12928898.v1}} + year = {2020}} @book{Falnes2002, address = {Cambridge; New York}, @@ -55,8 +85,7 @@ @book{Falnes2002 doi = {10.1017/CBO9780511754630}, publisher = {Cambridge University Press}, title = {Ocean Waves and Oscillating Systems}, - year = {2002}, - bdsk-url-1 = {https://doi.org/10.1017/CBO9780511754630}} + year = {2002}} @article{Bacelli2014Numerical, author = {Bacelli, Giorgio and Ringwood, John V}, @@ -68,5 +97,4 @@ @article{Bacelli2014Numerical publisher = {IEEE}, title = {Numerical optimal control of wave energy converters}, volume = {6}, - year = {2014}, - bdsk-url-1 = {https://doi.org/10.1109/TSTE.2014.2371536}} + year = {2014}} diff --git a/wecopttool/core.py b/wecopttool/core.py index 0ac3e025..4af71a0b 100644 --- a/wecopttool/core.py +++ b/wecopttool/core.py @@ -1072,7 +1072,7 @@ def time_mat(self) -> ndarray: """Matrix to create time-series from Fourier coefficients. For some array of Fourier coefficients :python:`x` - (excluding the sine component of the highest freequency), size + (excluding the sine component of the highest frequency), size :python:`(2*nfreq, ndof)`, the time series is obtained via :python:`time_mat @ x`, also size :python:`(2*nfreq, ndof)`. @@ -1085,7 +1085,7 @@ def derivative_mat(self) -> ndarray: some quantity. For some array of Fourier coefficients :python:`x` - (excluding the sine component of the highest freequency), size + (excluding the sine component of the highest frequency), size :python:`(2*nfreq, ndof)`, the Fourier coefficients of the derivative of :python:`x` are obtained via :python:`derivative_mat @ x`. @@ -1098,7 +1098,7 @@ def derivative2_mat(self) -> ndarray: some quantity. For some array of Fourier coefficients :python:`x` - (excluding the sine component of the highest freequency), size + (excluding the sine component of the highest frequency), size :python:`(2*nfreq, ndof)`, the Fourier coefficients of the second derivative of :python:`x` are obtained via :python:`derivative2_mat @ x`. From 4cc747eb9a2e49d93317427370183ff2373c15bb Mon Sep 17 00:00:00 2001 From: Michael Devin Date: Thu, 12 Oct 2023 19:22:33 -0600 Subject: [PATCH 6/6] Fixed install instructions link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 392e8cb4..a972aeec 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The Wave Energy Converter Design Optimization Toolbox (WecOptTool) allows users Refer to [WecOptTool documentation](https://sandialabs.github.io/WecOptTool/) for more information, including project overview, tutorials, theory, and API documentation. ## Getting started -**If you are brand new to Python and/or want detailed installation instructions, [click here](https://github.com/sandialabs/WecOptTool/INSTALLATION.md).** +**If you are brand new to Python and/or want detailed installation instructions, [click here](https://github.com/sandialabs/WecOptTool/blob/main/INSTALLATION.md).** WecOptTool requires Python >= 3.8. Python 3.10 & 3.11 are supported. It is strongly recommended you create a dedicated virtual environment (e.g., using [`conda`](https://www.anaconda.com/), [`mamba`](https://mamba.readthedocs.io/en/latest/), `venv`, etc.) before installing WecOptTool.