Commit 43b5d05d authored by Gerrit Erichsen's avatar Gerrit Erichsen
Browse files

Some corrections to storage's discharge and charge function as well as efficiency file load

parent bbd87093
......@@ -12,7 +12,10 @@ EfficiencyField::EfficiencyField()
dummy.push_back(1.);
m_xAxis = dummy;
m_yAxis = dummy;
dummy[1] = 0.;
m_maxValue = 0.001;
m_minValue = 0.001;
dummy[0] = m_minValue;
dummy[1] = m_minValue;
dummy2.push_back(dummy);
dummy2.push_back(dummy);
m_values = dummy2;
......@@ -24,6 +27,16 @@ EfficiencyField::EfficiencyField(const vector<double> & xAxis, const vector<doub
m_yAxis(yAxis),
m_values(values)
{
m_maxValue = 0.;
m_minValue = 1.;
for (const vector<double> & vec : values)
{
for (const double & value : vec)
{
if (value > m_maxValue) m_maxValue = value;
if (value < m_minValue) m_minValue = value;
}
}
}
bool EfficiencyField::isEmpty()
......@@ -59,6 +72,16 @@ void EfficiencyField::setData(const vector<double> & xAxis, const vector<double>
m_xAxis = xAxis;
m_yAxis = yAxis;
m_values = values;
m_maxValue = 0.;
m_minValue = 1.;
for (const vector<double> & vec : values)
{
for (const double & value : vec)
{
if (value > m_maxValue) m_maxValue = value;
if (value < m_minValue) m_minValue = value;
}
}
}
double EfficiencyField::getMinX() const
......@@ -117,17 +140,16 @@ vector<pair<double, double> > EfficiencyField::getFixedCurve(bool front, bool al
return result;
}
double EfficiencyField::getEfficiency(double x, double y,
double minValue) const
double EfficiencyField::getEfficiency(double x, double y) const
{
size_t indexX1, indexX2, indexY1, indexY2;
//set x indices
indexX2 = findUpperIndex(x, m_xAxis);
if (indexX2 > m_xAxis.size()) return minValue;
if (indexX2 > m_xAxis.size()) return getEfficiencyMin();
indexX1 = (indexX2 > 0) ? indexX2 - 1 : 0;
//set y indices
indexY2 = findUpperIndex(y, m_yAxis);
if (indexY2 > m_yAxis.size()) return minValue;
if (indexY2 > m_yAxis.size()) return getEfficiencyMin();
indexY1 = (indexY2 > 0) ? indexY2 - 1 : 0;
//calculate 2-D interpolation, first major case x1 matches x
if (isCloseEnoughToEqual(x, m_xAxis[indexX1])
......@@ -209,6 +231,16 @@ double EfficiencyField::getEfficiencyBottomRight() const
return m_values.back().back();
}
double EfficiencyField::getEfficiencyMin() const
{
return m_minValue;
}
double EfficiencyField::getEfficiencyMax() const
{
return m_maxValue;
}
string EfficiencyField::getFieldAsText() const
{
string txt = "";
......
......@@ -27,16 +27,20 @@ public:
double getMinY() const;
double getMaxY() const;
vector<pair<double, double>> getFixedCurve(bool front, bool alongX);
double getEfficiency(double x, double y, double minValue = 0.) const;
double getEfficiency(double x, double y) const;
double getEfficiencyCapped(double x, double y) const;
double getEfficiencyTopLeft() const;
double getEfficiencyBottomRight() const;
double getEfficiencyMin() const;
double getEfficiencyMax() const;
string getFieldAsText() const;
private:
vector<double> m_xAxis;
vector<double> m_yAxis;
vector<vector<double>> m_values;
double m_minValue;
double m_maxValue;
};
#endif // EFFICIENCYFIELD_H
......@@ -1186,7 +1186,7 @@ void Node::calculateStoragePower(size_t timeStep)
}
else //tz - do as before
{
powerOfPlant = m_storage[i]->discharge(powerOfPlant, timeStep);
powerOfPlant = m_storage[i]->discharge(currentResidual, timeStep);
storageLoad += powerOfPlant;
currentResidual -= powerOfPlant;
if (isCloseEnoughToEqual(currentResidual, 0.)) currentResidual = 0.;
......
......@@ -217,7 +217,7 @@ double Storage::charge(double nodeExcessPower, size_t step)
if (plantPower > maxPower) plantPower = maxPower;
// power withing range
if (plantPower * m_preferences->getStepTime() * getEfficiencyCharge(step, nodeExcessPower)
if (plantPower * m_preferences->getStepTime() * getEfficiencyCharge(step, plantPower)
<= m_storageCapacity - lastStorageLevel
&& plantPower >= minPower)
{
......@@ -227,22 +227,29 @@ double Storage::charge(double nodeExcessPower, size_t step)
m_lastStepOfPower = step;
}
else if (m_storageCapacity - lastStorageLevel >= minPower * m_preferences->getStepTime()
&& plantPower >= minPower)
&& plantPower >= minPower && plantPower > 0.)
{
m_storageLevel[step] = m_storageCapacity;
double powerReserve = (m_storageCapacity - lastStorageLevel) / m_preferences->getStepTime();
// this **should** be solved iteratively. But to not waste time, we'll take a random
// guess at the efficiency. This should be somewhat accurate enough
double efficiency = getEfficiencyCharge(step,
powerReserve
/ m_efficiencyCharge.getEfficiencyTopLeft());
if (isCloseEnoughToEqual(efficiency, 0.))
double powerCalc = powerReserve;
double powerNew = powerReserve;
int counter = 0; //used to restrict re-calcs
do
{
powerCalc = (fabs(1. - powerNew / powerCalc) > 0.1) ? (powerNew + powerCalc) * 0.5 : powerNew;
powerNew = powerReserve / getEfficiencyCharge(step, powerCalc);
} while (fabs(powerCalc - powerNew) > 0.01 * powerCalc && counter++ < 10);
if (powerReserve > plantPower)
{
plantPower = std::min(plantPower, powerReserve / 1e-5); // 1 permille as effictive min efficiency
double newLevel = lastStorageLevel
+ plantPower * m_preferences->getStepTime()
* getEfficiencyCharge(step, plantPower);
m_storageLevel[step] = (newLevel > m_storageCapacity) ? m_storageCapacity : newLevel;
}
else
{
plantPower = powerReserve / efficiency;
m_storageLevel[step] = m_storageCapacity;
plantPower = powerReserve;
}
m_lastStepOfPower = step;
}
......@@ -300,7 +307,8 @@ double Storage::discharge(double nodeResidualPower, size_t step)
plantPower = 0.;
}
m_load[step] = plantPower;
m_fullLoadHoursDischarge += plantPower * m_preferences->getStepTime() / m_nominalPowerDischarge;
m_fullLoadHoursDischarge += plantPower * m_preferences->getStepTime()
/ m_nominalPowerDischarge;
return plantPower;
}
......@@ -322,59 +330,34 @@ void Storage::turnOff(int step, bool charging)
void Storage::selfDischarge(int step)
{
//to discharge "m_lastStepOfPower" and "step" are not allowed to be equal, since those losses are embedded in the efficiencies
if ((m_lastStepOfPower != step || step == 0)
&& m_preferences->getLevelOfInterpolation() == 1)
if (m_lastStepOfPower != step || step == 0)
{
//defining helper value, since previous step of first step is last step
double lastStorageLevel;
if (step == 0)
{
lastStorageLevel = m_initialStorageLevel;
}
else
{
lastStorageLevel = m_storageLevel[step - 1];
}
double lastStorageLevel = (step == 0) ? m_initialStorageLevel : m_storageLevel[step - 1];
//discharge only, when not already empty
if (lastStorageLevel <= 0.)
{
m_storageLevel[step] = 0.;
}
else //discharge
else if (m_preferences->getLevelOfInterpolation() == 1) //discharge
{
m_storageLevel[step] = pow(1. - interpolatePairFromFirstToSecondLinear(lastStorageLevel / m_storageCapacity, m_selfDischargeInPercent) * 0.01,
m_storageLevel[step] = pow(1. - interpolatePairFromFirstToSecondLinear(lastStorageLevel
/ m_storageCapacity,
m_selfDischargeInPercent)
* 0.01,
m_preferences->getStepTime()) * lastStorageLevel;
}
//control to not get 'emptier', than empty
if (m_storageLevel[step] < 0.)
{
m_storageLevel[step] = 0.;
}
}
else if (m_lastStepOfPower != step || step == 0) //level = 0 --> const value required
{
//defining helper value, since previous step of first step is last step
double lastStorageLevel;
if (step == 0)
{
lastStorageLevel = m_initialStorageLevel;
}
else
{
lastStorageLevel = m_storageLevel[step - 1];
}
//discharge only, when not already empty
if (lastStorageLevel <= 0.)
{
m_storageLevel[step] = 0.;
}
else if (m_preferences->useLastValueWhenConst()) //discharge with last value in vector
{
m_storageLevel[step] = lastStorageLevel - m_selfDischargeInPercent.back().second * 0.01 * m_preferences->getStepTime() * lastStorageLevel;
m_storageLevel[step] = lastStorageLevel - m_selfDischargeInPercent.back().second
* 0.01 * m_preferences->getStepTime()
* lastStorageLevel;
}
else //discharge with first value in vector
{
m_storageLevel[step] = lastStorageLevel - m_selfDischargeInPercent.front().second * 0.01 * m_preferences->getStepTime() * lastStorageLevel;
m_storageLevel[step] = lastStorageLevel - m_selfDischargeInPercent.front().second
* 0.01 * m_preferences->getStepTime()
* lastStorageLevel;
}
//control to not get 'emptier', than empty
if (m_storageLevel[step] < 0.)
......@@ -560,8 +543,7 @@ double Storage::getEfficiencyCharge(size_t step, double power) const
&& lastStorageLevel <= m_storageCapacity)
{
eta = m_efficiencyDischarge.getEfficiency(power / m_nominalPowerCharge,
lastStorageLevel / m_storageCapacity,
1e-6);
lastStorageLevel / m_storageCapacity);
}
else
{
......
......@@ -59,7 +59,7 @@ EfficiencyField WindTableItem::getEfficiencyField(int powerDensity, int acceptab
&& m_efficiencies[i].first < powerDensity + acceptableDiff
&& (bestIndex < 0
|| abs(powerDensity - m_efficiencies[i].first)
< abs(powerDensity - m_efficiencies[bestIndex].first)))
< abs(powerDensity - m_efficiencies[bestIndex].first)))
{
bestIndex = i;
}
......@@ -136,7 +136,8 @@ bool WindTableItem::setCtCurveFile(QString fileName)
return false;
}
bool WindTableItem::addEfficiencyField(int powerDensity, const EfficiencyField & efficiencyField)
bool WindTableItem::addEfficiencyField(int powerDensity, const EfficiencyField & efficiencyField,
bool isFreshlyCalculated)
{
if (powerDensity < 1) return false;
bool inserterd = false;
......@@ -151,38 +152,46 @@ bool WindTableItem::addEfficiencyField(int powerDensity, const EfficiencyField &
inserterd = true;
}
}
if (m_efficiencies.count() == 0)
{
m_efficiencies.push_back(std::pair<int, EfficiencyField>(powerDensity,
efficiencyField));
}
if (isFreshlyCalculated)
{
#ifdef __APPLE__
QDir directory(QDir::currentPath() + "/../../../.windEfficiencyFiles/");
QDir directory(QDir::currentPath() + "/../../../.windEfficiencyFiles/");
#else
QDir directory(QDir::currentPath() + "/.windEfficiencyFiles/");
QDir directory(QDir::currentPath() + "/.windEfficiencyFiles/");
#endif
if (!directory.exists())
{
directory.mkpath(directory.path());
}
QString fileName = directory.path() + directory.separator() + this->getName()
+ "_" + QString::number(m_rotorDiameter)
+ "_" + QString::number(m_heightOfHub)
+ "_" + QString::number(powerDensity)
+ ".dat";
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QTextStream fileStream(&file);
if (!directory.exists())
{
directory.mkpath(directory.path());
}
QString fileName = directory.path() + directory.separator() + this->getName()
+ "_" + QString::number(m_rotorDiameter)
+ "_" + QString::number(m_heightOfHub)
+ "_" + QString::number(powerDensity)
+ ".dat";
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QTextStream fileStream(&file);
fileStream << QString("\"# Auto generated efficiency field for ") + this->getName() + "\"" << endl;
fileStream << QString("\"# Rotor diameter:\";") << m_rotorDiameter << ";\"m\"" << endl;
fileStream << QString("\"# Hub Height:\";") << m_heightOfHub << ";\"m\"" << endl;
fileStream << QString("\"# Power curve file:\";") << m_powerCurveFile << endl;
fileStream << QString("\"# ct curve file:\";") << m_ctCurveFile << endl;
fileStream << QString("\"# Hub Height:\";") << m_heightOfHub << ";\"m\"" << endl;
fileStream << QString("\"# Power Density:\";") << powerDensity << ";\"MW/km^2\"" << endl;
fileStream << QString("\"# Date of creation:\";")
<< QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
fileStream << QString("\"y-axis (v)\";\"Wind Direction in °\";")
<< QString("\"x-axis (->)\";\"Wind Speed in m/s\";") << endl;
fileStream << QString::fromStdString(efficiencyField.getFieldAsText()) << endl;
fileStream << QString("\"# Auto generated efficiency field for ") + this->getName() + "\"" << endl;
fileStream << QString("\"# Rotor diameter:\";") << m_rotorDiameter << ";\"m\"" << endl;
fileStream << QString("\"# Hub Height:\";") << m_heightOfHub << ";\"m\"" << endl;
fileStream << QString("\"# Power curve file:\";") << m_powerCurveFile << endl;
fileStream << QString("\"# ct curve file:\";") << m_ctCurveFile << endl;
fileStream << QString("\"# Hub Height:\";") << m_heightOfHub << ";\"m\"" << endl;
fileStream << QString("\"# Power Density:\";") << powerDensity << ";\"MW/km^2\"" << endl;
fileStream << QString("\"# Date of creation:\";")
<< QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
fileStream << QString("\"y-axis (v)\";\"Wind Direction in °\";")
<< QString("\"x-axis (->)\";\"Wind Speed in m/s\";") << endl;
fileStream << QString::fromStdString(efficiencyField.getFieldAsText()) << endl;
file.close();
file.close();
}
return true;
}
......@@ -220,14 +229,13 @@ void WindTableItem::loadEfficiencies()
if (fileName.startsWith(textToFind))
{
EfficiencyField field;
std::thread readThread([=, &fileName, &field] {load2DFile(fileName, field);});
readThread.join();
load2DFile(fileName, field);
int lastUnderscorePos = fileName.lastIndexOf("_");
int densityDescriptionLength = fileName.indexOf(".") - lastUnderscorePos - 1;
int powerDensity = fileName.mid(lastUnderscorePos + 1, densityDescriptionLength).toInt();
if (powerDensity > 0)
{
addEfficiencyField(powerDensity, field);
addEfficiencyField(powerDensity, field, false);
}
}
}
......
......@@ -71,7 +71,8 @@ public:
bool setPowerCurveFile(QString fileName);
bool setCtCurveFile(QString fileName);
bool addEfficiencyField(int powerDensity,
const EfficiencyField & efficiencyField);
const EfficiencyField & efficiencyField,
bool isFreshlyCalculated = true);
private:
bool doEfficienciesExist() const;
......
......@@ -69,6 +69,7 @@ Preferences &Preferences::operator=(const Preferences & rhs)
m_hardTargetCO2 = rhs.m_hardTargetCO2;
m_levelOfInterpolation = rhs.m_levelOfInterpolation;
m_useLastValueWhenConst = rhs.m_useLastValueWhenConst;
m_densityEquivalence = rhs.m_densityEquivalence;
m_createOperationPlan = rhs.m_createOperationPlan;
m_reworkOperationPlan = rhs.m_reworkOperationPlan; //tz
m_nPointsIntervall = rhs.m_nPointsIntervall;
......@@ -171,6 +172,7 @@ void Preferences::loadSettings()
m_hardTargetCO2 = settings.value("hard_target", 0.03805).toDouble();
m_levelOfInterpolation = settings.value("interpolation_level", 1).toInt();
m_useLastValueWhenConst = settings.value("last_value_when_const", true).toBool();
m_densityEquivalence = settings.value("acceptableDensityDiff", 2).toInt();
m_createOperationPlan = settings.value("create_operation_plan", false).toBool();
m_reworkOperationPlan = settings.value("rework_operation_plan", false).toBool(); //tz
m_nPointsIntervall = settings.value("n_points_intervall", 192).toInt();
......@@ -212,6 +214,7 @@ void Preferences::saveSettings()
settings.setValue("hard_target", m_hardTargetCO2);
settings.setValue("interpolation_level", m_levelOfInterpolation);
settings.setValue("last_value_when_const", m_useLastValueWhenConst);
settings.setValue("acceptableDensityDiff", m_densityEquivalence);
settings.setValue("create_operation_plan", m_createOperationPlan);
settings.setValue("rework_operation_plan", m_reworkOperationPlan);
settings.setValue("n_points_intervall", m_nPointsIntervall);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment