package longoperation.operation.DP;
import longoperation.data.dataStru.PowerStru;
import longoperation.db.dbconnect.DBConnectManager;
import longoperation.tools.datatools.DataManager;
import longoperation.tools.datatools.MathFuns;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Date;
/*区分流量与水量,出力与发电量*/
public class DP {
public static DataManager DM = new DataManager();
public PowerStru power;
private String power_id;
private String powerName;
private String regulation;
private int T = 12; //计算时段
/*保存优化计算结果,水位过程线,出力过程线,弃水过程线,*/
private double[] E_opt = new double[T - 1]; //保存2月初到12月初,共十一个点的最优路径上的 E数据,累积效益,,
private double[] Z_line = new double[T + 1]; //输出结果:水位过程线 13个点 属于时刻
private double[] N_line = new double[T]; //输出结果: 月平均出力 12个值,一个月一个 属于时段
private double[] E_line = new double[T]; //输出结果:月平均发电量 属于时段
private double[] H_line = new double[T];
private double[] R_line = new double[T];
public double[] Qout_line = new double[T]; //出库过程线,12个点,一个月一个, 属于时段
private double[] Qabandon_line = new double[T]; //弃水流量 属于时段 12个
private double[] Qgen_line = new double[T];
private int[] Index = new int[T - 1];
private double[][] resultE = new double[T - 1][]; //保存优化计算结果中的累积效益,从2月初到次年一月初共11个
private double[][] resultZ = new double[T - 1][]; //存每次优化计算的水头Z,从2月初到12月初 共11个,与resultE一一对应
private ArrayList resultE_e = new ArrayList(); //保存每次优化计算的阶段效益,从2月到11月 共10个,与resultE对应
private double Etatol; //保存年最大发电量 12月末时刻值
private double Eall;
/*计算用到的参数变量*/
private final int[] t = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //各月天数
public double[][] zv, zq, zr;
private double Nmin;
private double[] Qin;
private double dead_level;
private double normal_level;
private double NCapacity; //装机容量约束
private double N_COE; //出力平均系数,用耗水率计算时用不到
private double H_LOSTCONST; //水头损失常数,
private double H_LOSSCOE; //水头损失系数
private double Qoutmax;
private double Qgenmax;
private double HSTART; //计算时段初水位
private double HEND; //计算时段末水位
private double[] normal_levels;
private int caltype_long; //公式或耗水率,0为耗水率,1为公式计算
/*惩罚系数*/
private int PRESICE = 100;
private double coe_penalty1 = 0.5; //弃水惩罚系数
private double coe_penalty2;
private final double penalty =0- Math.pow(1000,20);
private void DPWork() {
int period = 0; //代表时段 0-11
double tsec; //时段长 单位秒
double[] Z_Now; //面临时段的时段初水位
double[] Z_Old; //面临时段的时段末水位
double[] Eold; //面临时段各时段初水位对应的累积最大发电量
double[] Enow; //面临时段各时段末水位对应的累积最大发电量
/*第一个时段。一月份,*/
Z_Now = DM.discreteZ(this.normal_levels[1],
this.dead_level, PRESICE);
/*第一步,根据当前时段的水位上下限,离散水位*/
tsec = 3600 * 24 * t[0]; /*计算当前时段的时长,,单位为秒*/
double Estart = 0;
Enow = new double[Z_Now.length];
for (int i = 0; i < Z_Now.length; i++) { //决策循环,随i变的起始条件只有 z_now
double H; //净水头,计算中间量
double R; //耗水率,计算中间量
double N;
double E;
double Qout; //针对每个决策计算的出库流量
double Qgen; //针对每个决策计算的发电力量
double zdown; //针对每个决策计算的Qout对应的水库下游水位
double Qwaste; //弃水
/*开始给变量赋予具体值*/
double zup_old = HSTART; //单位为 米
double zup_now = Z_Now[i]; // 单位为 米
double vup_now = 10000 * (DM.getVFromZ(zup_now, this.zv)); //单位为 立方米
double vup_old = 10000 * (DM.getVFromZ(zup_old, this.zv));
/*水量平衡计算Qout Qout = (Vk - V`k + Qin*t)/t */
Qout = (vup_old - vup_now + Qin[0] * tsec) / tsec;
/*此处判断的情况属于不允许在决策中出现的,直接将目标函数罚为负值*/
if (Qout <= 0 || Qout > Qoutmax) {
E = penalty;
continue;
}
else {
/*尾水位泄量关系插值得下游水位*/
zdown = DM.getZFromQ(Qout, this.zq);
H = getH(zup_old, zup_now, zdown, H_LOSTCONST);
R = DM.getRFromZ(H, zr); /*耗水率曲线插值*/
/*出库流量大于最大发电流量时的处理***对目标函数施加惩罚*/
if (Qout > this.Qgenmax) {
Qgen = Qgenmax;
Qwaste = (Qout - Qgen); // 弃水流量,需保存
double penaltyE = coe_penalty1 * Math.pow(Qwaste, 2);
N = Qgen / R * 3600 / 10000; //单位 万千瓦
E = N * tsec / 3600 - penaltyE; //单位为万千瓦时,对出现弃水的情况加以惩罚,允许有弃水出现
}
/*出库流量小于最大发电流量*/
else {
Qgen = Qout;
/*计算N N = Qgen/R*3600 */
N = Qgen / R * 3600 / 10000; //单位万千瓦 立方米/秒 除以
if (N < Nmin) {
double penaltyE = coe_penalty2 * Math.pow( (N - Nmin), 2)/2;
E = N * tsec / 3600 - penaltyE; //单位为 万千瓦时
}
else {
E = N * tsec / 3600; //单位为万千瓦时
}
}
}
/*需要保存的东西*/
Enow[i] = E; /*万千瓦时*/
}
resultE[0] = Enow;
resultZ[0] = Z_Now;
/*计算第一阶段结束*/
/* 二月初到12月初 共10个时段 1到10*/
for (period = 1; period < T - 1; period++) {
Z_Now = DM.discreteZ(this.normal_levels[period + 1],
this.dead_level, PRESICE);
Z_Old = DM.discreteZ(this.normal_levels[period],
this.dead_level, PRESICE);
resultZ[period] = Z_Now;
double[][] E_e = new double[Z_Old.length][Z_Now.length]; //每个阶段点对点计算的决策变量的目标函数值
Eold = Enow;
Enow = new double[Z_Now.length];
tsec = 3600 * 24 * t[period];
/* 选定时段后对时段初水位进行循环 目的只是为了计算 E_e 附带计算Q_abandon */
for (int oldzNo = 0; oldzNo < Z_Old.length; oldzNo++) {
double zup_old = Z_Old[oldzNo]; //单位为 米 计算净水头时用到 -一个对应一个循环
for (int nowzNo = 0; nowzNo < Z_Now.length; nowzNo++) {
double H; //净水头,计算中间量 由时段初、末水位,及尾水位得到 属于1月份每个离散水头的变量
double R; //耗水率,计算中间量 由H得到
double Qout; //针对每个决策计算的出库流量 /*用于每个时段针对每个离散点的计算*/
double Qgen; //针对每个决策计算的发电力量
double zdown; //针对每个决策计算的Qout对应的水库下游水位
double Qwaste; //弃水
double N; //由 Qgen与R得到
double E;
/*开始给变量赋予具体值*/
double zup_now = Z_Now[nowzNo]; // 单位为 米
double vup_now = 10000 * (DM.getVFromZ(zup_now, this.zv)); //单位为 立方米
double vup_old = 10000 * (DM.getVFromZ(zup_old, this.zv));
/*水量平衡计算Qout Qout = (Vk - V`k + Qin*t)/t */
Qout = (vup_old - vup_now + Qin[period] * tsec) / tsec;
/*出力下泄流量约束,若为零或超过最大下泄流量,直接对目标函数给一个很大的负值,并打断此次循环,下个决策开始*/
if (Qout <= 0 || Qout > Qoutmax) {
E = penalty;
N = penalty;
Qgen = penalty;
Qwaste = 0;
E_e[oldzNo][nowzNo] = E;
continue; // 是否continue 都一样,
}
else
/*Qout正常 计算*/{
zdown = DM.getZFromQ(Qout, this.zq);
H = getH(zup_old, zup_now, zdown, H_LOSTCONST);
R = DM.getRFromZ(H, zr);
/*出现弃水时的处理,******暂时想法:不应该对弃水时的发电量进行惩罚*/
if (Qout > this.Qgenmax) {
Qg