Skip to content

Commit

Permalink
Passing custom rotation angles to irradproc incidence angle
Browse files Browse the repository at this point in the history
  • Loading branch information
mjprilliman committed Oct 19, 2023
1 parent f6ec275 commit 080f986
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 16 deletions.
25 changes: 18 additions & 7 deletions shared/lib_irradproc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ solarpos_spa(int year, int month, int day, int hour, double minute, double secon

void incidence(int mode, double tilt, double sazm, double rlim, double zen,
double azm, bool en_backtrack, double gcr, double slope_tilt, double slope_azm,
bool force_to_stow, double stow_angle_deg, double angle[5]) {
bool force_to_stow, double stow_angle_deg, bool useCustomAngle, double customAngle, double angle[5]) {
/*
Calculate panel orientation, angle of incidence with beam radiation, and
tracker rotation angles (where applicable).
Expand Down Expand Up @@ -1225,6 +1225,9 @@ void incidence(int mode, double tilt, double sazm, double rlim, double zen,
}

/*Check if custom tilt angles enabled, apply timeseries value*/
if (useCustomAngle) {
rot = customAngle * DTOR; //overwrite rotation angle with input from array
}

/* Find tilt angle for the tracking surface */
arg = cos(xtilt) * cos(rot);
Expand Down Expand Up @@ -1768,7 +1771,7 @@ irrad::irrad(weather_record wf, weather_header hdr,
double groundCoverageRatioIn, double slopeTiltIn, double slopeAzmIn, std::vector<double> monthlyTiltDegrees,
std::vector<double> userSpecifiedAlbedo,
poaDecompReq *poaAllIn,
bool useSpatialAlbedos, const util::matrix_t<double>* userSpecifiedSpatialAlbedos, bool enableSubhourlyClipping, bool useCustomTiltAngles) :
bool useSpatialAlbedos, const util::matrix_t<double>* userSpecifiedSpatialAlbedos, bool enableSubhourlyClipping, bool useCustomTiltAngles, double customTiltAngles) :
skyModel(skyModelIn), radiationMode(radiationModeIn), trackingMode(trackModeIn),
enableBacktrack(backtrackingEnabled), forceToStow(forceToStowIn),
delt(dtHour), tiltDegrees(tiltDegreesIn), surfaceAzimuthDegrees(azimuthDegreesIn),
Expand Down Expand Up @@ -1797,6 +1800,8 @@ irrad::irrad(weather_record wf, weather_header hdr,

set_subhourly_clipping(enableSubhourlyClipping);

set_custom_tilt_angles(useCustomTiltAngles, customTiltAngle);

if (radiationMode == irrad::DN_DF) set_beam_diffuse(wf.dn, wf.df);
else if (radiationMode == irrad::DN_GH) set_global_beam(wf.gh, wf.dn);
else if (radiationMode == irrad::GH_DF) set_global_diffuse(wf.gh, wf.df);
Expand Down Expand Up @@ -1990,6 +1995,12 @@ void irrad::set_subhourly_clipping(bool enable)
if (enable) this->enableSubhourlyClipping = true;
}

void irrad::set_custom_tilt_angles(bool enable, double angle)
{
this->useCustomTiltAngles = enable;
this->customTiltAngle = angle;
}

void irrad::set_sky_model(int sm, double alb, const std::vector<double> &albSpatial) {
this->skyModel = sm;
this->albedo = alb;
Expand Down Expand Up @@ -2178,7 +2189,7 @@ int irrad::calc() {
// compute incidence angles onto fixed or tracking surface
incidence(trackingMode, tiltDegrees, surfaceAzimuthDegrees, rotationLimitDegrees, sunAnglesRadians[1],
sunAnglesRadians[0],
enableBacktrack, groundCoverageRatio, slopeTilt, slopeAzm, forceToStow, stowAngleDegrees, surfaceAnglesRadians);
enableBacktrack, groundCoverageRatio, slopeTilt, slopeAzm, forceToStow, stowAngleDegrees, useCustomTiltAngles, customTiltAngle, surfaceAnglesRadians);
if (radiationMode < irrad::POA_R) {
double hextra = sunAnglesRadians[8];
double hbeam = directNormal *
Expand Down Expand Up @@ -2578,7 +2589,7 @@ void irrad::getFrontSurfaceIrradiances(double pvFrontShadeFraction, double rowTo
// Calculate irradiance components for a 90 degree tilt to get horizon brightening
double angleTmp[5] = {0, 0, 0, 0, 0}; // ([0] = incidence angle, [1] = tilt)
incidence(0, 90.0, 180.0, 45.0, solarZenithRadians, solarAzimuthRadians, this->enableBacktrack,
this->groundCoverageRatio, this->slopeTilt, this->slopeAzm, this->forceToStow, this->stowAngleDegrees, angleTmp);
this->groundCoverageRatio, this->slopeTilt, this->slopeAzm, this->forceToStow, this->stowAngleDegrees, this->useCustomTiltAngles, this->customTiltAngle, angleTmp);
perez(0, calculatedDirectNormal, calculatedDiffuseHorizontal, albedo, angleTmp[0], angleTmp[1], solarZenithRadians,
poa, diffc);
double horizonDiffuse = diffc[2];
Expand Down Expand Up @@ -2714,7 +2725,7 @@ void irrad::getFrontSurfaceIrradiances(double pvFrontShadeFraction, double rowTo
// Calculate and add direct and circumsolar irradiance components
incidence(0, tiltRadians * RTOD, surfaceAzimuthRadians * RTOD, 45.0, solarZenithRadians, solarAzimuthRadians,
this->enableBacktrack, this->groundCoverageRatio, this->slopeTilt, this->slopeAzm,
this->forceToStow, this->stowAngleDegrees, surfaceAnglesRadians);
this->forceToStow, this->stowAngleDegrees, this->useCustomTiltAngles, this->customTiltAngle, surfaceAnglesRadians);
perez(0, calculatedDirectNormal, calculatedDiffuseHorizontal, albedo, surfaceAnglesRadians[0],
surfaceAnglesRadians[1], solarZenithRadians, poa, diffc);

Expand Down Expand Up @@ -2759,7 +2770,7 @@ void irrad::getBackSurfaceIrradiances(double pvBackShadeFraction, double rowToRo
// Calculate components for a 90 degree tilt to get horizon brightening
double surfaceAnglesRadians90[5] = {0, 0, 0, 0, 0};
incidence(0, 90.0, 180.0, 45.0, solarZenithRadians, solarAzimuthRadians, this->enableBacktrack,
this->groundCoverageRatio, this->slopeTilt, this->slopeAzm, this->forceToStow, this->stowAngleDegrees, surfaceAnglesRadians90);
this->groundCoverageRatio, this->slopeTilt, this->slopeAzm, this->forceToStow, this->stowAngleDegrees, this->useCustomTiltAngles, this->customTiltAngle, surfaceAnglesRadians90);
perez(0, calculatedDirectNormal, calculatedDiffuseHorizontal, albedo, surfaceAnglesRadians90[0],
surfaceAnglesRadians90[1], solarZenithRadians, planeOfArrayIrradianceRear, diffuseIrradianceRear);
double horizonDiffuse = diffuseIrradianceRear[2];
Expand Down Expand Up @@ -2959,7 +2970,7 @@ void irrad::getBackSurfaceIrradiances(double pvBackShadeFraction, double rowToRo
// Calculate and add direct and circumsolar irradiance components
incidence(0, 180.0 - tiltRadians * RTOD, (surfaceAzimuthRadians * RTOD - 180.0), 45.0, solarZenithRadians,
solarAzimuthRadians, this->enableBacktrack,
this->groundCoverageRatio, this->slopeTilt, this->slopeAzm, this->forceToStow, this->stowAngleDegrees, surfaceAnglesRadians);
this->groundCoverageRatio, this->slopeTilt, this->slopeAzm, this->forceToStow, this->stowAngleDegrees, this->useCustomTiltAngles, this->customTiltAngle, surfaceAnglesRadians);
perez(0, calculatedDirectNormal, calculatedDiffuseHorizontal, albedo, surfaceAnglesRadians[0],
surfaceAnglesRadians[1], solarZenithRadians, planeOfArrayIrradianceRear, diffuseIrradianceRear);

Expand Down
10 changes: 8 additions & 2 deletions shared/lib_irradproc.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ void solarpos_spa(int year, int month, int day, int hour, double minute, double
* \param[out] angle[3] tracking axis rotation angle in radians, measured from surface normal of unrotating axis (only for 1 axis trackers)
* \param[out] angle[4] backtracking difference (rot - ideal_rot) will be zero except in case of backtracking for 1 axis tracking
*/
void incidence(int mode, double tilt, double sazm, double rlim, double zen, double azm, bool en_backtrack, double gcr, double slope_tilt, double slope_azm, bool force_to_stow, double stow_angle_deg, double angle[5]);
void incidence(int mode, double tilt, double sazm, double rlim, double zen, double azm, bool en_backtrack, double gcr, double slope_tilt, double slope_azm, bool force_to_stow, double stow_angle_deg, bool useCustomAngle, double customAngle, double angle[5]);


/**
Expand Down Expand Up @@ -991,6 +991,10 @@ class irrad
//Enable subhourly clipping correction
bool enableSubhourlyClipping;

//Custom rotation angles for single-axis trackers
bool useCustomTiltAngles;
double customTiltAngle; // custom tracker rotation angle in degrees

// Subarray properties
double tiltDegrees; ///< Surface tilt of subarray in degrees
double surfaceAzimuthDegrees; ///< Surface azimuth of subarray in degrees
Expand Down Expand Up @@ -1055,7 +1059,7 @@ class irrad
double dtHour, double tiltDegrees, double azimuthDegrees, double trackerRotationLimitDegrees, double stowAngleDegreesIn,
double groundCoverageRatio, double slopeTilt, double slopeAzm, std::vector<double> monthlyTiltDegrees, std::vector<double> userSpecifiedAlbedo,
poaDecompReq* poaAllIn,
bool useSpatialAlbedos = false, const util::matrix_t<double>* userSpecifiedSpatialAlbedos = nullptr, bool enableSubhourlyClipping = false, bool useCustomTiltAngles = false);
bool useSpatialAlbedos = false, const util::matrix_t<double>* userSpecifiedSpatialAlbedos = nullptr, bool enableSubhourlyClipping = false, bool useCustomTiltAngles = false, double customTiltAngle = 0);

/// Construct the irrad class with an Irradiance_IO() object and Subarray_IO() object
irrad();
Expand All @@ -1078,6 +1082,8 @@ class irrad
//Set whether to use subhourly clipping model
void set_subhourly_clipping(bool enable = false);

void set_custom_tilt_angles(bool enable = false, double angle = 0);

/// Set the sky model for the irradiance processor, using \link Irradiance_IO::SKYMODEL
void set_sky_model(int skymodel, double albedo, const std::vector<double> &albedoSpatial = std::vector<double>());

Expand Down
9 changes: 8 additions & 1 deletion shared/lib_pv_io_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ Subarray_IO::Subarray_IO(compute_module* cm, const std::string& cmName, size_t s
nModulesPerString = cm->as_integer(prefix + "modules_per_string");
mpptInput = cm->as_integer(prefix + "mppt_input");
trackMode = cm->as_integer(prefix + "track_mode");
useCustomTiltAngles = cm->as_integer("use_custom_tilt_angles");
tiltEqualLatitude = 0;
if (cm->is_assigned(prefix + "tilt_eq_lat")) tiltEqualLatitude = cm->as_boolean(prefix + "tilt_eq_lat");

Expand All @@ -376,8 +377,14 @@ Subarray_IO::Subarray_IO(compute_module* cm, const std::string& cmName, size_t s
if (monthlyTiltDegrees[i] < 0.0) throw exec_error(cmName, "Subarray " + util::to_string((int)subarrayNumber) + " monthly tilt angles cannot be negative.");
}
}

/* Insert checks for custom tilt angles here*/

if (cm->is_assigned("custom_tilt_angles_array") && useCustomTiltAngles == 1) {
customTiltAngles = cm->as_vector_double("custom_tilt_angle_array");
for (int i = 0; i < customTiltAngles.size(); i++) {
if (customTiltAngles[i] < 0.0) throw exec_error(cmName, "Subarray " + util::to_string((int)subarrayNumber) + "custom tilt angles cannot be negative.");
}
}
//azimuth required for fixed tilt, single axis, and seasonal tilt- can't check for this in variable table so check here
azimuthDegrees = std::numeric_limits<double>::quiet_NaN();
if (trackMode == irrad::FIXED_TILT || trackMode == irrad::SINGLE_AXIS || trackMode == irrad::SEASONAL_TILT)
Expand Down
12 changes: 6 additions & 6 deletions ssc/cmod_pvsamv1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1126,9 +1126,9 @@ void cm_pvsamv1::exec()

std::vector<ssc_number_t> user_tilt_angles; user_tilt_angles.reserve(nrec);
size_t user_tilt_angles_size;
int use_user_tilt_angles = (as_integer("use_user_tilt_angles") == 1 && is_assigned("user_tilt_angles_array"));
if (as_integer("use_user_tilt_angles") == 1 && is_assigned("user_tilt_angles_array")) {
user_tilt_angles = as_vector_ssc_number_t("user_tilt_angles_array");
int use_custom_tilt_angles = (as_integer("use_custom_tilt_angles") == 1 && is_assigned("custom_tilt_angles_array"));
if (as_integer("use_custom_tilt_angles") == 1 && is_assigned("custom_tilt_angles_array")) {
user_tilt_angles = as_vector_ssc_number_t("custom_tilt_angles_array");
user_tilt_angles_size = user_tilt_angles.size();
if (user_tilt_angles_size != nrec)
throw exec_error("pvsamv1", "The measured temperature array must be the size of nrecords per year");
Expand All @@ -1138,7 +1138,7 @@ void cm_pvsamv1::exec()
//also check here for tilt > 0 for tracking systems, since this is a very uncommon configuration but an easy mistake to make
for (size_t nn = 0; nn < num_subarrays; nn++)
{
if (as_integer("use_user_tilt_angles") == 1 && is_assigned("user_tilt_angles_array")) {
if (as_integer("use_custom_tilt_angles") == 1 && is_assigned("custom_tilt_angles_array")) {
Subarrays[nn]->trackMode = irrad::SINGLE_AXIS;
//Subarrays[nn]->tiltDegrees = 0; //reset to 0 to then be replaced in loop?
Subarrays[nn]->backtrackingEnabled = false; //account for backtracking in user-specified angles [deg]
Expand Down Expand Up @@ -1507,7 +1507,7 @@ void cm_pvsamv1::exec()
continue; // skip disabled subarrays

/*
if (as_integer("use_user_tilt_angles") == 1 && is_assigned("user_tilt_angles_array")) {
if (as_integer("use_custom_tilt_angles") == 1 && is_assigned("custom_tilt_angles_array")) {
Subarrays[nn]->tiltDegrees = user_tilt_angles[inrec];

}*/
Expand All @@ -1518,7 +1518,7 @@ void cm_pvsamv1::exec()
Irradiance->dtHour, Subarrays[nn]->tiltDegrees, Subarrays[nn]->azimuthDegrees, Subarrays[nn]->trackerRotationLimitDegrees, 0.0, Subarrays[nn]->groundCoverageRatio, Subarrays[nn]->slopeTilt, Subarrays[nn]->slopeAzm,
Subarrays[nn]->monthlyTiltDegrees, Irradiance->userSpecifiedMonthlyAlbedo,
Subarrays[nn]->poa.poaAll.get(),
Irradiance->useSpatialAlbedos, &Irradiance->userSpecifiedMonthlySpatialAlbedos, as_boolean("enable_subhourly_clipping"));
Irradiance->useSpatialAlbedos, &Irradiance->userSpecifiedMonthlySpatialAlbedos, as_boolean("enable_subhourly_clipping"), as_boolean("use_custom_tilt_angles"), user_tilt_angles[inrec]);

int code = irr.calc();

Expand Down

0 comments on commit 080f986

Please sign in to comment.