Beispiel #1
0
        /// <summary>
        /// aktuell type 4
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="u">Qin in m³/d</param>
        /// <param name="par">
        /// par[0] is the density of the substrate in kg/m^3
        /// </param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     double u, params double[] par)
        {
            //
            physValue[] values = new physValue[1];

            // 1. komponente ist rho als double, unten in density def. dann anstatt
            // 1000 einsetzen
            if (par.Length != 1) // 2, da rho auch übergeben werden muss
            {
                throw new exception(String.Format(
                                        "Length of par is != 1: {0}!", par.Length));
            }

            transportation myTransportations = myPlant.myTransportation;

            // get pump from transportation class using id
            biogas.substrate_transport mySubsTransport = myTransportations.getSubstrateTransportByID(id_suffix);

            // is the energy_per_ton [kWh/t]
            double energy_per_ton = mySubsTransport.energy_per_ton;

            // calc energy consumption in kWh/d
            // hier muss man schon rho der zu fördernden menge kennen
            values[0] = new physValue("Pel_trans", u * par[0] / 1000 * energy_per_ton, "kWh/d",
                                      "transport energy");

            return(values);
        }
Beispiel #2
0
        /// <summary>
        /// Print state values to a string, to be displayed on a console
        /// </summary>
        /// <param name="x">state vector</param>
        /// <param name="digester_id"></param>
        /// <param name="myPlant"></param>
        /// <returns></returns>
        public static string print(double[] x, string digester_id, plant myPlant)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("  pH= " + calcPHOfADMstate(x).ToString("0.00") + "\t\t\t");
            sb.Append("NH4= " + calcNH4p(x, digester_id, myPlant, "g/l").printValue() + "\n");

            sb.Append("  VFA/TA= " + calcFOSTACOfADMstate(x).printValue() + "\t\t\t");
            sb.Append("TA= " + calcTACOfADMstate(x, "gCaCO3eq/l").printValue() + "\t\t\t");
            sb.Append("VFA= " + calcVFAOfADMstate(x, "gHAceq/l").printValue() + "\n");

            sb.Append("  Sac= " + calcFromADMstate(x, "Sac", "g/l").printValue() + "\t\t\t");
            sb.Append("Sbu= " + calcFromADMstate(x, "Sbu", "g/l").printValue() + "\t\t\t");
            sb.Append("Spro= " + calcFromADMstate(x, "Spro", "g/l").printValue() + "\t\t\t");
            sb.Append("Sva= " + calcFromADMstate(x, "Sva", "g/l").printValue() + "\n");

            physValue T = myPlant.getDigesterByID(digester_id).get_params_of("T");
            physValue V = myPlant.getDigesterByID(digester_id).get_params_of("Vliq");

            physValue qgas_h2, qgas_ch4, qgas_co2, qgas;

            calcBiogasOfADMstate(x, V, T, out qgas_h2, out qgas_ch4, out qgas_co2, out qgas);

            sb.Append("  Qch4= " + qgas_ch4.printValue("0.000") + "\t\t");
            sb.Append("Qco2= " + qgas_co2.printValue("0.000") + "\t\t");
            sb.Append("Qh2= " + qgas_h2.printValue("0.0000") + "\t\t");
            sb.Append("Qgas= " + qgas.printValue("0.00") + "\n");

            return(sb.ToString());
        }
Beispiel #3
0
        // -------------------------------------------------------------------------------------
        //                              !!! PUBLIC METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// calc organic nitrogen in state vector x
        /// measured in k mol N/m3
        /// </summary>
        /// <param name="x">ADM1 state or stream vector</param>
        /// <param name="digester_id">ID of digester</param>
        /// <param name="myPlant"></param>
        /// <returns>organic nitrogen</returns>
        public static double calcNorg(double[] x, string digester_id, plant myPlant)
        {
            // get ADM1 parameters
            // das sind die zuletzt upgedateten Parameter, nicht die default Werte
            double[] ADM1params = myPlant.getDefaultADMparams(digester_id);

            //

            // TODO - funktioniert nicht mehr wenn sich Positionen in vektor verschieben

            // TODO in ADMstate_properties wurden Positionen definiert, diese nutzen!!!

            // amino acids [kg COD/m3]
            double Saa = x[pos_Saa - 1];

            // soluble inerts kg COD/m3
            double SI = x[11];
            // composite kg COD/m3
            double Xc = x[12];

            // proteins kg COD/m3
            double Xpr = x[14];

            double Xbio = calcBiomassOfADMstate(x).Value;

            // particulate inerts kg COD/m3
            double XI = x[23];
            // Particulate products arising from biomass decay kg COD/m^3
            double Xp = x[24];


            // TODO funktioniert nicht wenn ADM parameter sich verändern

            double fSI_XC = ADM1params[ADMparams.pos_fSI_XC - 1]; // fraction SI from XC

            double fCH_XC = ADM1params[ADMparams.pos_fCH_XC - 1]; // fraction Xch from XC
            double fPR_XC = ADM1params[ADMparams.pos_fPR_XC - 1]; // fraction Xpr from XC
            double fLI_XC = ADM1params[ADMparams.pos_fLI_XC - 1]; // fraction Xli from XC
            double fXP_XC = ADM1params[ADMparams.pos_fXP_XC - 1]; // fraction Xp from XC

            double fXI_XC = 1 - fSI_XC - fCH_XC - fPR_XC - fLI_XC - fXP_XC;

            double N_I  = ADM1params[7];
            double N_aa = ADM1params[8];

            double N_XB = ADM1params[23];

            double N_Xp = ADM1params[103];


            // calc Norg
            // alle Verbindungen, welche Kohlenstoff beinhalten nennt man organisch
            // die anderen anorganisch. Ausnahme sind Oxide wie bspw. CO2 und ein paar weitere
            // Ausnahmen. damit sind hier alle verbindungen organisch, bspw. auch SI und XI.

            double Norg = N_aa * (Saa + fPR_XC * Xc + Xpr) + N_Xp * (fXP_XC * Xc + Xp) +
                          N_XB * Xbio + N_I * (SI + XI + fSI_XC * Xc + fXI_XC * Xc);

            return(Norg);
        }
Beispiel #4
0
        /// <summary>
        /// type 7
        ///
        /// called in ADMstate_stoichiometry.cs -> measure_type7
        /// </summary>
        /// <param name="x">ADM state vector - not used</param>
        /// <param name="myPlant"></param>
        /// <param name="mySubstrates">not yet used</param>
        /// <param name="mySensors">used to get TS inside digester</param>
        /// <param name="Q">not used</param>
        /// <param name="par">not used</param>
        /// <returns>measured values</returns>
        override protected physValue[] doMeasurement(double[] x, biogas.plant myPlant,
                                                     biogas.substrates mySubstrates,
                                                     biogas.sensors mySensors,
                                                     double[] Q, params double[] par)
        {
            // 1st Pel in kWh/d for mixing digester
            // 2nd Pdissipated in kWh/d for mixing digester, dissipated in digester
            physValue[] values = new physValue[dimension];

            //

            digester myDigester = myPlant.getDigesterByID(id_suffix);

            // calc stirrer(s) power for digester in kWh/d
            values[0] = myDigester.calcStirrerPower(mySensors);

            // calc stirrer(s) power dissipated to digester in kWh/d
            values[1] = myDigester.calcStirrerDissipation(mySensors);

            values[0].Label = "electrical energy of stirrer";
            values[1].Label = "thermal energy dissipated by stirrer";

            //

            return(values);
        }
Beispiel #5
0
        /// <summary>
        /// Print state values to a string, to be displayed on a console
        /// </summary>
        /// <param name="x"></param>
        /// <param name="digester_id"></param>
        /// <param name="myPlant"></param>
        /// <param name="pH"></param>
        /// <param name="NH4"></param>
        /// <param name="VFATA"></param>
        /// <param name="VFA"></param>
        /// <param name="TA"></param>
        /// <param name="Sac"></param>
        /// <param name="Sbu"></param>
        /// <param name="Spro"></param>
        /// <param name="Sva"></param>
        /// <param name="gas_h2"></param>
        /// <param name="gas_ch4"></param>
        /// <param name="gas_co2"></param>
        /// <param name="gas"></param>
        /// <returns></returns>
        public static string printAndReturn(double[] x, string digester_id, plant myPlant,
                                            out double pH, out double NH4, out double VFATA, out double VFA, out double TA,
                                            out double Sac, out double Sbu, out double Spro, out double Sva, out double gas_h2,
                                            out double gas_ch4, out double gas_co2, out double gas)
        {
            pH  = calcPHOfADMstate(x);
            NH4 = calcNH4p(x, digester_id, myPlant, "g/l").Value;

            VFATA = calcFOSTACOfADMstate(x).Value;
            TA    = calcTACOfADMstate(x, "gCaCO3eq/l").Value;
            VFA   = calcVFAOfADMstate(x, "gHAceq/l").Value;

            Sac  = calcFromADMstate(x, "Sac", "g/l").Value;
            Sbu  = calcFromADMstate(x, "Sbu", "g/l").Value;
            Spro = calcFromADMstate(x, "Spro", "g/l").Value;
            Sva  = calcFromADMstate(x, "Sva", "g/l").Value;

            physValue T = myPlant.getDigesterByID(digester_id).get_params_of("T");
            physValue V = myPlant.getDigesterByID(digester_id).get_params_of("Vliq");

            physValue qgas_h2, qgas_ch4, qgas_co2, qgas;

            calcBiogasOfADMstate(x, V, T, out qgas_h2, out qgas_ch4, out qgas_co2, out qgas);

            gas_h2  = qgas_h2.Value;
            gas_ch4 = qgas_ch4.Value;
            gas_co2 = qgas_co2.Value;
            gas     = qgas.Value;

            return(print(x, digester_id, myPlant));
        }
Beispiel #6
0
        /// <summary>
        /// Measure NH4 content inside a digester
        /// 1st measurement is Snh4 in g/l
        /// 2nd : Snh4 + NH4 in Xc in g/l
        ///
        /// type 5
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="x">ADM state vector</param>
        /// <param name="param">not used - but OK</param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant, double[] x,
                                                     string param, params double[] par)
        {
            physValue[] values = new physValue[dimension];

            // hier wird umrechnungsfaktor 18 genutzt, deshalb nur ammonium und nicht
            // ammonium nitrogen
            values[0] = ADMstate.calcFromADMstate(x, "Snh4", "g/l");

            //
            // -2 wegen _2 bzw. _3
            string digester_id = id.Substring(("Snh4_").Length, id.Length - 2 - ("Snh4_").Length);

            // kmol N/m^3
            double NH4 = ADMstate.calcNH4(x, digester_id, myPlant);

            //
            // erstmal Snh4 nennen, damit convertUnit funktioniert
            // TODO - könnte es auch N nennen, dann wird allerdings nur mit 14 als
            // umrechnungsfaktor gerechnet und nicht wie jetzt mit 18. Vorsicht
            // bei vergleich mit Ntot, TKN und Norg, dort wird nur mit 14 gerechnet.
            // da ich die Größe ammonium nitrogen nenne, wird umrechnungsfaktor 14 genutzt
            values[1]        = new physValue("N", NH4, "mol/l", "total ammonium nitrogen");
            values[1]        = values[1].convertUnit("g/l");
            values[1].Symbol = "NH4";

            return(values);
        }
        /// <summary>
        /// aktuell type 4
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="u">Qin in m³/d</param>
        /// <param name="par">
        /// par[0] is the to be pumped amount in m³/d
        /// par[1] is the density of the sludge in kg/m^3 (gilt nur für substrate_transport)
        /// für pump Aufruf, par ist nur 1dim.
        /// </param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     double u, params double[] par)
        {
            //
            physValue[] values = new physValue[1];

            // sobald in MATLAB die neuen pumps genutzt werden, ist par 2dim
            // 2. komponente ist rho als double, unten in density def. dann anstatt
            // 1000 einsetzen
            if ((par.Length <= 0) || (par.Length > 2)) // 2, da rho auch übergeben werden muss
            {
                throw new exception(String.Format(
                                        "Length of par must be 1 or 2: {0}!", par.Length));
            }

            transportation myTransportations = myPlant.myTransportation;

            // get gravitational constant
            physValue g = myPlant.g;

            if (par.Length == 2)
            {
                // get pump from transportation class using id
                biogas.substrate_transport mySubstrateTransport =
                    myTransportations.getSubstrateTransportByID(id_suffix);

                // muss hier nicht gemacht werden, wird schon in pump gemacht
                // basierend auf id_suffix, bzw. dem Startort entscheidet man
                // wie groß die Dichte ist
                // wenn Start: substratemix ist, dann Dichte über Mittelwerte der zu pumpenden
                // Substrate wählen, dazu getSubstrateMixFlowForFermenter nutzen
                // wenn Start ein Digester oder storagetank ist, dann ist Dichte immer 1000 kg/m^3
                // gemessene Dichte des density_sensors interessiert nicht, weil das die Dichte des
                // Inputs von einem digester ist.

                physValue density = new physValue("rho", par[1], "kg/m^3", "density");

                // calc energy consumption in kWh/d
                // hier muss man schon rho der zu fördernden menge kennen
                values[0] = mySubstrateTransport.calcEnergyConsumption(u, par[0], g, density);
            }
            else if (par.Length == 1) // called from pump, we pump sludge
            {
                // get pump from transportation class using id
                biogas.pump myPump = myTransportations.getPumpByID(id_suffix);

                physValue density = new physValue("rho", 1000, "kg/m^3", "density");

                // calc energy consumption in kWh/d
                // hier muss man schon rho der zu fördernden menge kennen
                values[0] = myPump.calcEnergyConsumption(u, par[0], g, density);
            }
            else
            {
                throw new exception("par must be one- or two-dimensional!");
            }

            return(values);
        }
