Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
4ae2687
torque 2026 loss factors and pie charts
ptrbortolotti Dec 29, 2025
fc6647a
wip [skip ci]
ptrbortolotti Dec 29, 2025
a05a348
more wip, not yet done [skip ci]
ptrbortolotti Dec 29, 2025
de356f8
15mw is running [skip ci]
ptrbortolotti Dec 29, 2025
371cdd5
updates to following examples
ptrbortolotti Dec 29, 2025
c1fa7c6
fix examples 7 and 8 [skip ci]
ptrbortolotti Dec 29, 2025
3d4475a
progress but several tests still not passing [skip ci]
ptrbortolotti Dec 29, 2025
019c600
progress [skip ci]
ptrbortolotti Dec 29, 2025
2f6fa78
fix 06 tests, more to do [skip ci]
ptrbortolotti Dec 30, 2025
89bcac5
may fix tests 1 and 2 [skip ci]
ptrbortolotti Dec 30, 2025
529e030
tests should be passing now
ptrbortolotti Dec 30, 2025
a830153
kick out nrel5mw, not running and not relevant
ptrbortolotti Dec 30, 2025
fadece8
fix a couple white spaces from pre-commit
ptrbortolotti Jan 5, 2026
6dcceff
validate yaml with windIO [skip ci]
ptrbortolotti Jan 5, 2026
fec5005
make progress [skip ci]
ptrbortolotti Jan 5, 2026
3ebb560
fix name rotated beam [skip ci]
ptrbortolotti Jan 5, 2026
a23721c
fix yaml example 6 [skip ci]
ptrbortolotti Jan 5, 2026
0858096
fix box beam coordinates and twist in degrees. start running tests. s…
ptrbortolotti Jan 5, 2026
c5e9ba0
fix a couple of issues
ptrbortolotti Jan 5, 2026
5083b3f
work on example 7 and reg tests 7
ptrbortolotti Jan 5, 2026
6c5c24d
try fixing iea15 and iea22 tests
ptrbortolotti Jan 5, 2026
8deed1d
update refs IEA15-22
ptrbortolotti Jan 5, 2026
86317fc
fix precommit
ptrbortolotti Jan 5, 2026
a799b5f
two tests #7 still failin [skip ci]
ptrbortolotti Jan 6, 2026
4e19418
two tests still failing [skip ci]
ptrbortolotti Jan 6, 2026
7c362f8
Fixed one of the viscoelastic tests, still have an issue with other. …
JustinPorter88 Jan 6, 2026
253af2a
tests might pass now
ptrbortolotti Jan 6, 2026
2b36c17
try again, lower tolerance on stiffness checks
ptrbortolotti Jan 7, 2026
21126a7
Specifying windIO versions more strictly + adding fatal errors.
JustinPorter88 Jan 8, 2026
1b12a71
Merge branch 'windIO2p0p1' of github.com:WISDEM/SONATA into windIO2p0p1
JustinPorter88 Jan 8, 2026
a0ee446
Only doing analytical viscoelastic calcs when appropriate (single mat…
JustinPorter88 Jan 8, 2026
b41f555
work on example 8, where anba4 fails
ptrbortolotti Jan 8, 2026
a36abf2
do not extrapolate and fix double conversion to radians when using c2…
ptrbortolotti Jan 8, 2026
0ea4970
Merge branch 'windIO2p0p1' of https://github.com/WISDEM/SONATA into w…
ptrbortolotti Jan 8, 2026
7f30c40
remove example 5 as it's currently empty
ptrbortolotti Jan 8, 2026
73b5242
fix twist again
ptrbortolotti Jan 8, 2026
a4c4d4c
Removing viscoelastic material props code that was moved out of windio.
JustinPorter88 Jan 8, 2026
4f36f54
Merge branch 'windIO2p0p1' of github.com:WISDEM/SONATA into windIO2p0p1
JustinPorter88 Jan 8, 2026
1dc9b89
update readme
ptrbortolotti Jan 8, 2026
abe4200
update reg values for iea15 and iea22
ptrbortolotti Jan 8, 2026
a1d308c
Merge branch 'windIO2p0p1' of https://github.com/WISDEM/SONATA into w…
ptrbortolotti Jan 8, 2026
690d40f
Changing the custom mesh material number in the example since a mater…
JustinPorter88 Jan 8, 2026
09ab351
fix precommit
ptrbortolotti Jan 8, 2026
56a2cc9
Merge pull request #41 from WISDEM/ex8
ptrbortolotti Jan 8, 2026
757c4d9
add examples 7 and 8 to CI
ptrbortolotti Jan 8, 2026
38a1d05
Merge branch 'windIO2p0p1' of https://github.com/WISDEM/SONATA into w…
ptrbortolotti Jan 8, 2026
4aad377
white spaces
ptrbortolotti Jan 8, 2026
2949e4b
Adding README notes about WindIO support in SONATA.
JustinPorter88 Jan 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions .github/workflows/python-package-conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,26 @@ jobs:
export MPLBACKEND=Agg
python 2_sonata_IEA22.py

- name: Run example 5
run: |
cd examples/5_IEA_5MW
export MPLBACKEND=Agg
python 5_sonata_IEA5.py
# - name: Run example 5
# run: |
# cd examples/5_NREL_5MW
# export MPLBACKEND=Agg
# python 5_sonata_NREL_5MW.py

- name: Run example 6
run: |
cd examples/6_beam_stress
export MPLBACKEND=Agg
python 6_sonata_beam_stress.py

- name: Run example 7
run: |
cd examples/7_viscoelastic
export MPLBACKEND=Agg
python 7_sonata_viscoelastic.py

- name: Run example 8
run: |
cd examples/8_fiber_orient
export MPLBACKEND=Agg
python 8_sonata_orientation.py
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
## Background
SONATA is a toolbox for Multidiciplinary Rotor Blade Design Environment for Structural Optimization and Aeroelastic Analysis. SONATA has originally been developed at the Helicopter Technology Institute of the Technical University of Munich (TUM), Germany. The original repository is available at https://gitlab.lrz.de/HTMWTUM/SONATA. The original work was supported by the German Federal Ministry for Economic Affairs and Energy through the German Aviation Research Program LuFo V-2 and the Austrian Research Promotion Agency through the Austrian Research Program TAKE OFF in the project VARI-SPEED.

SONATA has been adapted to wind energy applications thanks to work performed at the National Renewable Energy Laboratory ([NREL](https://www.nrel.gov)) in Colorado, USA
and funded by the US Department of Energy, Wind Energy Technology Office under the Big Adaptive Rotor program.
NREL has since been renamed National Laboratory of the Rockies (NLR).
This repository is managed by Pietro Bortolotti, researcher in the systems engineering group at NLR.
SONATA has been adapted to wind energy applications thanks to work performed at the National Renewable Energy Laboratory ([NREL](https://www.nrel.gov)), recently renamed National Laboratory of the Rockies (NLR), located in Golden, Colorado, USA. Work at NREL/NLR is funded by the US Department of Energy, Wind Energy Technology Office under the Big Adaptive Rotor program, and the STability and Aeroelastic Behavior of Large wind turbinEs (STABLE) project.

This repository is managed by Pietro Bortolotti and Justin Porter, researchers in the wind energy systems group at NLR.


## Part of the WETO Stack
Expand All @@ -22,9 +20,7 @@ SONATA is primarily developed with the support of the U.S. Department of Energy


## Installation
SONATA can be run on mac and linux machines. No Windows installation is supported at the moment. We make use of Anaconda, which is a commonly used package manager for python. Download and install the latest anaconda version [here](https://docs.anaconda.com/anaconda/install/)

At NREL (and possibly at other institutes), first disconnect from vpn client during installation in order to avoid remote server error when trying to retrieve URLs for installation.
SONATA can be run on mac and linux machines. No Windows installation is supported at the moment. We make use of Anaconda, which is a commonly used package manager for Python. Download and install the latest anaconda version [here](https://docs.anaconda.com/anaconda/install/)

First setup an anaconda environment, here named sonata-env, activate it, and add the pythonocc library (v7.4.1).
You should do this in the folder that you want to clone SONATA to.
Expand All @@ -49,7 +45,7 @@ conda activate sonata-env
cd ..
```

Next, download the solvers VABS (commercial, use wine to run it on mac/linux systems) or in the same conda environment compile ANBA4 (open-source)
Next, in the same conda environment compile ANBA4 (open-source)

```
git clone git@github.com:ANBA4/anba4.git # (or git clone https://github.com/ANBA4/anba4.git)
Expand Down Expand Up @@ -85,17 +81,24 @@ cd examples/0_beams
python 0_SONATA_init_box_beam_HT_antisym_layup_15_6_SI_SmithChopra91.py
```

Next try running the section at 30% along the blade span of the [IEA15MW refence wind turbine](https://github.com/IEAWindTask37/IEA-15-240-RWT)
Next try modeling the blade of the [IEA-15MW reference wind turbine](https://github.com/IEAWindSystems/IEA-15-240-RWT).
```
cd ../examples/1_IEA15MW
python 1_sonata_IEA15.py
```

Note that two examples use two different structures of the input files. Example 0 uses the original yaml structure from TUM, whereas the second file uses the wind turbine ontology coded in [windIO](https://github.com/IEAWindSystems/windIO). windIO is developed within IEA Wind Task 55 REFWIND and its documentation lives [here](https://ieawindsystems.github.io/windIO/main/index.html).


### Structural Damping Example

The IEA 22MW example includes instructions on how to estimate structural damping via the modal strain energy approach.
Detailed instructions can be found [here](examples/2_IEA22MW/README.md). Further details are provided in publications including Porter et al. (2025).

### Notes

1. You must define a TE anchor for SONATA. SONATA does not autodefine the TE anchor as implied by WindIO.
2. Layer definition in SONATA only supports `start_nd_arc` and `end_nd_arc`. Other tools can generate these quantities from the WindIO definition.


## Publications:
Expand Down
6 changes: 3 additions & 3 deletions SONATA/cbm/classCBM.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ def cbm_run_viscoelastic(self, test_elastic=True, test_tau0=True):

if not (self.materials[MatID].viscoelastic == {}):
time_scale_list += self.materials[MatID]\
.viscoelastic['time_scales_v'].tolist()
.viscoelastic['time_scales_v']

time_scale_list = np.sort(np.unique(time_scale_list)).tolist()

Expand All @@ -743,7 +743,7 @@ def cbm_run_viscoelastic(self, test_elastic=True, test_tau0=True):
mat = self.materials[MatID]

if hasattr(mat, 'viscoelastic') and not (mat.viscoelastic=={}):
found_time_scale = tau in mat.viscoelastic['time_scales_v'].tolist()
found_time_scale = tau in mat.viscoelastic['time_scales_v']
else:
found_time_scale = False

Expand All @@ -758,7 +758,7 @@ def cbm_run_viscoelastic(self, test_elastic=True, test_tau0=True):
else:
# find index of time scale
time_scale_ind = np.argmax(tau
== mat.viscoelastic['time_scales_v'])
== np.array(mat.viscoelastic['time_scales_v']))

if found_time_scale and mat.orth == 0:

Expand Down
20 changes: 1 addition & 19 deletions SONATA/cbm/classCBMConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@

# Third party modules
import numpy as np
import yaml

# First party modules
from SONATA.classMaterial import find_material, read_materials
from SONATA.classMaterial import find_material
from SONATA.anbax.classANBAXConfig import ANBAXConfig

if __name__ == "__main__":
Expand Down Expand Up @@ -144,20 +143,3 @@ def read_yaml_cbm(self, yml, materials):
if yml.get("trim_mass"):
self.bw = yml.get("trim_mass") #
self.setup["BalanceWeight"] = True


if __name__ == "__main__":

# classic configuration file:
os.chdir("/media/gu32kij/work/TPflumm/SONATA")
# fname = 'jobs/VariSpeed/advanced/sec_config.yml'
fname = "examples/sec_config.yml"
cfg = CBMConfig(fname)

with open("jobs/VariSpeed/UH-60A_adv.yml", "r") as myfile:
inputs = myfile.read()

yml = yaml.load(inputs)
materials = read_materials(yml.get("materials"))
yml = yml.get("components").get("blade").get("2d_fem").get("sections")[0]
wt_cfg = CBMConfig(yml, materials)
34 changes: 4 additions & 30 deletions SONATA/classAirfoil.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import os

# Third party modules
import matplotlib.pyplot as plt
import numpy as np
# PythonOCC Libraries
from OCC.Core.gp import gp_Pnt
Expand Down Expand Up @@ -129,7 +128,7 @@ def gen_OCCtopo(self, angular_deflection = 30 ):
self.wire = build_wire_from_BSplineLst(self.BSplineLst, twoD=False)
return self.wire

def trsf_to_blfr(self, loc, pa_loc, chord, twist):
def trsf_to_blfr(self, loc, soy, chord, twist):
"""
transforms the nondim. airfoil to the blade reference frame location
and pitch-axis information, scales it with chord information and rotates
Expand All @@ -139,8 +138,8 @@ def trsf_to_blfr(self, loc, pa_loc, chord, twist):
----------
loc : array
[x,y,z] position in blade reference coordinates
pa_loc : float
nondim. pitch axis location
soy : float
dim. pitch axis location
chord : float
chordlength
twist : float
Expand All @@ -151,7 +150,7 @@ def trsf_to_blfr(self, loc, pa_loc, chord, twist):
wire : TopoDS_Wire

"""
Trsf = trsf_af_to_blfr(loc, pa_loc, chord, twist)
Trsf = trsf_af_to_blfr(loc, soy, chord, twist)
if self.wire is None or self.BSplineLst is None:
self.gen_OCCtopo()

Expand Down Expand Up @@ -237,28 +236,3 @@ def transformed(self, airfoil2, k=0.5):
trf_af.coordinates = self.interpolate_shapes(self.coordinates, airfoil2.coordinates, k)

return trf_af



if __name__ == "__main__":
plt.close("all")
import yaml

with open("jobs/VariSpeed/UH-60A_adv.yml", "r") as f:
data = yaml.load(f.read())

airfoils = [Airfoil(af) for af in data["airfoils"]]

for af in airfoils:
af.gen_OCCtopo()

af1 = airfoils[0]
af2 = airfoils[1]
res = af1.transformed(af2, 1.0)
res.gen_OCCtopo()

with open("data1.yml", "w") as outfile:
yaml.dump(af1.write_yaml_airfoil(), outfile)

with open("data2.yml", "w") as outfile:
yaml.dump(af2.write_yaml_airfoil(), outfile)
Loading
Loading