예제 #1
0
        /// <summary>
        /// Calculate dissipated power of stirrers inside digester, dissipated to digester
        /// in kWh/d
        /// </summary>
        /// <param name="mySensors"></param>
        /// <returns>dissipated power of stirrers inside digester in kWh/d</returns>
        /// <exception cref="exception">calculation of stirrer power failed</exception>
        public physValue calcStirrerDissipation(sensors mySensors)
        {
            double Tdigester = T.convertUnit("°C").Value;
            double TSdigester;

            // get TS measurement inside this digester
            mySensors.getCurrentMeasurementD("TS_" + id + "_3", out TSdigester);

            // calc dissipated power of all mixers in this digester, measure in kWh/d
            double Pdiss = mixers.calcPdissipation(Tdigester, TSdigester);

            return(new physValue("Pdiss_mix", Pdiss, "kWh/d"));
        }
예제 #2
0
        /// <summary>
        /// Calculate electrical power of stirrers inside digester
        /// </summary>
        /// <param name="mySensors"></param>
        /// <returns>electrical power of stirrers inside digester in kWh/d</returns>
        /// <exception cref="exception">calculation of stirrer power failed</exception>
        public physValue calcStirrerPower(sensors mySensors)
        {
            double Tdigester = T.convertUnit("°C").Value;
            double TSdigester;

            // get TS measurement inside this digester
            mySensors.getCurrentMeasurementD("TS_" + id + "_3", out TSdigester);

            // calc electrical power of all mixers in this digester, measure in kWh/d
            double Pel = mixers.calcPelectrical(Tdigester, TSdigester);

            return(new physValue("Pel_mix", Pel, "kWh/d"));
        }
예제 #3
0
        // -------------------------------------------------------------------------------------
        //                            !!! 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);
        }
예제 #4
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);
        }
예제 #5
0
        /// <summary>
        /// Returns the ADM params vector, depending on the current substrate feed.
        /// The current substrate feed is taken out of the current substrate feed
        /// measurement in mySensors
        ///
        /// Attention!!! Changes the values of the ADM params!!!
        ///
        /// the following params depend on the substrate feed:
        /// - XC fractions (fCH_XC, fLI_XC, ...]
        /// - disintegration constant: kdis
        /// - hydrolysis constant: khyd_ch, khyd_pr, khyd_li
        /// </summary>
        /// <param name="t">current simulation time measured in days</param>
        /// <param name="mySensors"></param>
        /// <param name="mySubstrates"></param>
        /// <param name="substrate_network_digester"></param>
        /// <param name="digesterID">digester id</param>
        /// <returns></returns>
        public double[] getParams(double t, sensors mySensors, substrates mySubstrates,
                                  double[] substrate_network_digester, String digesterID /*,
                                                                                          * double deltatime*/)
        {
            double[] Q;

            mySensors.getMeasurementsAt("Q", "Q", t, mySubstrates, out Q);

            // multiply the two vectors with the vector product
            // two column vector are multiplied therefore a column vector is returned
            Q = math.times(substrate_network_digester, Q);

            double QdigesterIn;

            mySensors.getCurrentMeasurementD(String.Format("Q_{0}_2", digesterID), out QdigesterIn);

            double[] ADMparams = getParams(t, Q, QdigesterIn, mySubstrates); // , mySensors.isEmpty()

            // measurement of ADM1 params to sensors
            mySensors.measure(t, "ADMparams_" + digesterID, ADMparams);

            return(ADMparams);
        }
