/// <summary> /// Do measurements which depend on fitness_params. /// /// 8th type /// /// example sensor: /// used by all fitness sensors /// </summary> /// <param name="time">current simulation time</param> /// <param name="id">id of sensor</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="par">some doubles</param> /// <param name="value">first measured value</param> /// <exception cref="exception">Unknown sensor id</exception> public void measure(double time, string id, biogas.plant myPlant, //double deltatime, biooptim.fitness_params myFitnessParams, double[] par, out double value) { physValue[] vals = measureVec(time, id, myPlant, myFitnessParams, par); value = vals[0].Value; }
/// <summary> /// Do measurements which depend on fitness_params. /// /// 8th type /// /// example sensor: /// used by all fitness sensors /// </summary> /// <param name="time">current simulation time</param> /// <param name="id">id of sensor</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="par">some doubles</param> /// <returns>measured values</returns> /// <exception cref="exception">Unknown sensor id</exception> public physValue[] measureVec(double time, string id, biogas.plant myPlant, //double deltatime, biooptim.fitness_params myFitnessParams, params double[] par) { sensor mySensor = get(id); return(mySensor.measure(time, sampling_time, myPlant, myFitnessParams, this, par)); }
/// <summary> /// calculate finale fitness vector, for so-optimization this is a vector with /// one element only /// </summary> /// <param name="myFitnessParams"></param> /// <param name="energyBalance"></param> /// <param name="fitness_constraints"></param> /// <param name="udot"></param> /// <returns>fitness vector</returns> private static double[] calcFitnessVector(fitness_params myFitnessParams, double energyBalance, double fitness_constraints, double udot) { double[] fitness = new double[myFitnessParams.nObjectives]; if (myFitnessParams.nObjectives == 1) { // TODO - der vorfaktor vor udot muss immer identisch sein zu dem // welcher in matlab genutzt wird fitness[0] = myFitnessParams.myWeights.w_money * energyBalance + fitness_constraints + myFitnessParams.myWeights.w_udot * udot; } else if (myFitnessParams.nObjectives == 2) { fitness[0] = energyBalance; // 1000 €/d // TODO - der vorfaktor vor udot muss immer identisch sein zu dem // welcher in matlab genutzt wird fitness[1] = fitness_constraints + myFitnessParams.myWeights.w_udot * udot; } else if (myFitnessParams.nObjectives == 3) { fitness[0] = energyBalance; // 1000 €/d // TODO - der vorfaktor vor udot muss immer identisch sein zu dem // welcher in matlab genutzt wird fitness[1] = fitness_constraints; fitness[2] = myFitnessParams.myWeights.w_udot * udot; } else { throw new exception(String.Format("myFitnessParams.nObjectives == {0}", myFitnessParams.nObjectives)); } return(fitness); }
// ------------------------------------------------------------------------------------- // !!! PRIVATE METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Calc weighted sum of fitness values /// </summary> /// <param name="myFitnessParams"></param> /// <param name="SS_COD_fitness"></param> /// <param name="VS_COD_fitness"></param> /// <param name="pHvalue_fitness"></param> /// <param name="VFA_TAC_fitness"></param> /// <param name="TS_fitness"></param> /// <param name="VFA_fitness"></param> /// <param name="AcVsPro_fitness"></param> /// <param name="TAC_fitness"></param> /// <param name="OLR_fitness"></param> /// <param name="HRT_fitness"></param> /// <param name="N_fitness">NH3 and NH4 boundaries</param> /// <param name="CH4_fitness"></param> /// <param name="biogasExcess_fitness">wird in 1000 €/d Verlust gerechnet</param> /// <param name="Stability_punishment"></param> /// <param name="energyProd_fitness">is produced energy near max. producable energy</param> /// <param name="fitness_etaIE"> /// fitness of removal capacity of intestinal enterococci: 0, ..., 1 /// </param> /// <param name="fitness_etaFC"> /// fitness of removal capacity of faecal coliforms: 0, ..., 1 /// </param> /// <param name="diff_setpoints"></param> /// <returns></returns> private static double calcFitnessConstraints(fitness_params myFitnessParams, double SS_COD_fitness, double VS_COD_fitness, //double VS_COD_degradationRate, double pHvalue_fitness, double VFA_TAC_fitness, double TS_fitness, double VFA_fitness, double AcVsPro_fitness, double TAC_fitness, double OLR_fitness, double HRT_fitness, double N_fitness, double CH4_fitness, double biogasExcess_fitness, double Stability_punishment, double energyProd_fitness, double fitness_etaIE, double fitness_etaFC, double diff_setpoints) { // TODO // anstatt biogasExcess / 20000 // prüfen ob biogasExcess > 10 % der max. zu verarbietenden Biogasmenge, // d.h. > 110 % produzierte biogasmenge isngesamt, dann mit 1 * gewicht // bestrafen double fitness_constraints = myFitnessParams.myWeights.w_CSB * (SS_COD_fitness + VS_COD_fitness) + // TODO macht der term sinn? //myFitnessParams.myWeights.w_CSB * 1 / 3 * Convert.ToDouble(VS_COD_degradationRate < 65) + myFitnessParams.myWeights.w_pH * pHvalue_fitness + myFitnessParams.myWeights.w_TS * TS_fitness + // TODO - falls einfluss zu stark, dann noch mit w_money multiplizieren myFitnessParams.myWeights.w_gasexc * biogasExcess_fitness + // wegen finanziellem Verlust // und wegen Umweltbelastung, falls Biogas nicht ideal verbrennt, so oder so // es wird CO2 erzeugt, was vorher mit energieaufwand angebaut wurde // dieser term ist für umweltbelastung, einfach eine konstante -> 1 // linearer anstieg mit biogasExcess_fitness ist ja schon oben, muss nicht doppelt // nicht > 0 machen, da matlab berechnung von excess gas komischerweise werte // ganz knapp über 0 zurück gibt auch wenn sie 0 sind. wo da der fehler // ist muss ich mal prüfen // TODO - da ich keine Sprünge mag habe ich das auskommentiert!!! //myFitnessParams.myWeights.w_gasexc * 1 / 2 * Convert.ToDouble(biogasExcess_fitness > 0.001) + myFitnessParams.myWeights.w_CH4 * CH4_fitness + myFitnessParams.myWeights.w_FOS_TAC * VFA_TAC_fitness + myFitnessParams.myWeights.w_VFA * VFA_fitness + myFitnessParams.myWeights.w_AcVsPro * AcVsPro_fitness + myFitnessParams.myWeights.w_TAC * TAC_fitness + myFitnessParams.myWeights.w_OLR * OLR_fitness + myFitnessParams.myWeights.w_HRT * HRT_fitness + myFitnessParams.myWeights.w_N * N_fitness + myFitnessParams.myWeights.w_energy * energyProd_fitness + Stability_punishment + myFitnessParams.myWeights.w_faecal * (fitness_etaIE + fitness_etaFC) + myFitnessParams.myWeights.w_setpoint * diff_setpoints; return(fitness_constraints); }
// ------------------------------------------------------------------------------------- // !!! PUBLIC METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// called by fitness_sensor in MATLAB /// </summary> /// <param name="time">current simulation time in days</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySubstrates"></param> /// <param name="par"></param> public void measure_optim_params(double time, biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.substrates mySubstrates, double par) { // measure substrate costs // Calculation of costs of substrate inflow // € / d double substrate_costs, manurebonus, udot; measure(time, "substrate_cost", mySubstrates, out substrate_costs); // measure whether current substrate feed qualifies for EEG2009 manure bonus measure(time, "manurebonus", mySubstrates, 0, out manurebonus); measure(time, "udot", mySubstrates, 0, out udot); // measure all other fitness sensors measure_type8(time, myPlant, myFitnessParams, par); }
// ------------------------------------------------------------------------------------- // !!! PUBLIC METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// get all objectives /// </summary> /// <param name="mySensors"></param> /// <param name="myPlant"></param> /// <param name="mySubstrates"></param> /// <param name="myFitnessParams"></param> /// <param name="Stability_punishment"></param> /// <param name="energyBalance">cost - benefit [1000 €/d]</param> /// <param name="energyProd_fitness"></param> /// <param name="energyConsumption">total el. energy consumption [kWh/d]</param> /// <param name="energyThConsumptionHeat">thermal energy consumption [kWh/d]</param> /// <param name="energyConsumptionPump">el. energy consumption for pumps [kWh/d]</param> /// <param name="energyConsumptionMixer">el. energy consumption for mixer [kWh/d]</param> /// <param name="energyProdMicro">thermal energy prod. microbiology [kWh/d]</param> /// <param name="moneyEnergy"> /// money I get for selling the produced total energy (el. + therm.) in €/d /// </param> /// <param name="fitness_constraints">sum of fitness functions</param> /// <param name="fitness">fitness vector</param> public static void getObjectives(biogas.sensors mySensors, biogas.plant myPlant, biogas.substrates mySubstrates, fitness_params myFitnessParams, /*out double SS_COD_fitness, out double VS_COD_fitness,*/ /*out double SS_COD_degradationRate, out double VS_COD_degradationRate, */ /*out double CH4_fitness, */ out double Stability_punishment, out double energyBalance, out double energyProd_fitness, out double energyConsumption, out double energyThConsumptionHeat, out double energyConsumptionPump, out double energyConsumptionMixer, out double energyProdMicro, /*out double energyThermProduction, * out double energyProduction,*/out double moneyEnergy, out double fitness_constraints, out double[] fitness) { double pHvalue_fitness, VFA_TAC_fitness, TS_fitness, VFA_fitness, AcVsPro_fitness, TAC_fitness, OLR_fitness, HRT_fitness, N_fitness, biogasExcess_fitness, diff_setpoints, CH4_fitness, SS_COD_fitness, VS_COD_fitness; // // normalized between 0 and 1 mySensors.getCurrentMeasurementD("SS_COD_fit", out SS_COD_fitness); // normalized between 0 and 1 mySensors.getCurrentMeasurementD("VS_COD_fit", out VS_COD_fitness); // fitness > 0 if pH value under or over boundaries // normalized between 0 and 1 mySensors.getCurrentMeasurementD("pH_fit", out pHvalue_fitness); // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein mySensors.getCurrentMeasurementD("VFA_TAC_fit", out VFA_TAC_fitness); // this is the fitness of the TS in the digester // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein mySensors.getCurrentMeasurementD("TS_fit", out TS_fitness); // TODO // Calculation of TS concentration in inflow // gibt es auch schon in Individuum Überprüfung: nonlcon_substrate // braucht hier dann eigentlich nicht mehr gemacht werden // verhältnis von propionic acid to acetic acid // max. grenze bei 1.4, s. PhD für Quellen // hier ist der Kehrwert, also min grenze, hier wird mit tukey gearbeitet mySensors.getCurrentMeasurementD("AcVsPro_fit", out AcVsPro_fitness); // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein mySensors.getCurrentMeasurementD("VFA_fit", out VFA_fitness); // tukey mySensors.getCurrentMeasurementD("TAC_fit", out TAC_fitness); // tukey mySensors.getCurrentMeasurementD("OLR_fit", out OLR_fitness); // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein mySensors.getCurrentMeasurementD("HRT_fit", out HRT_fitness); // sum of Snh4 + Snh3, mit tukey mySensors.getCurrentMeasurementD("N_fit", out N_fitness); // CH4 > 50 % als tukey implementiert mySensors.getCurrentMeasurementD("CH4_fit", out CH4_fitness); // biogasExcess_fitness is lossbiogasExcess / 1000 // measured in tausend € / d mySensors.getCurrentMeasurementD("gasexcess_fit", out biogasExcess_fitness); // TODO // // calculate OLR and HRT of plant // TODO - ich könnte auch faecal_fit_sensor schreiben // faecal bacteria removal capacity // intestinal enterococci // faecal coliforms double etaIE = 0, etaFC = 0; for (int idigester = 0; idigester < myPlant.getNumDigesters(); idigester++) { string digesterID = myPlant.getDigesterID(idigester + 1); etaIE += mySensors.getCurrentMeasurementDind("faecal_" + digesterID, 0); etaFC += mySensors.getCurrentMeasurementDind("faecal_" + digesterID, 1); } if (myPlant.getNumDigesters() > 0) { etaIE /= myPlant.getNumDigesters(); etaFC /= myPlant.getNumDigesters(); } // TODO - als ausgabeargumente definieren - nö double fitness_etaIE, fitness_etaFC; // wird in 100 % gemessen fitness_etaIE = 1.0f - etaIE / 100.0f; fitness_etaFC = 1.0f - etaFC / 100.0f; // TODO // stability //stateIsStable(1:n_fermenter,1)= 0; //for ifermenter= 1:n_fermenter // %digester_id= char( plant.getDigesterID(ifermenter) ); // %% TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // stateIsStable(ifermenter,1)= 1;%... // %getStateIsStable(measurements, digester_id, plant); //end //% d.h instabil? //if any(stateIsStable == 0) // Stability_punishment= 1; //else // Stability_punishment= 0; //end Stability_punishment = 0; // TODO // double mbonus; mySensors.getCurrentMeasurementD("manurebonus", out mbonus); myFitnessParams.manurebonus = Convert.ToBoolean(mbonus); // energyConsumption = getElEnergyConsumption(myPlant, mySensors, out energyConsumptionPump, out energyConsumptionMixer); // double energyThProdMixer; double energyThConsumption = getThermalEnergyConsumption(myPlant, mySensors, out energyThConsumptionHeat, out energyThProdMixer, out energyProdMicro); // TODO: einheiten nicht sauber // costs for heating in €/d // // kosten für heizung werden direkt in geld umgerechnet // wenn thermisch produzierte wärme zum heizen des fermenters benutzt wird, // dann werden hier virtuelle kosten berechnet mit kosten revenueTherm, // welche unten bei sellEnergy wieder als erlös mit dem gleichen Wert // berechnet werden, d.h. +/- das gleiche. // double costs_heating = myPlant.calcCostsForHeating_Total( new physValue(energyThConsumption, "kWh/d"), myPlant.myFinances.revenueTherm.Value, myPlant.myFinances.priceElEnergy.Value); // // total el. energy production in kWh/d double energyProduction = mySensors.getCurrentMeasurementDind("energyProdSum", 0); // total thermal energy production in kWh/d double energyThermProduction = mySensors.getCurrentMeasurementDind("energyProdSum", 1); //energyProduction= getEnergyProduction(myPlant, mySensors, out energyThermProduction); // double energyProductionMax = getMaxElEnergyProduction(myPlant); // measured in 100 % energyProd_fitness = (1 - energyProduction / energyProductionMax); // Calculation of costs of substrate inflow // € / d double substrate_costs; mySensors.getCurrentMeasurementD("substrate_cost", out substrate_costs); // double udot; mySensors.getCurrentMeasurementD("udot", out udot); // // TODO // was ist wenn wir weniger thermische energie im BHKW erzeugen als wir verbrauchen? // dann ist costs_heating (virt. kosten) > moneyEnergy thermisch (verkauf von thermischer Energie) // die differenz muss dann elektrisch erzeugt werden, wird allerdings nicht gemacht. // die differenz wird aktuell alas virtuelle Kosten verbucht (Verlust den man hat da man nicht wärme verkauft) // und nicht als reale kosten (erzeugungskosten: thermische energie erzeugt durch heizung) // um das zu lösen, warum ruft man nicht berechnung von costs_heating nach berechnung // von energyThermProduction auf und übergibt dann differenz zw. energyThConsumption und // energyThermProduction? // // TODO - was ist wenn die produzierte elektrische energie von niemanden abgenommen wird // das ist der fall, wenn nach sollwert gefahren wird, dann wird nur so viel energie bezahlt // wie nach sollwert verlangt wurde, das geht so ab eeg 2012 - direktvermarktung // must be in kWh/d double energyElSold = 0; // electrical energy that would be sold // dann gibt es eine referenz kurve welche angibt wieviel energie verkauft würde wenn sie produziert // würde, hier nur elektrische energie if (mySensors.exist("ref_energy_sold")) { // wichtig, dass man sich die messung zur aktuellen zeit holt, da // ref_energy_sold eine referenz vorgibt double time = mySensors.getCurrentTime(); energyElSold = mySensors.getMeasurementDAt("ref_energy_sold", "", time, 0, false); energyElSold = Math.Min(energyElSold, energyProduction); } else { energyElSold = energyProduction; } // moneyEnergy : €/d moneyEnergy = biogas.gasexcess_fit_sensor.sellEnergy(energyElSold, energyThermProduction, myPlant, myFitnessParams); // € / d // is negative when we make more money as we have to pay energyBalance = energyConsumption * myPlant.myFinances.priceElEnergy.Value + costs_heating - moneyEnergy + substrate_costs; // tausend € / d energyBalance = energyBalance / 1000; // // TODO bool noisy = false; // calc setpoint control error //diff_setpoints = calc_setpoint_errors(mySensors, myPlant, myFitnessParams, noisy); mySensors.getCurrentMeasurementD("setpoint_fit", noisy, out diff_setpoints); // calc total fitness of all the constraints fitness_constraints = calcFitnessConstraints(myFitnessParams, SS_COD_fitness, VS_COD_fitness, /*VS_COD_degradationRate,*/ pHvalue_fitness, VFA_TAC_fitness, TS_fitness, VFA_fitness, AcVsPro_fitness, TAC_fitness, OLR_fitness, HRT_fitness, N_fitness, CH4_fitness, biogasExcess_fitness, Stability_punishment, energyProd_fitness, fitness_etaIE, fitness_etaFC, diff_setpoints); // calc fitness vector fitness = calcFitnessVector(myFitnessParams, energyBalance, fitness_constraints, udot); }
// ------------------------------------------------------------------------------------- // !!! PUBLIC METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Do measurements which depend on fitness_params. /// /// 8th type /// /// example sensor: /// used by all fitness sensors /// </summary> /// <param name="time">current simulation time</param> /// <param name="id">id of sensor</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="par">some double</param> /// <param name="value">first measured value</param> /// <exception cref="exception">Unknown sensor id</exception> public void measure(double time, string id, biogas.plant myPlant, //double deltatime, biooptim.fitness_params myFitnessParams, double par, out double value) { double[] parvec = { par }; measure(time, id, myPlant, myFitnessParams, parvec, out value); }