MCP Calculation Service

The CalcMCPService gives access to the MCP module in windPRO. It contains methods to get and set (CalcMCPService.GetMCPCalc and CalcMCPService.SetMCPCalc) the calculations similar to other calculation services. An MCP calculation needs a site data object.

The MCP calculation is different as there are sessions in the calculation where MCP calculation are performed. To add a session you can use the CalcMCPService.AddSession function. The function CalcMCPService.GetTemplateModels generates all available models with their default setting to make it easier to add them. Sseveral of these models can be assigned to the MCP calculation object. To Assign them in windPRO (and to generate the correct model handle) use CalcMCPService.SetMCPCalc.

The MCP calculation object has different handles and IDs that need to be set. For convenience they are listed below with a description.

Data types available from online

Property

Description

Handle

Handle of the MCP calculation

Sessions.TApiMcpSession[].Handle

Handle of the specific session

Sessions.TApiMcpSession[].SGSiteDataHandle

Handle for the site data object

Sessions.TApiMcpSession[].MeasureMeteoHandle

Handle of the meteo object with the measurement data

Sessions.TApiMcpSession[].MeasureMeteoUID

ID to identify the correct height in the meteo object

Sessions.TApiMcpSession[].ReferenceMeteoHandle

Handle of the meteo object with the reference data

Sessions.TApiMcpSession[].ReferenceMeteoUID

ID to identify the correct height in the meteo object

Sessions.TApiMcpSession[].SelectedModelHandle

Model to be used for performing MCP calculation

Sessions.TApiMcpSession[].Models.TApiMCPModel[].Handle

Handle for the specific models

It is important to remember that assigning values to the object in python (or your preferred programming language) does not set them in windPRO. This needs to be done with CalcMCPService.SetMCPCalc to take effect in further calculations.

The different models can be calculated for training and testing with CalcMCPService.TrainAndTest. This will calculate all models of the selected session.

There are several functions to get access to different statistics that are available in the interactive session in the meteo object. CalcMCPService.PredictToWindStat Their use us shown in the example below. For obtaining these statistics the calculation needs to be open from windPRO scripting unlike for calculating other calculations.

The final MCP calculations are performed by adding a time series with CalcMCPService.PredictToMeteo or by making a wind statistics with CalcMCPService.PredictToWindStat. For the latter, a site data object needs to be assigned to the MCP session.

Properties of the calculation object can be found here TApiCalcMCP.

The example below shows how to set up an MCP calculation from scratch in a project with existing meteo objects.

"""
Copyright 2023 EMD International
License for this script: MIT https://opensource.org/license/mit/
License for windPRO commercial software: https://www.emd-international.com/contact-us/general-terms-conditions-sale/
"""

import os
import numpy as np
from windproapi import WindProApi
from windproapi.utils import get_windpro_sample_path
from windproapi import nan_to_skipvalue


def find_closest_height_handle(meteo_object, measurement_height):
    # Determining which height is closest to the selection height
    meteo_height_diffs = []
    meteo_heights = []
    meteo_height_handles = []
    for temp in meteo_object.Heights.TApiMeteoHeight:
        meteo_height_diffs.append(temp.Height - measurement_height)
        meteo_heights.append(temp.Height)
        meteo_height_handles.append(temp.Handle)

    index_min = np.argmin(abs(np.array(meteo_height_diffs)))
    meteo_height_handle = meteo_height_handles[index_min]
    return meteo_height_handle


# Opening windPRO
_windproapi = WindProApi()

# Project file
working_dir = os.path.join(get_windpro_sample_path('4.0'), 'New Salem\\4.0')
project_path = os.path.join(working_dir, 'New Salem.w40p')
_windproapi.start_windpro_random_port()

# Services
project_service = _windproapi.get_service('ProjectService')
objects_service = _windproapi.get_service('ObjectsService')
calculation_service = _windproapi.get_service('CalculationService')
calc_park_service = _windproapi.get_service('CalcParkService')
obj_wtg_service = _windproapi.get_service('ObjWtgService')
calc_MCP_service = _windproapi.get_service('CalcMCPService')
obj_meteo_service = _windproapi.get_service('ObjMeteoService')
calc_statgen_service = _windproapi.get_service('CalcStatgenService')
obj_site_data_service = _windproapi.get_service('ObjSiteDataService')
factory = _windproapi.get_factory('WindproService')

# Open project file
project_service.LoadFromFile(filename=project_path)

# Making a new MCP calculation
mcp_handle = calculation_service.CreateEmpty(calcType='CalcMCP')
calculation_service.OpenCalcForEdit(handle=mcp_handle)
mcp_calc = calc_MCP_service.GetMCPCalc()

# There is not much in the calculation yet without making a new MCP session
print(mcp_calc)
calc_MCP_service.AddSession()