Beispiel #8
0
        /// <summary>
        /// returns NH3 in given unit
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="digester_id">digester id</param>
        /// <param name="myPlant"></param>
        /// <param name="unit">unit in which NH3 should be returned</param>
        /// <returns>NH3 in given unit</returns>
        /// <exception cref="exception">Conversion error</exception>
        /// <exception cref="exception">Unknown unit</exception>
        public static physValue calcNH3(double[] x, string digester_id, plant myPlant, string unit)
        {
            // NH3 in kmolN/m^3
            double NH3 = calcNH3(x, digester_id, myPlant);

            physValue pNH3 = new physValue("Snh3", NH3, "kmol/m^3");

            pNH3 = pNH3.convertUnit(unit);

            return(pNH3);
        }
Beispiel #9
0
        /// <summary>
        /// calc Ntot= TKN + NH3
        /// total nitrogen in k mol N/m3
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="digester_id">digester ID</param>
        /// <param name="myPlant"></param>
        /// <returns>Ntot</returns>
        public static double calcNtot(double[] x, string digester_id, plant myPlant)
        {
            double TKN = calcTKN(x, digester_id, myPlant);

            double NH3 = calcNH3(x, digester_id, myPlant);

            // calc Ntot= TKN + NH3
            double Ntot = TKN + NH3;

            return(Ntot);
        }
Beispiel #10
0
        /// <summary>
        /// returns NH4 in given unit
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="digester_id">digester id</param>
        /// <param name="myPlant"></param>
        /// <param name="unit">unit in which NH4 should be returned</param>
        /// <returns>NH4 in given unit</returns>
        /// <exception cref="exception">Conversion error</exception>
        /// <exception cref="exception">Unknown unit</exception>
        public static physValue calcNH4p(double[] x, string digester_id, plant myPlant, string unit)
        {
            // NH4 in kmolN/m^3
            double NH4 = calcNH4(x, digester_id, myPlant);

            physValue pNH4 = new physValue("Snh4", NH4, "kmol/m^3");

            pNH4 = pNH4.convertUnit(unit);

            return(pNH4);
        }
Beispiel #11
0
        /// <summary>
        /// calc TKN= Norg + NH4
        /// total Kjehldahl nitrogen in k mol N/m3
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="digester_id">digester ID</param>
        /// <param name="myPlant"></param>
        /// <returns>TKN</returns>
        public static double calcTKN(double[] x, string digester_id, plant myPlant)
        {
            double Norg = calcNorg(x, digester_id, myPlant);

            double NH4 = calcNH4(x, digester_id, myPlant);

            // calc TKN= Norg + NH4
            double TKN = Norg + NH4;

            return(TKN);
        }
Beispiel #12
0
        /// <summary>
        /// measures electrical and thermal energy produced by chp in kWh/d
        ///
        /// type: 5
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="u">biogas stream going through given chp</param>
        /// <param name="param">not used</param>
        /// <param name="par">not used</param>
        /// <returns>measured el. and thermal energy produced</returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     double[] u, string param,
                                                     params double[] par)
        {
            // wegen 2 siehe oben
            physValue[] values = new physValue[dimension];

            myPlant.burnBiogas(id_suffix, u, out values[0], out values[1]);

            return(values);
        }
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            // fitness > 0 if pH value under or over boundaries
            double pHvalue_fitness = getpHvalue_fitness(mySensors, myPlant, myFitnessParams);

            values[0] = new physValue("pH_fitness", pHvalue_fitness, "-");

            return(values);
        }
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            // this is the fitness of the VS_COD in the digester
            double VS_COD_degradationRate;
            double VS_COD_fitness = getVS_COD_fitness(mySensors, out VS_COD_degradationRate);

            values[0] = new physValue("VS_COD_fitness", VS_COD_fitness, "-");

            return(values);
        }
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein
            double VFA_TAC_fitness = sensors.calcFitnessDigester_min_max(myPlant, mySensors, "VFA_TAC",
                                                                         "min_max", myFitnessParams, "_3", true);

            values[0] = new physValue("VFA_TAC_fitness", VFA_TAC_fitness, "-");

            return(values);
        }
