/// <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> /// calc methane yield [m^3 CH4 / kgVS] /// /// http://www.bioconverter.com/technology/primer.htm#Methane%20Yield%20%28m3%20CH4%20/%20kg%20VS%20added%29 /// /// if methane yield is high, everything is ok, if it is too low /// maybe decrease substrate feed, digester could be overburdened /// /// </summary> /// <param name="x">ADM state vector</param> /// <param name="pQ">Q : m^3/d : total feed into the digester</param> /// <param name="pVS">VS : % TS : volatile solids content of feed</param> /// <param name="pTS">TS : % FM : total solids content of feed</param> /// <param name="prho">rho : kg/m^3 : density of feed</param> /// <returns></returns> public physValue calcCH4Yield(double[] x, physValue pQ, physValue pVS, physValue pTS, physValue prho) { physValue Qgas_h2, Qgas_ch4; ADMstate.calcBiogasOfADMstate(x, Vliq, T, out Qgas_h2, out Qgas_ch4); physValue Q = pQ.convertUnit("m^3/d"); physValue VS = pVS.convertUnit("% TS"); physValue TS = pTS.convertUnit("% FM"); physValue rho = prho.convertUnit("kg/m^3"); VS = substrate.convertFrom_TS_To_FM(VS, TS); // VS [% FM] * [100 % / % FM] * m^3/d * kg/m^3 = VS kg/d physValue VS_kg = VS.convertUnit("100 %") * Q * rho; if (VS_kg.Value == 0) { return(new physValue(0, "m^3/kg")); } // m^3/d / kgVS/d= m^3/kgVS // Einheit ist: m^3/kg physValue CH4Yield = Qgas_ch4 / VS_kg; return(CH4Yield); }
// ------------------------------------------------------------------------------------- // !!! PROTECTED METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// measures Q of ADM stream in m^3/d /// /// type 0 /// </summary> /// <param name="x">ADM state vector (dimension: dim_stream)</param> /// <param name="par">not used</param> /// <returns>flow in m^3/d</returns> override protected physValue[] doMeasurement(double[] x, params double[] par) { physValue[] values = new physValue[1]; values[0] = ADMstate.calcQOfADMstate(x); return(values); }
// ------------------------------------------------------------------------------------- // !!! PROTECTED METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Measures volatile fatty acid concentration in digester /// /// type 0 /// </summary> /// <param name="x">ADM state vector</param> /// <param name="par">not used</param> /// <returns>volatile fatty acid concentration in gHAceq/l</returns> override protected physValue[] doMeasurement(double[] x, params double[] par) { physValue[] values = new physValue[1]; values[0] = ADMstate.calcVFAOfADMstate(x, "gHAceq/l"); values[0].Symbol = "Svfa"; return(values); }
/// <summary> /// Calculates given symbol out of state vector x. The symbol in the state vector /// must be measured in the unit of the ADM state vector (as defined in variable /// unitsADMstate) and is returned in ToUnit /// /// </summary> /// <param name="x"></param> /// <param name="symbol"></param> /// <param name="ToUnit"></param> /// <returns></returns> public static physValueBounded calcFromADMstate(double[] x, string symbol, string ToUnit) { // nicht so gut den defaultUnit von physValue zu holen, da ein anderes AD // Model andere Einheiten haben könnte //string FromUnit= physValue.getDefaultUnit(symbol); // so ist es OK! string FromUnit = ADMstate.getUnitOfADMstatevariable(symbol); return(calcFromADMstate(x, symbol, FromUnit, ToUnit)); }
// ------------------------------------------------------------------------------------- // !!! PROTECTED METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Calculates hydraulic retention time of the digester measured in days /// /// type 0 aktuell type 1 /// </summary> /// <param name="x">ADM state vector</param> /// <param name="par">volume of the digester in m^3</param> /// <returns>measured HRT in days</returns> override protected physValue[] doMeasurement(double[] x, params double[] par) { physValue[] values = new physValue[dimension]; if (par.Length != 1) { throw new exception(String.Format( "Length of params is != 1: {0}!", par.Length)); } double Vliq = par[0]; values[0] = ADMstate.calcHRTOfADMstate(x, Vliq); return(values); }
// ------------------------------------------------------------------------------------- // !!! PROTECTED METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Calculates the heat energy produced by bacteria inside the digester measured in kWh/d /// /// nicht type 0 und auch nicht type 1, da x ist vektor aus ADM1 beschreibend die reaktions /// raten p oder rho genannt /// </summary> /// <param name="p">ADM reaction rates vector</param> /// <param name="par">volume of the digester in m^3</param> /// <returns>measured energy in kWh/d</returns> override protected physValue[] doMeasurement(double[] p, params double[] par) { physValue[] values = new physValue[dimension]; if (par.Length != 1) { throw new exception(String.Format( "Length of params is != 1: {0}!", par.Length)); } double Vliq = par[0]; values[0] = new physValue("Pprodmic", ADMstate.calcProdEnergyOfMicroOrganisms(p, Vliq), "kWh/d", "thermal energy prod. of microorganisms"); return(values); }
/// <summary> /// calc methane production rate [m^3/m^3/day] /// /// http://www.bioconverter.com/technology/primer.htm#Methane%20Production%20Rate /// /// http://www.bioconverter.com/technology/primer.htm#Methane%20Production%20Rate%20%28m3/m3-day%29 /// /// </summary> /// <param name="x">ADM state vector</param> /// <returns></returns> public physValue calcCH4ProductionRate(double[] x) { physValue Qgas_h2, Qgas_ch4; ADMstate.calcBiogasOfADMstate(x, Vliq, T, out Qgas_h2, out Qgas_ch4); Qgas_ch4 = Qgas_ch4.convertUnit("m^3/d"); _Vliq = Vliq.convertUnit("m^3"); if (Vliq.Value == 0) { return(new physValue(0, "1/d")); } // m^3/d/m^3= 1/d physValue CH4ProductionRate = Qgas_ch4 / Vliq; return(CH4ProductionRate); }
// ------------------------------------------------------------------------------------- // !!! PROTECTED METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Measure ADM stream vector in default units of the model /// /// is a type 0, because u is the stream vector /// </summary> /// <param name="u">33 or 34 dim stream vector</param> /// <param name="par">not used</param> /// <returns>measured ADM stream vector</returns> /// <exception cref="exception">u.Length < ADMstate.dim_stream - 1</exception> override protected physValue[] doMeasurement(double[] u, params double[] par) { physValue[] values = new physValue[dimension]; if (u.Length < ADMstate.dim_stream - 1) { throw new exception(String.Format( "u has not the correct dimension! is: {0}, must be at least: {1}!", u.Length, ADMstate.dim_stream - 1)); } for (int idim = 0; idim < dimension; idim++) { values[idim] = new physValue(ADMstate.symADMstate[idim], u[idim], ADMstate.getUnitOfADMstatevariable(idim + 1)); } return(values); }
// ------------------------------------------------------------------------------------- // !!! PROTECTED METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Measure ADM state vector in default units of the model /// /// not type 0, because x is not the stream vector, but the 37 dim state vector /// </summary> /// <param name="x">37 dim state vector</param> /// <param name="par">not used</param> /// <returns>measured ADM state vector</returns> /// <exception cref="exception">x.Length != ADMstate.dim_state</exception> protected override physValue[] doMeasurement(double[] x, params double[] par) { physValue[] values= new physValue[dimension]; if (x.Length != ADMstate.dim_state) { throw new exception(String.Format( "x has not the correct dimension! is: {0}, must be: {1}!", x.Length, ADMstate.dim_state)); } for (int idim= 0; idim < dimension; idim++) { values[idim]= new physValue(ADMstate.symADMstate[idim], x[idim], ADMstate.getUnitOfADMstatevariable(idim + 1)); } return values; }
/// <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> /// 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> /// Measure NH3 content inside a digester /// 1st measurement is Snh3 in g/l /// 2nd : Snh3 + NH3 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]; // ammonia values[0] = ADMstate.calcFromADMstate(x, "Snh3", "g/l"); // // -2 wegen _2 bzw. _3 string digester_id = id.Substring(("Snh3_").Length, id.Length - 2 - ("Snh3_").Length); // kmol N/m^3 double NH3 = ADMstate.calcNH3(x, digester_id, myPlant); // // erstmal Snh3 nennen, damit convertUnit funktioniert // ammonia nitrogen, umrechnungsfaktor 14 values[1] = new physValue("N", NH3, "mol/l", "total ammonia nitrogen"); values[1] = values[1].convertUnit("g/l"); values[1].Symbol = "NH3"; return(values); }