MHKiT WEC-Sim Example
This notebook demonstrates using the MHKiT wave module and WEC-Sim together to perform a resource characterization study in MHKiT, simulate representative cases with WEC-Sim, and visualize the results in MHKiT to estimate MAEP (Mean Annual Energy Production).
Characterize the available resource at a location
See the PacWave example notebook
Write a WEC-Sim batch file for the given clusters
Simulate the device in WEC-Sim.
Ensure that the spectra used in WEC-Sim is identical to the one used in MHKiT.
Load WEC-Sim batch results
Assess results and visualize quantities of interest
This example uses WEC-Sim to simulate the Oscillating Surge Wave Energy Converter (OSWEC), a flap-type device.
Start by importing MHKiT and the necessary python packages (e.g.scipy.io, matplotlib.pyplot, pandas, numpy).
[1]:
from mhkit import wave
import scipy.io as sio
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
1. Characterize the available resource at a location
This example will use an abbreviated version of PacWave_resource_characterization_example.ipynb. For full details on downloading, calculating, and visualizing the k-means clusters representation of the site’s wave resouce, see that example.
We select the N=32 cluster as it’s total energy flux is closet to the total energy flux of the site considering all wave conditions. We will load the PacWave example output, which can be easily saved after running the example with the command results[32].to_csv("pacwave_cluster_32.csv"). We will start this example by reading in that csv output and formatting it for WEC-Sim.
[2]:
results = pd.read_csv("data/wave/pacwave_cluster_32.csv", index_col=0)
results
[2]:
| Te | Hm0 | weights | Tp | J | |
|---|---|---|---|---|---|
| 0 | 7.974491 | 1.253970 | 0.058861 | 9.294279 | 6031.115427 |
| 1 | 10.794533 | 2.641403 | 0.035216 | 12.581041 | 37004.325098 |
| 2 | 6.901979 | 1.953122 | 0.052001 | 8.044264 | 12516.214519 |
| 3 | 12.667628 | 7.310116 | 0.005070 | 14.764135 | 367451.945581 |
| 4 | 12.893701 | 2.262294 | 0.016046 | 15.027624 | 36455.136139 |
| 5 | 10.557621 | 4.754297 | 0.017311 | 12.304920 | 116784.361789 |
| 6 | 8.766664 | 2.739380 | 0.043646 | 10.217557 | 31825.667989 |
| 7 | 6.537403 | 1.305578 | 0.050746 | 7.619350 | 5272.441394 |
| 8 | 9.666291 | 1.340694 | 0.037070 | 11.266073 | 8443.649821 |
| 9 | 12.787307 | 3.920397 | 0.016464 | 14.903621 | 107680.986511 |
| 10 | 11.605879 | 1.821016 | 0.022323 | 13.526666 | 19446.169168 |
| 11 | 7.584082 | 1.878735 | 0.054624 | 8.839256 | 12827.143861 |
| 12 | 10.175411 | 6.133932 | 0.008836 | 11.859453 | 188189.689187 |
| 13 | 9.319357 | 4.587432 | 0.018817 | 10.861722 | 95155.068368 |
| 14 | 7.228996 | 1.256691 | 0.057692 | 8.425403 | 5449.034309 |
| 15 | 5.646967 | 1.339107 | 0.032118 | 6.581547 | 4750.825175 |
| 16 | 7.615980 | 2.634620 | 0.036497 | 8.876433 | 25339.645267 |
| 17 | 9.460406 | 3.381147 | 0.033824 | 11.026114 | 52508.670941 |
| 18 | 16.000441 | 3.044223 | 0.004295 | 18.648532 | 87446.895732 |
| 19 | 10.550343 | 1.563634 | 0.030265 | 12.296437 | 12622.321616 |
| 20 | 11.817436 | 2.982923 | 0.021717 | 13.773236 | 53748.089829 |
| 21 | 12.101122 | 5.305727 | 0.014540 | 14.103872 | 177305.220432 |
| 22 | 10.400035 | 3.588297 | 0.032312 | 12.121253 | 65405.272028 |
| 23 | 9.132540 | 2.011568 | 0.048130 | 10.643986 | 17913.129344 |
| 24 | 9.880296 | 2.462908 | 0.050634 | 11.515496 | 29157.316025 |
| 25 | 8.321803 | 2.003080 | 0.054171 | 9.699071 | 16104.920042 |
| 26 | 6.131352 | 1.794449 | 0.035429 | 7.146098 | 9295.960216 |
| 27 | 11.430727 | 3.979891 | 0.025331 | 13.322525 | 90734.821382 |
| 28 | 14.263809 | 2.781733 | 0.009359 | 16.624486 | 66183.179571 |
| 29 | 13.744161 | 5.465225 | 0.007518 | 16.018835 | 240475.837506 |
| 30 | 8.735251 | 1.270630 | 0.047066 | 10.180945 | 6821.344537 |
| 31 | 8.301748 | 3.676767 | 0.022070 | 9.675697 | 54122.886646 |
2. Write a WEC-Sim batch file for the given clusters
WEC-Sim MCR (multiple condition run) files should contain a structure mcr that contains two variables: header and cases. Each column of header and cases denotes a variable and it’s value respectively. Each row is another simulation. WEC-Sim defines waves using the significant wave height and peak period. We will isolate these values from the results of the cluster analysis and
create a dictionary that is written to the .mat file.
[3]:
ws_mcr_cases = results[["Hm0","Tp"]]
ws_mcr_header = np.array(["waves.height","waves.period"], dtype='object')
ws_mcr_out = {'mcr': {'header': ws_mcr_header, 'cases': ws_mcr_cases}}
sio.savemat('mcr_mhkit.mat', ws_mcr_out)
3. Simulate the device in WEC-Sim
Now that the MCR file is created, we need to go simulate WEC performance in these wave conditions using WEC-Sim. To recreate the data used in the next step, use the created MCR file with WEC-Sim’s OSWEC example. For an accurate comparison to the power calculated in the resource characterization, we should ensure that the WEC-Sim cases use irregular JONSWAP wave spectra as in the PacWave example.
For convenience in this demonstration, we enforce OSWEC model stability in the extreme wave conditions by arbitrarily applying a large PTO stiffness and damping:
pto(1).stiffness = 1e5;
pto(1).damping = 5e7;
To reduce the amount of extranenous data saved for this example, we limit the WEC-Sim output to the PTO’s power output in the userDefinedFunctions.m script:
if exist('imcr','var')
if imcr == 1
nmcr = size(mcr.cases,1);
power = nan(1, nmcr);
end
iRampEnd = simu.rampTime./simu.dtOut + 1;
power(imcr) = -mean(output.ptos(1).powerInternalMechanics(iRampEnd:end,5));
if imcr == nmcr
% Save output
save('mcr_mhkit_power.mat', 'power');
end
end
4. Load WEC-Sim batch results
Note that in this example we do not save the entire WEC-Sim output structure for each case. See the wecsim_example.ipynb for information on loading that WEC-Sim data. Here the output is one array of average power output that we will load and compare to the resource characterization.
Note that the power output [W] is significantly larger than the energy flux [W/m] due to the width of the OSWEC.
[4]:
# Relative location and filename of simulated WEC-Sim data (run with mooring)
filename = "./data/wave/mcr_mhkit_power.mat"
# Load data using the `wecsim.read_output` function which returns a dictionary of Datasets.
wecsim_data = sio.loadmat(filename)
results['P'] = wecsim_data['power'][0]
results
[4]:
| Te | Hm0 | weights | Tp | J | P | |
|---|---|---|---|---|---|---|
| 0 | 7.974491 | 1.253970 | 0.058861 | 9.294279 | 6031.115427 | 6.861312e+04 |
| 1 | 10.794533 | 2.641403 | 0.035216 | 12.581041 | 37004.325098 | 3.873519e+05 |
| 2 | 6.901979 | 1.953122 | 0.052001 | 8.044264 | 12516.214519 | 1.923400e+05 |
| 3 | 12.667628 | 7.310116 | 0.005070 | 14.764135 | 367451.945581 | 1.951187e+06 |
| 4 | 12.893701 | 2.262294 | 0.016046 | 15.027624 | 36455.136139 | 3.115873e+05 |
| 5 | 10.557621 | 4.754297 | 0.017311 | 12.304920 | 116784.361789 | 8.410281e+05 |
| 6 | 8.766664 | 2.739380 | 0.043646 | 10.217557 | 31825.667989 | 3.398579e+05 |
| 7 | 6.537403 | 1.305578 | 0.050746 | 7.619350 | 5272.441394 | 8.332614e+04 |
| 8 | 9.666291 | 1.340694 | 0.037070 | 11.266073 | 8443.649821 | 6.951609e+04 |
| 9 | 12.787307 | 3.920397 | 0.016464 | 14.903621 | 107680.986511 | 5.068824e+05 |
| 10 | 11.605879 | 1.821016 | 0.022323 | 13.526666 | 19446.169168 | 1.601980e+05 |
| 11 | 7.584082 | 1.878735 | 0.054624 | 8.839256 | 12827.143861 | 2.112478e+05 |
| 12 | 10.175411 | 6.133932 | 0.008836 | 11.859453 | 188189.689187 | 2.402013e+06 |
| 13 | 9.319357 | 4.587432 | 0.018817 | 10.861722 | 95155.068368 | 1.067714e+06 |
| 14 | 7.228996 | 1.256691 | 0.057692 | 8.425403 | 5449.034309 | 6.414256e+04 |
| 15 | 5.646967 | 1.339107 | 0.032118 | 6.581547 | 4750.825175 | 7.328911e+04 |
| 16 | 7.615980 | 2.634620 | 0.036497 | 8.876433 | 25339.645267 | 3.671972e+05 |
| 17 | 9.460406 | 3.381147 | 0.033824 | 11.026114 | 52508.670941 | 4.020208e+05 |
| 18 | 16.000441 | 3.044223 | 0.004295 | 18.648532 | 87446.895732 | 2.414505e+05 |
| 19 | 10.550343 | 1.563634 | 0.030265 | 12.296437 | 12622.321616 | 1.335059e+05 |
| 20 | 11.817436 | 2.982923 | 0.021717 | 13.773236 | 53748.089829 | 3.552203e+05 |
| 21 | 12.101122 | 5.305727 | 0.014540 | 14.103872 | 177305.220432 | 1.343228e+06 |
| 22 | 10.400035 | 3.588297 | 0.032312 | 12.121253 | 65405.272028 | 7.368317e+05 |
| 23 | 9.132540 | 2.011568 | 0.048130 | 10.643986 | 17913.129344 | 1.998769e+05 |
| 24 | 9.880296 | 2.462908 | 0.050634 | 11.515496 | 29157.316025 | 2.715734e+05 |
| 25 | 8.321803 | 2.003080 | 0.054171 | 9.699071 | 16104.920042 | 2.319710e+05 |
| 26 | 6.131352 | 1.794449 | 0.035429 | 7.146098 | 9295.960216 | 1.478045e+05 |
| 27 | 11.430727 | 3.979891 | 0.025331 | 13.322525 | 90734.821382 | 9.391133e+05 |
| 28 | 14.263809 | 2.781733 | 0.009359 | 16.624486 | 66183.179571 | 2.000335e+05 |
| 29 | 13.744161 | 5.465225 | 0.007518 | 16.018835 | 240475.837506 | 8.686179e+05 |
| 30 | 8.735251 | 1.270630 | 0.047066 | 10.180945 | 6821.344537 | 8.550423e+04 |
| 31 | 8.301748 | 3.676767 | 0.022070 | 9.675697 | 54122.886646 | 7.578856e+05 |
5. Assess results and visualize quantities of interest
Now that we have loaded the OSWEC’s modeled power, we can assess it’s performance relative to the incoming wave and calculate the mean annual energy production (MAEP) using MHKiT.
[5]:
results['CW'] = wave.performance.capture_width(results['P'], results['J'])
oswec_width = 18
results['CWR'] = results['CW'] / oswec_width
results
[5]:
| Te | Hm0 | weights | Tp | J | P | CW | CWR | |
|---|---|---|---|---|---|---|---|---|
| 0 | 7.974491 | 1.253970 | 0.058861 | 9.294279 | 6031.115427 | 6.861312e+04 | 11.376523 | 0.632029 |
| 1 | 10.794533 | 2.641403 | 0.035216 | 12.581041 | 37004.325098 | 3.873519e+05 | 10.467747 | 0.581542 |
| 2 | 6.901979 | 1.953122 | 0.052001 | 8.044264 | 12516.214519 | 1.923400e+05 | 15.367264 | 0.853737 |
| 3 | 12.667628 | 7.310116 | 0.005070 | 14.764135 | 367451.945581 | 1.951187e+06 | 5.310048 | 0.295003 |
| 4 | 12.893701 | 2.262294 | 0.016046 | 15.027624 | 36455.136139 | 3.115873e+05 | 8.547144 | 0.474841 |
| 5 | 10.557621 | 4.754297 | 0.017311 | 12.304920 | 116784.361789 | 8.410281e+05 | 7.201547 | 0.400086 |
| 6 | 8.766664 | 2.739380 | 0.043646 | 10.217557 | 31825.667989 | 3.398579e+05 | 10.678736 | 0.593263 |
| 7 | 6.537403 | 1.305578 | 0.050746 | 7.619350 | 5272.441394 | 8.332614e+04 | 15.804090 | 0.878005 |
| 8 | 9.666291 | 1.340694 | 0.037070 | 11.266073 | 8443.649821 | 6.951609e+04 | 8.232943 | 0.457386 |
| 9 | 12.787307 | 3.920397 | 0.016464 | 14.903621 | 107680.986511 | 5.068824e+05 | 4.707260 | 0.261514 |
| 10 | 11.605879 | 1.821016 | 0.022323 | 13.526666 | 19446.169168 | 1.601980e+05 | 8.238022 | 0.457668 |
| 11 | 7.584082 | 1.878735 | 0.054624 | 8.839256 | 12827.143861 | 2.112478e+05 | 16.468814 | 0.914934 |
| 12 | 10.175411 | 6.133932 | 0.008836 | 11.859453 | 188189.689187 | 2.402013e+06 | 12.763787 | 0.709099 |
| 13 | 9.319357 | 4.587432 | 0.018817 | 10.861722 | 95155.068368 | 1.067714e+06 | 11.220783 | 0.623377 |
| 14 | 7.228996 | 1.256691 | 0.057692 | 8.425403 | 5449.034309 | 6.414256e+04 | 11.771363 | 0.653965 |
| 15 | 5.646967 | 1.339107 | 0.032118 | 6.581547 | 4750.825175 | 7.328911e+04 | 15.426605 | 0.857034 |
| 16 | 7.615980 | 2.634620 | 0.036497 | 8.876433 | 25339.645267 | 3.671972e+05 | 14.491015 | 0.805056 |
| 17 | 9.460406 | 3.381147 | 0.033824 | 11.026114 | 52508.670941 | 4.020208e+05 | 7.656274 | 0.425349 |
| 18 | 16.000441 | 3.044223 | 0.004295 | 18.648532 | 87446.895732 | 2.414505e+05 | 2.761110 | 0.153395 |
| 19 | 10.550343 | 1.563634 | 0.030265 | 12.296437 | 12622.321616 | 1.335059e+05 | 10.576970 | 0.587609 |
| 20 | 11.817436 | 2.982923 | 0.021717 | 13.773236 | 53748.089829 | 3.552203e+05 | 6.608984 | 0.367166 |
| 21 | 12.101122 | 5.305727 | 0.014540 | 14.103872 | 177305.220432 | 1.343228e+06 | 7.575793 | 0.420877 |
| 22 | 10.400035 | 3.588297 | 0.032312 | 12.121253 | 65405.272028 | 7.368317e+05 | 11.265631 | 0.625868 |
| 23 | 9.132540 | 2.011568 | 0.048130 | 10.643986 | 17913.129344 | 1.998769e+05 | 11.158124 | 0.619896 |
| 24 | 9.880296 | 2.462908 | 0.050634 | 11.515496 | 29157.316025 | 2.715734e+05 | 9.314074 | 0.517449 |
| 25 | 8.321803 | 2.003080 | 0.054171 | 9.699071 | 16104.920042 | 2.319710e+05 | 14.403735 | 0.800207 |
| 26 | 6.131352 | 1.794449 | 0.035429 | 7.146098 | 9295.960216 | 1.478045e+05 | 15.899861 | 0.883326 |
| 27 | 11.430727 | 3.979891 | 0.025331 | 13.322525 | 90734.821382 | 9.391133e+05 | 10.350087 | 0.575005 |
| 28 | 14.263809 | 2.781733 | 0.009359 | 16.624486 | 66183.179571 | 2.000335e+05 | 3.022422 | 0.167912 |
| 29 | 13.744161 | 5.465225 | 0.007518 | 16.018835 | 240475.837506 | 8.686179e+05 | 3.612080 | 0.200671 |
| 30 | 8.735251 | 1.270630 | 0.047066 | 10.180945 | 6821.344537 | 8.550423e+04 | 12.534806 | 0.696378 |
| 31 | 8.301748 | 3.676767 | 0.022070 | 9.675697 | 54122.886646 | 7.578856e+05 | 14.003052 | 0.777947 |
[6]:
MAEP = wave.performance.mean_annual_energy_production_matrix(results['CW'], results['J'], results['weights']) / 1000 # kWh
MAEP = np.round(MAEP, 0).item()
MAEP
[6]:
2865149.0