예제 #6
0
        /// <summary>
        /// Measure TS content inside a digester
        ///
        /// type 7
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="myPlant"></param>
        /// <param name="mySubstrates">list of substrates</param>
        /// <param name="mySensors"></param>
        /// <param name="Q">
        /// substrate feed and recirculation sludge going into the digester
        /// first values are Q for substrates, then pumped sludge going into digester
        /// dimension: always number of substrates + number of digesters
        /// </param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(double[] x, biogas.plant myPlant,
                                                     biogas.substrates mySubstrates, biogas.sensors mySensors,
                                                     double[] Q, params double[] par)
        {
            // TODO
            // so erweitern, dass auch TS in Fermenter Input gemessen werden kann
            // evtl. substrate_sensor nutzen, kann aber auch direkt über mySubstrates gemessen werden

            physValue[] values = new physValue[1];

            // number of substrates
            int n_substrate = mySubstrates.getNumSubstrates();

            if (Q.Length < n_substrate)
            {
                throw new exception(String.Format(
                                        "Q.Length < n_substrate: {0} < {1}!", Q.Length, n_substrate));
            }

            double[] Qsubstrates = new double[n_substrate];

            // volumeflow for substrates
            for (int isubstrate = 0; isubstrate < n_substrate; isubstrate++)
            {
                Qsubstrates[isubstrate] = Q[isubstrate];
            }

            //

            biogas.substrates substrates_or_sludge;

            //
            List <double> Q_s_or_s = new List <double>();

            // if no substrate is going into the fermenter we have to take the
            // TS from the digesters sludge going into this digester to calculate a
            // sludge. If there is substrate going into the digester we ignore
            // recirculation sludge, because the COD content inside the digester is
            // already influenced by the recirculated COD, so a high recirculation leads
            // to a reduction of the COD content inside the digester and then also to a
            // TS content reduction.
            if (math.sum(Qsubstrates) == 0)
            {
                substrates_or_sludge = new biogas.substrates();

                int ifermenter = 0;

                //

                for (int iflux = n_substrate; iflux < Q.Length; iflux++)
                {
                    string digester_id = myPlant.getDigesterID(ifermenter + 1);

                    double TS_digester = 0;

                    try
                    {
                        mySensors.getCurrentMeasurementD("TS_" + digester_id + "_3", out TS_digester);

                        if (TS_digester < double.Epsilon) // vermutlich wurde noch nicht gemessen?
                        {
                            TS_digester = 11;
                        }
                    }
                    catch // TODO: wann passiert das??, sollte eigentlich nicht passieren
                    {
                        TS_digester = 11;
                    }

                    substrates_or_sludge.addSubstrate(
                        new biogas.sludge(mySubstrates, math.ones(n_substrate), TS_digester));

                    ifermenter = ifermenter + 1;
                }

                //

                for (int isubstrate = n_substrate; isubstrate < Q.Length; isubstrate++)
                {
                    Q_s_or_s.Add(Q[isubstrate]);
                }
            }
            else
            {
                substrates_or_sludge = mySubstrates;

                for (int isubstrate = 0; isubstrate < Qsubstrates.Length; isubstrate++)
                {
                    Q_s_or_s.Add(Qsubstrates[isubstrate]);
                }
            }



            if (id.EndsWith("3")) // out sensor
            {
                // calc TS inside digester due to the substrates or the sludge if digester is not fed
                values[0] = biogas.digester.calcTS(x, substrates_or_sludge, Q_s_or_s.ToArray());
            }
            else if (id.EndsWith("2")) // in sensor
            {
                // TODO
                // ändern, da momentan entweder substrate oder sludge genommen wird und nicht beides
                // selbe Problem wie bei OLR_sensor denke ich
                substrates_or_sludge.get_weighted_mean_of(Q_s_or_s.ToArray(), "TS", out values[0]);

                values[0].Symbol = "TS";
            }
            else
            {
                throw new exception(String.Format("id of TS sensor not valid: {0}", id));
            }

            //

            values[0].Label = "total solids";

            return(values);
        }
