/// <summary>Complete mix tank model.</summary> /// <param name="tank">Tank to be updated.</param> /// <param name="dt">Step duration in seconds.</param> private void Tankmix1(QualityTank tank, long dt) { // React contents of tank double c = Tankreact(tank.Concentration, tank.Volume, ((Tank)tank.Node).Kb, dt); // Determine tank & volumes double vold = tank.Volume; tank.Volume = tank.Volume + tank.Demand * dt; double vin = tank.VolumeIn; double cin; if (vin > 0.0) { cin = tank.MassIn / vin; } else { cin = 0.0; } // Compute inflow concen. double cmax = Math.Max(c, cin); // Mix inflow with tank contents if (vin > 0.0) { c = (c * vold + cin * vin) / (vold + vin); } c = Math.Min(c, cmax); c = Math.Max(c, 0.0); tank.Concentration = c; tank.Quality = tank.Concentration; }
/// <summary>2-compartment tank model (seg1 = mixing zone,seg2 = ambient zone).</summary> /// <param name="tank">Tank to be updated.</param> /// <param name="dt">Step duration in seconds.</param> private void Tankmix2(QualityTank tank, long dt) { if (tank.Segments.Count == 0) { return; } QualitySegment seg1 = tank.Segments.Last.Value; QualitySegment seg2 = tank.Segments.First.Value; seg1.C = Tankreact(seg1.C, seg1.V, ((Tank)tank.Node).Kb, dt); seg2.C = Tankreact(seg2.C, seg2.V, ((Tank)tank.Node).Kb, dt); // Find inflows & outflows double vnet = tank.Demand * dt; double vin = tank.VolumeIn; double cin = vin > 0.0 ? tank.MassIn / vin : 0.0; double v1Max = ((Tank)tank.Node).V1Max; // Tank is filling double vt = 0.0; if (vnet > 0.0) { vt = Math.Max(0.0, seg1.V + vnet - v1Max); if (vin > 0.0) { seg1.C = (seg1.C * seg1.V + cin * vin) / (seg1.V + vin); } if (vt > 0.0) { seg2.C = (seg2.C * seg2.V + seg1.C * vt) / (seg2.V + vt); } } // Tank is emptying if (vnet < 0.0) { if (seg2.V > 0.0) { vt = Math.Min(seg2.V, -vnet); } if (vin + vt > 0.0) { seg1.C = (seg1.C * seg1.V + cin * vin + seg2.C * vt) / (seg1.V + vin + vt); } } // Update segment volumes if (vt > 0.0) { seg1.V = v1Max; if (vnet > 0.0) { seg2.V += vt; } else { seg2.V = Math.Max(0.0, seg2.V - vt); } } else { seg1.V += vnet; seg1.V = Math.Min(seg1.V, v1Max); seg1.V = Math.Max(0.0, seg1.V); seg2.V = 0.0; } tank.Volume = Math.Max(tank.Volume + vnet, 0.0); // Use quality of mixed compartment (seg1) to // represent quality of tank since this is where // outflow begins to flow from tank.Concentration = seg1.C; tank.Quality = tank.Concentration; }
/// <summary>Last In-First Out (LIFO) tank model.</summary> /// <param name="tank">Tank to be updated.</param> /// <param name="dt">Step duration in seconds.</param> private void Tankmix4(QualityTank tank, long dt) { if (tank.Segments.Count == 0) { return; } // React contents of each compartment if (_reactflag) { for (LinkedListNode <QualitySegment> el = tank.Segments.Last; el != null; el = el.Previous) { QualitySegment seg = el.Value; seg.C = Tankreact(seg.C, seg.V, ((Tank)tank.Node).Kb, dt); } } // Find inflows & outflows double vnet = tank.Demand * dt; double vin = tank.VolumeIn; double cin; if (vin > 0.0) { cin = tank.MassIn / tank.VolumeIn; } else { cin = 0.0; } tank.Volume = Math.Max(0.0, tank.Volume + vnet); tank.Concentration = tank.Segments.Last.Value.C; // If tank filling, then create new last seg if (vnet > 0.0) { if (tank.Segments.Count > 0) { QualitySegment seg = tank.Segments.Last.Value; // Quality is the same, so just add flow volume to last seg if (Math.Abs(seg.C - cin) < _net.Ctol) { seg.V += vnet; } // Otherwise add a new last seg to tank // Which points to old last seg else { tank.Segments.AddLast(new QualitySegment(vin, cin)); } } else { tank.Segments.AddLast(new QualitySegment(vin, cin)); } tank.Concentration = tank.Segments.Last.Value.C; } // If net emptying then remove last segments until vnet consumed else if (vnet < 0.0) { double vsum = 0.0; double csum = 0.0; vnet = -vnet; while (vnet > 0.0) { if (tank.Segments.Count == 0) { break; } QualitySegment seg = tank.Segments.Last.Value; if (seg == null) { break; } double vseg = seg.V; vseg = Math.Min(vseg, vnet); if (tank.Segments.Count == 1) { vseg = vnet; } vsum += vseg; csum += seg.C * vseg; vnet -= vseg; if (vnet >= 0.0 && vseg >= seg.V) { tank.Segments.RemoveLast(); //(2.00.12 - LR) } else { // Remaining volume in segment seg.V -= vseg; } } // Reported tank quality is mixture of flow released and any inflow tank.Concentration = (csum + tank.MassIn) / (vsum + vin); } tank.Quality = tank.Concentration; }
/// <summary>First-In-First-Out (FIFO) tank model.</summary> /// <param name="tank">Tank to be updated.</param> /// <param name="dt">Step duration in seconds.</param> /// private void Tankmix3(QualityTank tank, long dt) { if (tank.Segments.Count == 0) { return; } // React contents of each compartment if (_reactflag) { foreach (QualitySegment seg in tank.Segments) { seg.C = Tankreact(seg.C, seg.V, ((Tank)tank.Node).Kb, dt); } } // Find inflows & outflows double vnet = tank.Demand * dt; double vin = tank.VolumeIn; double vout = vin - vnet; double cin; if (vin > 0.0) { cin = tank.MassIn / tank.VolumeIn; } else { cin = 0.0; } tank.Volume = Math.Max(tank.Volume + vnet, 0.0); // Withdraw flow from first segment double vsum = 0.0; double csum = 0.0; while (vout > 0.0) { if (tank.Segments.Count == 0) { break; } QualitySegment seg = tank.Segments.First.Value; double vseg = seg.V; // Flow volume from leading seg vseg = Math.Min(vseg, vout); if (tank.Segments.Count == 1) { vseg = vout; } vsum += vseg; csum += seg.C * vseg; vout -= vseg; // Remaining flow volume if (vout >= 0.0 && vseg >= seg.V) { tank.Segments.RemoveFirst(); } else { // Remaining volume in segment seg.V -= vseg; } } // Use quality withdrawn from 1st segment // to represent overall quality of tank if (vsum > 0.0) { tank.Concentration = csum / vsum; } else { tank.Concentration = tank.Segments.First.Value.C; } tank.Quality = tank.Concentration; // Add new last segment for new flow entering tank if (vin > 0.0) { if (tank.Segments.Count > 0) { QualitySegment seg = tank.Segments.Last.Value; // Quality is the same, so just add flow volume to last seg if (Math.Abs(seg.C - cin) < _net.Ctol) { seg.V += vin; } else // Otherwise add a new seg to tank { tank.Segments.AddLast(new QualitySegment(vin, cin)); } } else // If no segs left then add a new one. { tank.Segments.AddLast(new QualitySegment(vin, cin)); } } }