Beispiel #16
0
        /// <summary>
        /// calc NH4 in ADM1 state, this is the sum:
        /// Snh4 + NH4 in Xc, measured in the given unit
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="digester_id">digester ID</param>
        /// <param name="myPlant"></param>
        /// <param name="unit">unit in which NH4N is returned</param>
        /// <returns>NH4</returns>
        public static double calcNH4(double[] x, string digester_id, plant myPlant, string unit)
        {
            double NH4 = calcNH4(x, digester_id, myPlant);

            if (unit != "mol/l")
            {
                physValue values = new physValue("N", NH4, "mol/l", "total ammonium nitrogen");
                values = values.convertUnit(unit);

                NH4 = values.Value;
            }

            return(NH4);
        }
        /// <summary>
        /// Constructor called by the constructor of biogas.sensors while
        /// reading the sensors out of a XML file. So reader must be at the correct position,
        /// which is &lt;sensor&gt; was just read.
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="id">id of sensor</param>
        /// <param name="myPlant"></param>
        public total_biogas_sensor(ref XmlTextReader reader, string id,
                                   biogas.plant myPlant) :
            base(ref reader, id, myPlant.getNumCHPs() * (int)BioGas.n_gases +
                 (int)BioGas.n_gases + 1 + 1)
        {
            // gas for each chp
            // total gas splitted in fractions [% and ppm]
            // total biogas [m³/d]
            // biogas excess [m³/d]
            //dimension

            // TODO
            // type= ?
            _type = 87;
        }
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            // this is the fitness of the CH4 in the digester
            // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein
            double CH4_fitness;

            getBiogas_fitness(mySensors, out CH4_fitness);

            values[0] = new physValue("CH4_fitness", CH4_fitness, "-");

            return(values);
        }
        // -------------------------------------------------------------------------------------
        //                              !!! CONSTRUCTOR METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// Standard Constructor creating the sensor. Its id is total_biogas.
        /// id_suffix is here actually nothing
        /// </summary>
        /// <param name="id">TODO: what is that?</param>
        /// <param name="myPlant"></param>
        public total_biogas_sensor(string id, biogas.plant myPlant) :
            base(String.Format("{0}_{1}", _spec, id),
                 String.Format("total biogas sensor {0}", id), id,
                 myPlant.getNumCHPs() * (int)BioGas.n_gases +
                 (int)BioGas.n_gases + 1 + 1)
        {
            // gas for each chp
            // total gas splitted in fractions [% and ppm]
            // total biogas [m³/d]
            // biogas excess [m³/d]
            //dimension

            // TODO
            // type= ?
            _type = 87;
        }