예제 #7
0
        /// <summary>
        /// Measure OLR of a digester
        ///
        /// type 7
        ///
        /// TODO: größtenteils identisch mit TS_sensor, man könnte was zusammen legen
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="myPlant"></param>
        /// <param name="mySubstrates">list of substrates</param>
        /// <param name="mySensors"></param>
        /// <param name="Q">
        /// substrate feed and recirculation sludge going into fermenter in m³/d
        /// first values are Q for substrates, then pumped sludge going into digester
        /// dimension: always number of substrates + number of digesters
        /// </param>
        /// <param name="par"></param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(double[] x, biogas.plant myPlant,
                                                     biogas.substrates mySubstrates, biogas.sensors mySensors,
                                                     double[] Q, params double[] par)
        {
            physValue[] values = new physValue[1];

            // TODO: so abändern, dass die aufgerufene methode calcOLR immer
            // feed und sludge übergeben werden. nicht oder

            // number of substrates
            int n_substrate = mySubstrates.getNumSubstrates();

            double Qsum = math.sum(Q);

            if (Q.Length < n_substrate)
            {
                throw new exception(String.Format(
                                        "Q.Length < n_substrate: {0} < {1}!", Q.Length, n_substrate));
            }

            double[] Qsubstrates = new double[n_substrate];

            // volumeflow for substrates
            for (int isubstrate = 0; isubstrate < n_substrate; isubstrate++)
            {
                Qsubstrates[isubstrate] = Q[isubstrate];
            }

            //

            biogas.substrates substrates_or_sludge;

            //
            List <double> Q_s_or_s = new List <double>();

            // if no substrate is going into the fermenter we have to take the
            // TS from the digesters sludge going into this digester to calculate a
            // sludge. If there is substrate going into the digester we ignore
            // recirculation sludge, because the COD content inside the digester is
            // already influenced by the recirculated COD, so a high recirculation leads
            // to a reduction of the COD content inside the digester and then also to a
            // TS content reduction.
            if (math.sum(Qsubstrates) == 0)
            {
                substrates_or_sludge = new biogas.substrates();

                int ifermenter = 0;

                //

                for (int iflux = n_substrate; iflux < Q.Length; iflux++)
                {
                    string digester_id = myPlant.getDigesterID(ifermenter + 1);

                    double TS_digester, VS_digester = 0;

                    try
                    {
                        mySensors.getCurrentMeasurementD("TS_" + digester_id + "_3", out TS_digester);
                        mySensors.getCurrentMeasurementD("VS_" + digester_id + "_3", out VS_digester);

                        // TODO - warum 4, wenn Fermenter abgestürzt ist, dann ist TS < 2
                        // was zu doofen Fehlermeldungen führt mit calcNfE und boundNDF, wenn man
                        // VS unten in biogas.sludge setzt. deshalb hier abfrage
                        if (TS_digester < 4 /*double.Epsilon*/)
                        {
                            TS_digester = 11;
                        }
                        // TODO - herausfinden warum 15
                        if (VS_digester < 20 /*double.Epsilon*/)
                        {
                            VS_digester = 85; // 85 % TS
                        }
                    }
                    catch
                    {
                        TS_digester = 11;
                        VS_digester = 85;
                    }

                    try
                    {
                        substrates_or_sludge.addSubstrate(
                            new biogas.sludge(mySubstrates, math.ones(n_substrate),
                                              TS_digester, VS_digester));
                    }
                    catch (exception e)
                    {
                        LogError.Log_Err(String.Format("OLR_sensor.doMeasurement, VS: {0}, TS: {1}",
                                                       VS_digester, TS_digester), e);
                        throw (e);
                    }

                    ifermenter = ifermenter + 1;
                }

                //

                for (int isubstrate = n_substrate; isubstrate < Q.Length; isubstrate++)
                {
                    Q_s_or_s.Add(Q[isubstrate]);
                }
            }
            else
            {
                substrates_or_sludge = mySubstrates;

                for (int isubstrate = 0; isubstrate < Qsubstrates.Length; isubstrate++)
                {
                    Q_s_or_s.Add(Qsubstrates[isubstrate]);
                }
            }

            //

            digester myDigester = myPlant.getDigesterByID(id_suffix);

            try
            {
                values[0] = myDigester.calcOLR(x, substrates_or_sludge, Q_s_or_s.ToArray(), Qsum);
            }
            catch (exception e)
            {
                LogError.Log_Err("OLR_sensor.doMeasurement2", e);
                throw (e);
            }

            //

            return(values);
        }