Automate running a simulation using Python
This example shows how to run and post-process a Bladed Next Gen simulation in an automated way with the support of Python.
The tutorial uses the IEA_15MW_240-RWT v1.1 model JSON input file 15MW_NREL_DNV_v1_1_pcoeffs.json
and the run_pcoeff.py
Python script contained in the Bladed Next Gen samples.
Prerequisites
- Latest version of Bladed Next Gen and Samples installed, including the Bladed Python packages (both dnv-bladed-models and dnv-bladed-results).
- Licence for Bladed Next Gen (request a licence).
- Python 3.9 to 3.12 installed.
What you will learn
- How to load a Bladed model using the Python inputs API.
- How to modify a model using the Python inputs API.
- How to run a simulation using Python.
- How to load results data using the Python results API.
- How to post-process the results data.
How to use this tutorial
To use this tutorial it is advised to download the samples. The package contains all required content to complete this tutorial.
Make sure to check the Get started article on how to setup your machine for the tutorials.
Switch to the samples folder in VS Code and open run_pcoeff.py
.
Read through the comments in the Python file or on the code snippet bellow, to understand how to automate a Bladed Next Gen simulation using Python.
Once you have gone through the file, try running it and see the results.
import dnv_bladed_models as models
import os
import subprocess
from pathlib import Path
from dnv_bladed_results import ResultsApi
from dnv_bladed_results.UsageExamples import ResultsApi_PostProcessing
import matplotlib.pyplot as plt
# ------------
# !! ADJUST IF NECESSARY !!
# Bladed Next Gen install path
# If you do not have Bladed NG installed in your
# system path you can manually add bladed.exe path
# to the below line
bladed_NG_path = ''
# ------------
output_name = 'run_15MW_pcoeff'
bladed_exe_path = os.path.join(bladed_NG_path,'bladed.exe')
# Specify required folders, relative to this script
examples_models_path = os.path.dirname(__file__)
results_path = os.path.join(examples_models_path, "results")
generated_models_path = os.path.join(examples_models_path, "generated-models")
def ensure_folder_exists(path: str):
if not os.path.exists(path):
os.makedirs(path)
ensure_folder_exists(results_path)
ensure_folder_exists(generated_models_path)
# Load the model
model_15MW_path = os.path.join(examples_models_path,'15MW_NREL_DNV_v1_1_pcoeffs.json')
sim1 = models.BladedAnalysis.from_file(model_15MW_path)
# Set parameters for simulation
PitchAngle_to_plot = -0.18
sim1.SteadyCalculation.PitchRange.Minimum = - 0.18
sim1.SteadyCalculation.PitchRange.Maximum = - 0.18
sim1.SteadyCalculation.PitchRange.Interval = 0.05
sim1.SteadyCalculation.TipSpeedRatioRange.Minimum = 2.
sim1.SteadyCalculation.TipSpeedRatioRange.Maximum = 18.
sim1.SteadyCalculation.TipSpeedRatioRange.Interval = 0.1
# Save to new file
model_15MW_modified_filename = Path(model_15MW_path).stem + '_mod'+ '.json'
model_15MW_modified_path = os.path.join(generated_models_path, model_15MW_modified_filename)
sim1.to_file(model_15MW_modified_path)
# Run the simulation
cmd = bladed_exe_path
try:
subprocess.check_output([cmd, model_15MW_modified_path, '-o', results_path, '-n', output_name])
print('Bladed calculations were executed successfully!')
except subprocess.CalledProcessError as error_message:
print(str(error_message.output).split('ERROR:')[-1])
# Set the file path for writing the processed data
file_name = os.path.join(results_path, "example_timeseries")
# Get the target run outputs
run = ResultsApi.get_run(results_path, output_name)
# Get a time series variable - Power Coefficient.
variable_name = "Power Coefficient"
# Check the number of independent variables
if run.contains_variable_2d(variable_name):
# 2D
CP_variable = run.get_variable_2d(variable_name)
# Create a data structure to handle the output data using the structure in dnv_bladed_Results.UsageExamples
CP_struct = ResultsApi_PostProcessing.DataStructureClass(CP_variable)
# Transform data into a Pandas DataFrame
CP_data_frame = ResultsApi_PostProcessing.to_data_frame(CP_struct)
plt.figure()
ax= CP_data_frame.loc[PitchAngle_to_plot].plot()
ax.set_ylabel(CP_struct.dependent_variable.name + " [" + CP_struct.dependent_variable.siunit + "]")
ax.set_title(CP_data_frame.index.name + "=" + str(PitchAngle_to_plot))
plt.show()
elif run.contains_variable_1d(variable_name):
# 1D
CP_variable = run.get_variable_1d(variable_name)
# Create a data structure to handle the output data
CP_struct = ResultsApi_PostProcessing.DataStructureClass(CP_variable)
plt.figure()
plt.plot(CP_struct.primary_independent_variable.values,CP_struct.dependent_variable.values)
plt.xlabel(CP_struct.primary_independent_variable.name + " [" + CP_struct.primary_independent_variable.siunit + "]")
plt.ylabel(CP_struct.dependent_variable.name + " [" + CP_struct.dependent_variable.siunit + "]")
plt.show()
else:
raise Exception("Variable " + variable_name+" not found")