Beispiel #20
0
        /// <summary>
        /// calc NH3 in ADM1 state, this is the sum:
        /// Snh3 + NH3 in Xc, measured in kmolN/m^3
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="digester_id">digester ID</param>
        /// <param name="myPlant"></param>
        /// <returns>NH4</returns>
        public static double calcNH3(double[] x, string digester_id, plant myPlant)
        {
            // get ADM1 parameters
            // das sind die zuletzt upgedateten Parameter, nicht die default Werte
            double[] ADM1params = myPlant.getDefaultADMparams(digester_id);

            // TODO - funktioniert nicht mehr wenn sich Positionen in vektor verschieben

            // Ammonium k mol N/m3
            double Snh4 = x[10];

            // composite kg COD/m3
            double Xc = x[12];

            // Ammonia k mol N/m3
            double Snh3 = x[32];

            // enthält NH4 und NH3
            double fSIN_XC = ADM1params[6]; // ist immer 0


            // Verhältnis von NH3 zu NH4 im Fermenter, Annahme, dass es sich
            // mit NH3 und NH4 in Xc genauso verhält.
            //
            // Herl:
            // Nsumme= NH4 + NH3= fSIN_Xc * Xc =
            // = NH3 * (1 + 1/r_N3_N4)
            // NH3= Nsumme / (1 + 1/r_N3_N4)
            // TODO: kann C# eigentlich mit /0 rechnen? denke schon
            // wenn ja, gibt es hier kein Problem, ob Snh3 oder Snh4 0 ist ist egal
            // C# rechnet richtig, scheinbar doch nicht, deshalb abfragen unten
            double r_N3_N4 = Snh3 / Snh4;

            double NH3 = Snh3 + fSIN_XC * Xc / (1 + 1 / r_N3_N4);

            // TODO - das ist falsch - Faktor 0.1 hängt von pH Wert ab
            // NH3 ist dann eher fSIN_XC * Xc * faktor, faktor hängt aber vom pH Wert ab
            if (Snh3 == 0)                       // da wir dann durch unendlich geteilt haben, gibt es probleme
            {
                NH3 = Snh3 + fSIN_XC * Xc * 0.1; // 1/ unendlich scheint in C# nicht 0 zu sein, sondern evtl. n.def.
            }
            else if (Snh4 == 0)                  // da wir dann durch unendlich geteilt haben, gibt es probleme
            {
                NH3 = Snh3 + fSIN_XC * Xc * 0.1; // 1/ unendlich scheint in C# nicht 0 zu sein, sondern evtl. n.def.
            }
            return(NH3);
        }
        // -------------------------------------------------------------------------------------
        //                              !!! PRIVATE METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// Calculates sum of setpoint control errors
        /// </summary>
        /// <param name="mySensors">sensors object with all measurements</param>
        /// <param name="myPlant">plant object</param>
        /// <param name="myFitnessParams">fitness params</param>
        /// <param name="noisy">if true then noisy measurements are used</param>
        /// <returns></returns>
        private static double calc_setpoint_errors(sensors mySensors, plant myPlant,
                                                   biooptim.fitness_params myFitnessParams, bool noisy)
        {
            double diff_setpoints = 0; // to be returned value: control setpoint error

            double[] sim_t = mySensors.getTimeStream();

            double t = mySensors.getCurrentTime();

            double sim_val, ref_val; // last simulated value and reference value at time t

            //

            if (sim_t.Length > 3)
            {
                foreach (biooptim.setpoint mySetpoint in myFitnessParams.mySetpoints)
                {
                    if (mySetpoint.s_operator == "") // then compare measurement of one sensor
                    {
                        string sensor_id = mySetpoint.sensor_id + "_" + mySetpoint.location;

                        // get reference values always not noisy
                        ref_val = mySensors.getMeasurementDAt(String.Format("ref_{0}_{1}", sensor_id, mySetpoint.index),
                                                              "", t, 0, false);

                        sim_val = mySensors.getCurrentMeasurementDind(sensor_id, mySetpoint.index, noisy);
                    }
                    else // compare measurement of a group of sensors, energy of all chps, gas of all digesters, ...
                    {
                        string s_operator = mySetpoint.location + "_" + mySetpoint.s_operator;

                        // get reference values always not noisy
                        ref_val = mySensors.getMeasurementDAt(
                            String.Format("ref_{0}_{1}", mySetpoint.sensor_id, mySetpoint.index),
                            "", t, 0, false);

                        sim_val = mySensors.getCurrentMeasurementDind(myPlant, mySetpoint.sensor_id, s_operator,
                                                                      mySetpoint.index, noisy);
                    }

                    diff_setpoints += mySetpoint.scalefac * Math.Pow(ref_val - sim_val, 2);
                }
            }

            return(diff_setpoints);
        }
        // -------------------------------------------------------------------------------------
        //                            !!! PRIVATE METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// returns a value between 0 and 1. if the pH value is lower or upper
        /// some constraints, then the value is greater 0, else 0.
        ///
        /// TODO: diese methode überdenken
        /// </summary>
        /// <param name="mySensors"></param>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <returns></returns>
        private static double getpHvalue_fitness(biogas.sensors mySensors, biogas.plant myPlant,
                                                 biooptim.fitness_params myFitnessParams)
        {
            double pH_Punishment = 0;
            double pH_value;

            int n_digester = myPlant.getNumDigesters();

            for (int idigester = 0; idigester < n_digester; idigester++)
            {
                string digester_id = myPlant.getDigesterID(idigester + 1);

                mySensors.getCurrentMeasurementD("pH_" + digester_id + "_3", out pH_value);

                // punish values bigger than 8 or smaller than 7
                // Der Faktor gibt die Steilheit der Strafe an, bei max. 2, dann ist
                // schon bei 8 bzw. 7 der Ausdruck ( 2.0 .* (pH(ifermenter,1) - 7.5) )
                // == 1

                // TODO - maybe use tukey function here instead
                // macht es überhaupt sinn mit optimal values zu arbeiten?
                // oder einfacher die calcFitnessDigester_min_max() methode nutzen

                double pH_punish_digester = Math.Min(1 / (10 ^ 4) * (
                                                         Math.Pow(1.8 * (pH_value -
                                                                         myFitnessParams.get_param_of("pH_optimum", idigester)), 12)),
                                                     Math.Abs(pH_value - myFitnessParams.get_param_of("pH_optimum", idigester)));

                pH_punish_digester = Math.Max(pH_punish_digester,
                                              Convert.ToDouble(pH_value < myFitnessParams.get_param_of("pH_min", idigester)));
                pH_punish_digester = Math.Max(pH_punish_digester,
                                              Convert.ToDouble(pH_value > myFitnessParams.get_param_of("pH_max", idigester)));

                // diese zeile begrenzt pH Strafe zwischen 0 und 1
                pH_Punishment = pH_Punishment + Math.Min(pH_punish_digester, 1);
            }

            if (n_digester > 0)
            {
                pH_Punishment = pH_Punishment / n_digester;
            }

            // values between 0 and 1, can be hard constraints
            return(pH_Punishment);
        }