# With the new session much more information in .Session
mcp_calc = calc_MCP_service.GetMCPCalc()
mcp_calc.Name = 'Generate by scripting'
print(mcp_calc)
mcp_session_handle = mcp_calc.Sessions.TApiMcpSession[0].Handle

# Adding meteorological data
meteo_objs = objects_service.GetObjects(apiObjType='MeteoObjectData')
obj_measurement = [d for d in meteo_objs if d.UserDescription == 'New Salem South'][0]
obj_reference = [d for d in meteo_objs if 'EmdWrf' in d.UserDescription][0]

meteo_measurement = obj_meteo_service.GetMeteoObject(handle=obj_measurement.Handle)
meteo_reference = obj_meteo_service.GetMeteoObject(handle=obj_reference.Handle)

# Getting the handles for the correct heights inside the meteo object
internal_measurement_handle = find_closest_height_handle(meteo_measurement, 60)
internal_reference_handle = find_closest_height_handle(meteo_reference, 60)

ses = mcp_calc.Sessions.TApiMcpSession[0]
ses.Enabled = True
ses.MeasureMeteoHandle = meteo_measurement.Handle
ses.MeasureMeteoUID = internal_measurement_handle
ses.ReferenceMeteoHandle = meteo_reference.Handle
ses.ReferenceMeteoUID = internal_reference_handle

# Site data object for making wind statistics
site_objs = objects_service.GetObjects(apiObjType='SiteData')
sitedata = [d for d in site_objs if d.UserDescription == 'for STATGEN'][0]

# Check that the site data object has the right purpose. As this is for generating wind statistics it needs to be
# SdPurpStatgen
if obj_site_data_service.GetSiteDataObject(sitedata.Handle).Purpose == 'SdPurpStatgen':
    print('Correct purpose for added site data object.')
else:
    raise ValueError('Incorrect purpose for site data objects.')
ses.SGSiteDataHandle = sitedata.Handle

# Adding all MCP models
template_models = calc_MCP_service.GetTemplateModels()
print(template_models)
# All template models have the same handle. Need to use SetMCPCalc to have windPRO assign correct handles
ses.Models.TApiMCPModel = template_models
nan_to_skipvalue(mcp_calc)
calc_MCP_service.SetMCPCalc(mcp_calc)

# Checking the handles for the models.
mcp_calc = calc_MCP_service.GetMCPCalc()
for ses in mcp_calc.Sessions.TApiMcpSession[0].Models.TApiMCPModel:
    print('method: {}, handle:{}'.format(ses.Method, ses.Handle))

# Checking some statistics available in MCP
correlation = calc_MCP_service.GetCorrelationModelInputData(sessionHandle=mcp_session_handle,
                                                            Averaging="aiMonth")
print("Correlation between reference and long term data. Monthly averaged.")
print(correlation)

single_MK_test = calc_MCP_service.GetMeasureAndReference(sessionHandle=mcp_session_handle,
                                                         StartMonth='ApiJan')
print("Information on the long term variability.")
print(single_MK_test)

# Training and testing data. Using 24h alternating slicing
calc_MCP_service.TrainAndTest(mcp_session_handle, 'Api24Hours')

# Getting updated statistics on wind speed and energy for hourly averaging
statistics_24h_speed = calc_MCP_service.UpdateStatistics(mcp_session_handle, 'saHour', 'satWindSpeed',
                                                        'residualsDefault')

for ds in statistics_24h_speed:
    print(f"{ds.Method:>25}: WS measured concurrent {ds.MeasuredMeanWindSpeedConcurrent:2.3f}, WS predicted concurrent "
          f"{ds.PredictedMeanWindSpeedConcurrent:2.3f}, WS long term {ds.LongTermMeanWindSpeed:2.3f}")

# Setting to 3 (the neural network model)
mcp_calc.Sessions.TApiMcpSession[0].Handle = 3

# Close and calculate
calculation_service.CloseCalc(save=True)
calculation_service.Calculate(handle=mcp_calc.Handle)

# Using MCP to make a new longer time series in the meteoobject for the measurement
# For this the calculationg needs to be open, since this calculation is started from within the GUI of the calculation
# in windPRO
calculation_service.OpenCalcForEdit(handle=mcp_handle)
mcp_calc = calc_MCP_service.GetMCPCalc()
calc_MCP_service.PredictToMeteo(sessionHandle=mcp_calc.Sessions.TApiMcpSession[0].Handle,
                                modelHandle=3,
                                inMeasMeteo=True,
                                newName='Scripting Long Term Corrected')

# Making wind statistics
calc_MCP_service.PredictToWindStat(sessionHandle=mcp_calc.Sessions.TApiMcpSession[0].Handle,
                                   modelHandle=3,
                                   wsFnName=os.path.join(working_dir, 'wind_stat_MCP.wws'))
calculation_service.CloseCalc(save=True)