Beispiel #23
0
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            // TODO - was muss ich hier machen, damit sensor daten noisy aufzeichnet???
            bool noisy = false;

            // calc setpoint control error - errors of setpoint controls
            double diff_setpoints = calc_setpoint_errors(mySensors, myPlant, myFitnessParams, noisy);

            // wende tukey biweight an

            diff_setpoints = math.tukeybiweight(diff_setpoints);

            values[0] = new physValue("diff_setpoints", diff_setpoints, "-");

            return(values);
        }
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            // Grenzwerte, welche ich mal auf einer Konferenz (vermutlich VDI Tagung) aufgeschnappt habe
            //
            // TAC &lt; 50 mmol/l              gefährlich
            // 50 &lt; TAC &lt; 100 mmol/l     gering Warnung
            // 100 &lt; TAC &lt; 250 mmol/l    OK

            // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein
            double TAC_fitness = sensors.calcFitnessDigester_min_max(myPlant, mySensors, "TAC",
                                                                     "min", myFitnessParams, "_3", true);

            values[0] = new physValue("TAC_fitness", TAC_fitness, "-");

            return(values);
        }
        /// <summary>
        /// type 7
        ///
        /// called in ADMstate_stoichiometry.cs
        ///
        /// unterschied zu typ 7 ist, dass Q hier nur aus Substraten besteht und nicht
        /// aus zusätzlichem sludge, da sludge nicht aufgewärmt werden muss,
        /// nein ist jetzt ein Typ 7 sensor, sludge wird ignoriert
        /// </summary>
        /// <param name="x">not used</param>
        /// <param name="myPlant"></param>
        /// <param name="mySubstrates"></param>
        /// <param name="mySensors"></param>
        /// <param name="Q">zufuhr aller substrate in fermenter (nicht in Anlage),
        /// da heatConsumption_sensor am fermenter angebracht ist</param>
        /// <param name="par">not used</param>
        /// <returns>measured values</returns>
        override protected physValue[] doMeasurement(double[] x, biogas.plant myPlant,
                                                     biogas.substrates mySubstrates,
                                                     biogas.sensors mySensors,
                                                     double[] Q, params double[] par)
        {
            // wegen 4 siehe oben
            // 1. Ptherm kWh/d for heating substrates
            // 2. Ptherm kWh/d loss due to radiation
            // 3. Ptherm kWh/d produced by microbiology
            // 4. Ptherm kWh/d produced by stirrer dissipation
            physValue[] values = new physValue[dimension];

            // TODO - rufe hier calcThermalEnergyBalance auf von digester_energy.cs
            // benötigt als weiteren Parameter allerdings mySensors

            digester myDigester = myPlant.getDigesterByID(id_suffix);

            // Q ist nur das was in fermenter rein geht
            // bspw. gäbe es bei einem nicht gefütterten aber beheiztem fermenter
            // keine substrate welche aufgeheizt werden müssten
            //myDigester.heatInputSubstrates(Q, mySubstrates, out values[0]);

            myDigester.calcThermalEnergyBalance(Q, mySubstrates, myPlant.Tout, mySensors,
                                                out values[0], out values[1], out values[2], out values[3]);

            //

            values[0].Label = "thermal energy to heat substrates";
            values[1].Label = "thermal energy loss due to radiation";
            values[2].Label = "thermal energy produced by microorganisms";
            values[3].Label = "thermal energy dissipated by stirrer";

            //physValue P_radiation_loss_kW;
            // because in heating first power in kW is calculated, it does not
            // make the code faster to not have power in kW as parameter
            //myPlant.compensateHeatLossDueToRadiation(id_suffix,
            //        out P_radiation_loss_kW, out values[1]);

            //

            return(values);
        }
Beispiel #26
0
        /// <summary>
        /// ...
        ///
        /// type 8
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="myFitnessParams"></param>
        /// <param name="mySensors"></param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par)
        {
            physValue[] values = new physValue[1];

            //

            // <param name="biogasExcess_fitness">lost money due to biogas excess [1000 €/d]</param>
            // <param name="biogasExcess">in excess produced biogas [m^3/d]</param>
            // <param name="lossBiogasExcess">lost money due to biogas excess [€/d]</param>

            physValue[] biogas_v = mySensors.getCurrentMeasurementVector("total_biogas_");

            //
            // excess biogas in [m^3/d]
            double biogasExcess;// = biogas_v[biogas_v.Length - 1].Value;

            //
            // Calculation of costs of substrate inflow
            // € / d
            double substrate_costs;

            mySensors.getCurrentMeasurementD("substrate_cost", out substrate_costs);


            // loss of excess methane prod. in €/d
            // if there is a loss, then positive value
            // if there is a gain, then negative value, should not be the case
            double lossBiogasExcess = calcLossDueToBiogasExcess(biogas_v, substrate_costs, myPlant,
                                                                myFitnessParams, out biogasExcess);

            // tausend € / d
            double biogasExcess_fitness = lossBiogasExcess / 1000;

            //

            values[0] = new physValue("biogasExcess_fitness", biogasExcess_fitness, "-");

            return(values);
        }
Beispiel #27
0
        /// <summary>
        /// Measure Norg content inside a digester
        ///
        /// type 5
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="x">ADM state vector</param>
        /// <param name="param">not used - but OK</param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant, double[] x,
                                                     string param, params double[] par)
        {
            physValue[] values = new physValue[1];

            //
            // -1 sowieso, -2 wegen _2 bzw. _3
            string digester_id = id.Substring(("Norg_").Length, id.Length - 2 - ("Norg_").Length);

            // kmol N/m^3
            double Norg = ADMstate.calcNorg(x, digester_id, myPlant);

            //
            // erstmal N nennen, damit convertUnit funktioniert
            values[0]        = new physValue("N", Norg, "mol/l", "organic nitrogen");
            values[0]        = values[0].convertUnit("g/l");
            values[0].Symbol = "Norg";

            //

            return(values);
        }
        /// <summary>
        /// Returns measurement at a given time t of a sensor. Dependent on the operator
        /// the sum or mean is returned for all chps or all digesters.
        /// </summary>
        /// <param name="myPlant">plant object</param>
        /// <param name="sensor_id">id of sensor</param>
        /// <param name="s_operator">operator: mean or sum for chps or digesters</param>
        /// <param name="t">simulation time in days</param>
        /// <param name="index">index inside sensor: 0, 1, 2, ...</param>
        /// <param name="noisy">if true, then noisy measurement values are returned.
        /// they are only noisy if the parameter apply_real_sensor was true before and during
        /// the simulation</param>
        /// <returns></returns>
        /// <exception cref="exception">Unknown sensor id</exception>
        /// <exception cref="exception">Invalid index</exception>
        public double getMeasurementDAt(plant myPlant, string sensor_id,
                                        string s_operator, double t, int index, bool noisy)
        {
            List <double> values = new List <double>();

            if (s_operator.StartsWith("chps"))
            {
                foreach (chp myCHP in myPlant.myCHPs)
                {
                    values.Add(getMeasurementDAt(sensor_id + "_" + myCHP.id, "", t, index, noisy));
                }
            }
            else if (s_operator.StartsWith("digesters"))
            {
                foreach (digester myDigester in myPlant.myDigesters)
                {
                    values.Add(getMeasurementDAt(sensor_id + "_" + myDigester.id, "", t, index, noisy));
                }
            }
            else
            {
                throw new exception(String.Format("Invalid operator: {0}. Must start with chps or digesters!",
                                                  s_operator), "sensors_getMeasurements_special.cs");
            }

            if (s_operator.EndsWith("sum"))
            {
                return(math.sum(values));
            }
            else if (s_operator.EndsWith("mean"))
            {
                return(math.mean(values));
            }
            else
            {
                throw new exception(String.Format("Invalid operator: {0}. Must end with sum or mean!",
                                                  s_operator), "sensors_getMeasurements_special.cs");
            }
        }
Beispiel #29
0
        /// <summary>
        /// Measure TKN content inside a digester
        ///
        /// type 5
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="x">ADM state vector</param>
        /// <param name="param">not used - but OK</param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant, double[] x,
                                                     string param, params double[] par)
        {
            physValue[] values = new physValue[1];

            //
            // -2 wegen _2 bzw. _3
            string digester_id = id.Substring(("TKN_").Length, id.Length - 2 - ("TKN_").Length);

            // kmol N/m^3
            double TKN = ADMstate.calcTKN(x, digester_id, myPlant);

            //
            // erstmal N nennen, damit convertUnit funktioniert
            values[0]        = new physValue("N", TKN, "mol/l", "total Kjehldahl nitrogen");
            values[0]        = values[0].convertUnit("g/l");
            values[0].Symbol = "TKN";

            //

            return(values);
        }
        /// <summary>
        /// Calculates Ash content in digester
        /// </summary>
        /// <param name="x"></param>
        /// <param name="digester_id"></param>
        /// <param name="mySensors"></param>
        /// <param name="mySubstrates"></param>
        /// <param name="Q"></param>
        /// <param name="myPlant"></param>
        /// <returns></returns>
        public static physValue calcAsh(double[] x, string digester_id, biogas.sensors mySensors, substrates mySubstrates, double[] Q,
                                        plant myPlant)
        {
            physValue ash_digester, ash_substrate;

            try
            {
                ash_digester = mySensors.getCurrentMeasurement("Ash_" + digester_id + "_3");
            }
            catch (exception e)
            {
                Console.WriteLine(e.Message);
                ash_digester = new physValue("ash_digester", 11, "% TS");
            }

            try
            {
                mySubstrates.get_weighted_mean_of(Q, "Ash", out ash_substrate);
            }
            catch (exception e)
            {
                ash_substrate = new physValue("ash_substrate", 0, "% FM");

                return(ash_digester);
            }

            double volume_substrate = math.sum(Q);              // m^3/d

            double volume_dig = myPlant.get_param_of_d("Vliq"); // m^3

            // TODO - achtung mit einheiten, mix von % TS und % FM
            ash_digester = ash_digester + volume_substrate / volume_dig * ash_substrate;

            ash_digester        = ash_digester.convertUnit("% TS");
            ash_digester.Symbol = "Ash";

            return(ash_digester);
        }