/// <summary> /// Substracts and returns the substracted water. /// volume should be positive. Otherwise a water object with zero volume will be returned public virtual IWaterPacket Substract(double Volume) { if (Log) { LogString.AppendLine("Substracted mass: " + Volume); } //Remember the volume double v1 = this.Volume; Volume = Math.Min(this.Volume, Math.Max(0, Volume)); IWaterPacket W = DeepClone(Volume); this.Volume -= Volume; double factor = this.Volume / v1; //Now adjust the concentrations foreach (Chemical c in _chemicals.Keys.ToArray()) { _chemicals[c] *= factor; } return(W); }
public void SortingOfIncomingWater() { Stream_Accessor s = new Stream_Accessor("s", 100, 1, 1); WaterPacket wp1 = new WaterPacket(1, 50); WaterPacket wp2 = new WaterPacket(2, 100); s.AddWaterPacket(new DateTime(2000, 1, 1), new DateTime(2000, 1, 11), wp1); s.AddWaterPacket(new DateTime(2000, 1, 6), new DateTime(2000, 1, 11), wp2); s.PrePareIncomingWater(); Assert.AreEqual(2, s._incomingWater.Count); IWaterPacket iwp = s._incomingWater.Dequeue(); Assert.AreEqual(25, iwp.Volume); Assert.AreEqual(1, iwp.Composition[1]); iwp = s._incomingWater.Dequeue(); Assert.AreEqual(125, iwp.Volume); Assert.AreEqual(25.0 / 125.0, iwp.Composition[1]); Assert.AreEqual(100.0 / 125.0, iwp.Composition[2]); WaterPacket wp3 = new WaterPacket(3, 100); WaterPacket wp4 = new WaterPacket(4, 200); WaterPacket wp5 = new WaterPacket(5, 300); s.AddWaterPacket(new DateTime(2000, 1, 1), new DateTime(2000, 1, 3), wp3); s.AddWaterPacket(new DateTime(2000, 1, 2), new DateTime(2000, 1, 3), wp4); s.AddWaterPacket(new DateTime(2001, 1, 1, 12, 0, 0), new DateTime(2001, 1, 5), wp5); s.PrePareIncomingWater(); }
/// <summary> /// Adds the WaterPackets and returns them as the most advanced type. /// </summary> /// <param name="Waters"></param> /// <returns></returns> public static IWaterPacket Mix(IEnumerable <IWaterPacket> Waters) { if (Waters.Count() == 0) { return(null); } else if (Waters.Count() == 1) { return(Waters.First()); } else { IWaterPacket[] warr = Waters.ToArray(); IWaterPacket Water1 = warr[0]; for (int i = 1; i < warr.Count(); i++) { if (warr[i].GetType().IsSubclassOf(Water1.GetType())) { warr[i].Add(Water1); Water1 = warr[i]; } else { Water1.Add(warr[i]); } } return(Water1); } }
/// <summary> /// Adds a water packet to the stream. /// This method is to be used by upstream connections. /// The time period is used sort the incoming packets when the stream has multiple upstream connections /// </summary> /// <param name="Start">Start of inflow period</param> /// <param name="End">End of inflow period</param> /// <param name="Water"></param> public void AddWaterPacket(DateTime Start, DateTime End, IWaterPacket Water) { Water.Tag(ID); if (Water.Volume != 0) { Incoming.Add(new Treple <DateTime, DateTime, IWaterPacket>(Start, End, Water)); } }
public void GetSourceWaterTest() { SinkSourceBoundary target = new SinkSourceBoundary(200); target.ContactGeometry = XYPolygon.GetSquare(1); IWaterPacket actual = target.GetSourceWater(DateTime.Now, new TimeSpan(1, 0, 0)); Assert.AreEqual(200 * 3600, actual.Volume); }
/// <summary> /// Distributes water on the downstream connections. /// Should be called chronologically! /// </summary> /// <param name="TimeStep"></param> /// <param name="water"></param> private void SendWaterDownstream(IWaterPacket water) { if (water.Volume != 0) { DateTime EndOfFlow = StartofFlowperiod.AddSeconds(water.Volume / WaterToRoute * CurrentTimeStep.TotalSeconds); SendWaterDownstream(water, StartofFlowperiod, EndOfFlow); //Call the logger Output.Log(water, StartofFlowperiod, EndOfFlow); StartofFlowperiod = EndOfFlow; } }
private void WaterEquals(IWaterPacket wp, IWaterPacket wp2) { Assert.AreEqual(wp.Volume, wp2.Volume); Assert.AreEqual(wp.WaterAge, wp2.WaterAge); Assert.AreEqual(wp.RelativeTimeTag, wp2.RelativeTimeTag); if (wp.Composition.Count > 0) { Assert.AreEqual(wp.Composition.Values.First(), wp2.Composition.Values.First()); Assert.AreEqual(wp.Composition.Keys.First(), wp2.Composition.Keys.First()); } }
/// <summary> /// Adds W to this water. This has no effect on W. However, it would be non-physical to use W subsequently /// </summary> /// <param name="W"></param> public virtual void Add(IWaterPacket W) { if (Log) { LogString.AppendLine("Added mass: " + W.Volume); } if (Volume == 0) { WaterAge = W.WaterAge; } Temperature = Temperature * Volume + W.Volume * W.Temperature; double Multiplier = Volume; Volume += W.Volume; Temperature /= Volume; Multiplier /= Volume; foreach (var key in Composition.Keys.ToArray()) { _composition[key] *= Multiplier; } foreach (var KVP in W.Composition) { if (_composition.ContainsKey(KVP.Key)) { _composition[KVP.Key] += KVP.Value * (1 - Multiplier); } else { _composition.Add(KVP.Key, KVP.Value * (1 - Multiplier)); } } foreach (KeyValuePair <Chemical, double> KVP in ((WaterPacket)W)._chemicals) { if (_chemicals.ContainsKey(KVP.Key)) { _chemicals[KVP.Key] += KVP.Value; } else { _chemicals.Add(KVP.Key, KVP.Value); } } }
protected virtual void DeepClone(IWaterPacket CloneToThis, double Volume) { WaterWithChemicals WCC = (WaterWithChemicals)CloneToThis; double factor = Volume / this.Volume; //DeepClone the properties of the base clas base.DeepClone(WCC); //Now clone the chemicals foreach (KeyValuePair <Chemical, double> KVP in _chemicals) { WCC.AddChemical(KVP.Key, KVP.Value * factor); } }
/// <summary> /// Sets a state and fills the network with water /// </summary> /// <param name="stateID"></param> /// <param name="CurrentTime"></param> public void SetState(string stateID, DateTime CurrentTime, IWaterPacket WaterTypeToFillWith) { this.CurrentTime = CurrentTime; StateIds.Add(stateID); if (StateIds.Count == 1) { SimulationStartTime = CurrentTime; } foreach (IWaterBody IW in _waterBodies) { IW.SetState(stateID, CurrentTime, WaterTypeToFillWith.DeepClone(IW.Volume)); } }
public void Mix(double Volume, IWaterPacket WP) { if (_anythingToMix) { double d = Volume / _totalVolume; if (_inflow != null) { WP.Add(_inflow.Substract(d * _inflowVolume)); } WP.Evaporate(d * _evapoVolume); WP.Substract(d * _sinkVolume); } }
/// <summary> /// Sets the state. Also stores the state. If the state name already exists it will be overwritten /// </summary> /// <param name="StateName"></param> /// <param name="Time"></param> /// <param name="WaterInStream"></param> public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream) { var state = new Tuple <DateTime, IWaterPacket>(Time, WaterInStream.DeepClone()); if (_states.ContainsKey(StateName)) { _states[StateName] = state; } else { _states.Add(StateName, state); } RestoreState(StateName); }
/// <summary> /// Distributes water on downstream connections. /// </summary> /// <param name="Water"></param> /// <param name="Start"></param> /// <param name="End"></param> protected void SendWaterDownstream(IWaterPacket Water, DateTime Start, DateTime End) { //Send water to downstream recipients if (_downStreamConnections.Count == 1) { _downStreamConnections[0].AddWaterPacket(Start, End, Water); } else if (_downStreamConnections.Count > 1) { double fraction = Water.Volume / _downStreamConnections.Count; foreach (IWaterBody IW in _downStreamConnections) { IW.AddWaterPacket(CurrentTime, End, Water.Substract(fraction)); } } }
public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water) { CurrentFlowRate = -Water.Volume / TimeStep.TotalSeconds; if (FlowType == GWType.Darcy) { WaterFlow.AddSiValue(Start, Start.Add(TimeStep), CurrentFlowRate); } if (ReceivedWater == null) { ReceivedWater = Water; } else { ReceivedWater.Add(Water); } }
/// <summary> /// Substracts a volume of water /// </summary> /// <param name="Volume"></param> /// <returns></returns> public override IWaterPacket Substract(double Volume) { //Remember the volume double v1 = this.Volume; //Use the base method. This method will call inherited DeepClone method IWaterPacket w = base.Substract(Volume); double factor = this.Volume / v1; //Now adjust the concentrations foreach (Chemical c in _chemicals.Keys.ToArray()) { _chemicals[c] *= factor; } return(w); }
/// <summary> /// Sets the state. Also stores the state. I /// </summary> /// <param name="StateName"></param> /// <param name="Time"></param> /// <param name="WaterInStream"></param> public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream) { Queue <IWaterPacket> _water = new Queue <IWaterPacket>(); _water.Enqueue(WaterInStream.DeepClone()); Tuple <DateTime, Queue <IWaterPacket> > state = new Tuple <DateTime, Queue <IWaterPacket> >(Time, _water); if (_states.ContainsKey(StateName)) { _states[StateName] = state; } else { _states.Add(StateName, state); } RestoreState(StateName); }
/// <summary> /// Logs chemical /// </summary> /// <param name="Water"></param> /// <param name="Start"></param> /// <param name="End"></param> public void Log(IWaterPacket Water, DateTime Start, DateTime End) { WaterPacket wc = Water as WaterPacket; //Log chemicals if the water is based on WaterPacket if (wc != null) { if (LogAllChemicals) { foreach (var c in wc.Chemicals.Keys) { TimestampSeries ts; if (!ChemicalsToLog.TryGetValue(c, out ts)) { ts = CreateChemicalSeries(c); } ts.AddSiValue(End, wc.GetConcentration(c)); } } else { foreach (KeyValuePair <Chemical, TimestampSeries> ct in ChemicalsToLog) { ct.Value.AddSiValue(End, ((WaterPacket)Water).GetConcentration(ct.Key)); } } } //Log the water composition if (LogComposition) { foreach (var id in Water.Composition) { TimestampSeries ts; if (!CompositionLog.TryGetValue(id.Key, out ts)) { ts = CreateCompositionTimeSeries(id.Key); } ts.AddValue(End, id.Value); } } }
/// <summary> /// Adds water /// </summary> /// <param name="W"></param> public override void Add(IWaterPacket W) { base.Add(W); //If we have chemicals add them if (W.GetType().Equals(this.GetType())) { foreach (KeyValuePair<Chemical, double> KVP in ((WaterWithChemicals)W)._chemicals) { if (_chemicals.ContainsKey(KVP.Key)) _chemicals[KVP.Key] += KVP.Value; else _chemicals.Add(KVP.Key, KVP.Value); } } else { //Keep track of how much non-chemical water is added. _volumeOfNonChemicalWater += W.Volume; } }
public void SubtractTest() { int ID1 = 1; WaterPacket w = new WaterPacket(500); w.IDForComposition = ID1; IWaterPacket w2 = w.Substract(230); Assert.AreEqual(270, w.Volume); Assert.AreEqual(230, w2.Volume); Assert.AreEqual(1, w.Composition[ID1]); Assert.AreEqual(1, w.Composition[ID1]); IWaterPacket w3 = w.Substract(1000); Assert.AreEqual(0, w.Volume); Assert.AreEqual(270, w3.Volume); Assert.AreEqual(1, w3.Composition[ID1]); }
protected virtual void DeepClone(IWaterPacket CloneToThis, double Volume) { WaterPacket W = (WaterPacket)CloneToThis; double factor = Volume / this.Volume; //Copy the properties W.RelativeTimeTag = this.RelativeTimeTag; W.WaterAge = WaterAge; W.Temperature = Temperature; W.LogString = new StringBuilder(LogString.ToString()); foreach (KeyValuePair <int, double> KVP in _composition) { W._composition.Add(KVP.Key, KVP.Value); } //Now clone the chemicals foreach (KeyValuePair <Chemical, double> KVP in _chemicals) { W.AddChemical(KVP.Key, KVP.Value * factor); } }
internal Mixer(IWaterPacket Inflow, double EvapoVolume, double SinkVolume) { _evapoVolume = EvapoVolume; _sinkVolume = SinkVolume; _inflow = Inflow; double totalVolume; if (Inflow != null) { totalVolume = Inflow.Volume - EvapoVolume - SinkVolume; _inflowVolume = Inflow.Volume; } else { totalVolume = -EvapoVolume - SinkVolume; } if (totalVolume != 0) { _anythingToMix = true; } _totalVolume = totalVolume; }
/// <summary> /// Adds water /// </summary> /// <param name="W"></param> public override void Add(IWaterPacket W) { base.Add(W); //If we have chemicals add them if (W.GetType().Equals(this.GetType())) { foreach (KeyValuePair <Chemical, double> KVP in ((WaterWithChemicals)W)._chemicals) { if (_chemicals.ContainsKey(KVP.Key)) { _chemicals[KVP.Key] += KVP.Value; } else { _chemicals.Add(KVP.Key, KVP.Value); } } } else { //Keep track of how much non-chemical water is added. _volumeOfNonChemicalWater += W.Volume; } }
public void ReceiveWater(DateTime Start, DateTime End, IWaterPacket Water) { throw new NotImplementedException(); }
/// <summary> /// Adds a water packet to the lake. /// This method is to be used by upstream connections. /// /// </summary> /// <param name="Start">Start of inflow period</param> /// <param name="End">End of inflow period</param> /// <param name="Water"></param> public void AddWaterPacket(DateTime Start, DateTime End, IWaterPacket Water) { Water.Tag(ID); _waterReceivedSinceLastUpdate += Water.Volume; CurrentStoredWater.Add(Water); }
/// <summary> /// Adds W to this water over the length of the period. /// Use this method if the addition is not instantaneous. /// </summary> /// <param name="W"></param> /// <param name="LengthOfPeriod"></param> public virtual void Add(IWaterPacket W, TimeSpan LengthOfPeriod) { Add(W); }
internal Mixer(IWaterPacket Inflow, double EvapoVolume, double SinkVolume) { _evapoVolume = EvapoVolume; _sinkVolume = SinkVolume; _inflow = Inflow; double totalVolume; if (Inflow != null) { totalVolume = Inflow.Volume - EvapoVolume - SinkVolume; _inflowVolume = Inflow.Volume; } else totalVolume = -EvapoVolume - SinkVolume; if (totalVolume != 0) { _anythingToMix = true; } _totalVolume = totalVolume; }
/// <summary> /// Adds a water packet to the stream. /// This method is to be used by upstream connections. /// The time period is used sort the incoming packets when the stream has multiple upstream connections /// </summary> /// <param name="Start">Start of inflow period</param> /// <param name="End">End of inflow period</param> /// <param name="Water"></param> public void AddWaterPacket(DateTime Start, DateTime End, IWaterPacket Water) { Water.Tag(ID); if (Water.Volume !=0) Incoming.Add(new Treple<DateTime, DateTime, IWaterPacket>(Start, End, Water)); }
public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water) {}
/// <summary> /// Sets a state and fills the network with water /// </summary> /// <param name="stateID"></param> /// <param name="CurrentTime"></param> public void SetState(string stateID, DateTime CurrentTime, IWaterPacket WaterTypeToFillWith) { this.CurrentTime = CurrentTime; StateIds.Add(stateID); if (StateIds.Count == 1) SimulationStartTime = CurrentTime; foreach (IWaterBody IW in _waterBodies) IW.SetState(stateID, CurrentTime, WaterTypeToFillWith.DeepClone(IW.Volume)); }
public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream) { throw new NotImplementedException(); }
/// <summary> /// This is the timestepping procedure /// </summary> /// <param name="TimeStep"></param> public void Update(DateTime NewTime) { CurrentTimeStep = NewTime.Subtract(CurrentTime); #region Sum of Sinks and sources //Sum the sources var GWFlow = GroundwaterBoundaries.Where(var => var.IsSource(CurrentTime)).Select(var => var.GetSourceWater(CurrentTime, CurrentTimeStep)); var SourceFlow = Sources.Select(var => var.GetSourceWater(CurrentTime, CurrentTimeStep)); IWaterPacket InFlow = WaterMixer.Mix(GWFlow.Concat(SourceFlow)); double InflowVolume = 0; if (InFlow != null) { InflowVolume = InFlow.Volume; } //Sum the Evaporation boundaries double EvapoVolume = _evapoBoundaries.Sum(var => var.GetSinkVolume(CurrentTime, CurrentTimeStep)); //Sum the sinks double SinkVolume = Sinks.Sum(var => var.GetSinkVolume(CurrentTime, CurrentTimeStep)); //Add the sinking groundwater boundaries SinkVolume += GroundwaterBoundaries.Where(var => !var.IsSource(CurrentTime)).Sum(var => var.GetSinkVolume(CurrentTime, CurrentTimeStep)); double sumSinkSources = InflowVolume - EvapoVolume - SinkVolume; //If we have no water from upstream but Inflow, remove water from inflow to fill stream if (sumSinkSources / Volume > 5) { AddWaterPacket(CurrentTime, NewTime, InFlow.Substract(sumSinkSources - Volume * 5)); InflowVolume = InFlow.Volume; sumSinkSources = InflowVolume - EvapoVolume - SinkVolume; } //Sort the incoming water an put in to queue PrePareIncomingWater(); //Calculate the surplus WaterToRoute = _waterInStream.Sum(var => var.Volume) + InflowVolume - EvapoVolume - SinkVolume - Volume + _incomingWater.Sum(var => var.Volume); //If the loss is bigger than available water, reduce Evaporation and Sinks if (WaterToRoute + Volume < 0) { double reductionfactor = 1 + (WaterToRoute + Volume) / (EvapoVolume + SinkVolume); EvapoVolume *= reductionfactor; SinkVolume *= reductionfactor; WaterToRoute = 0; } //Convert to rates double qu = sumSinkSources / CurrentTimeStep.TotalSeconds / Volume; double qop = _incomingWater.Sum(var => var.Volume) / CurrentTimeStep.TotalSeconds; double qout = qu * Volume + qop; //Create a mixer class Mixer M = new Mixer(InFlow, EvapoVolume, SinkVolume); #endregion #region Stored water //Send stored water out if (WaterToRoute > 0) { double OutflowTime = 0; //The volume that needs to flow out to meet the watertotroute double VToSend = WaterToRoute; if (qu != 0) { VToSend = qout / qu * (1 - 1 / (Math.Exp(qu * CurrentTimeStep.TotalSeconds))); } //There is water in the stream that should be routed while (VToSend > 0 & _waterInStream.Count > 0) { IWaterPacket IW; //Mixing during flow towards end of stream double dv = _waterInStream.Peek().Volume *(Math.Exp(qu * OutflowTime) - 1); //Check if the entire water packet should flow out or it should be split if (_waterInStream.Peek().Volume + dv < VToSend) { IW = _waterInStream.Dequeue(); } else { IW = _waterInStream.Peek().Substract(VToSend); } //Update how mush water is yet to be routed VToSend -= IW.Volume; //Now do the mix M.Mix(dv, IW); //Calculate outflow time double dt; if (qu == 0) { dt = IW.Volume / qop; } else { dt = Math.Log(qout / (qout - qu * IW.Volume)) / qu; } //Mixing during outflow M.Mix(qout * dt - IW.Volume, IW); IW.MoveInTime(TimeSpan.FromSeconds(OutflowTime + dt / 2), IW.Volume / Depth); SendWaterDownstream(IW); OutflowTime += dt; } } //Now move the remaining packets to their final destination and time foreach (IWaterPacket IWP in _waterInStream) { if (qu != 0) { M.Mix(IWP.Volume * (Math.Exp(qu * CurrentTimeStep.TotalSeconds) - 1), IWP); } IWP.MoveInTime(CurrentTimeStep, IWP.Volume / Depth); } #endregion #region Water packets traveling right through double inflowtime = 0; //No water in stream and incoming water. Just pass through if (_waterInStream.Count == 0 & _incomingWater.Count > 0) { //Calculate how much incoming water is required to fill stream volume; double VToStore = Volume; if (qu != 0) { VToStore = qop / qu * Math.Log(Volume * qu / qop + 1); } //Now send water through double incomingVolume = _incomingWater.Sum(var => var.Volume); //Send packets through until the remaining will just fill the stream while (incomingVolume > VToStore + 1e-12 & _incomingWater.Count != 0) { IWaterPacket WP; if (incomingVolume - _incomingWater.Peek().Volume > VToStore) { WP = _incomingWater.Dequeue(); } else { WP = _incomingWater.Peek().Substract(incomingVolume - VToStore); } incomingVolume -= WP.Volume; //Keep track of inflow time. inflowtime += WP.Volume / qop; if (qu != 0) { double dvr = WP.Volume * qu * Volume / qop; M.Mix(dvr, WP); } //Calculate the time a water package uses to travel through the stream TimeSpan CurrentTravelTime; if (qu != 0) { CurrentTravelTime = TimeSpan.FromSeconds(1 / qu * Math.Log(Volume * qu / qop + 1)); } else { CurrentTravelTime = TimeSpan.FromSeconds(Volume / qout); } //Moves right through WP.MoveInTime(CurrentTravelTime, WP.Volume / Depth); SendWaterDownstream(WP); } } #endregion #region Fill the stream //The remaining incoming water is moved forward and stays in the stream. while (_incomingWater.Count > 0) { IWaterPacket WP = _incomingWater.Dequeue(); double dt = WP.Volume / qop; inflowtime += dt; double dt2 = CurrentTimeStep.TotalSeconds - inflowtime; //How much of the timestep is left when this packet has moved in. if (qu != 0) { //Volume change during inflow double Vnew = qop * (Math.Exp(qu * dt) - 1) / qu; //Volume change while in stream Vnew *= Math.Exp(qu * dt2); M.Mix(Vnew - WP.Volume, WP); } //The time is half the inflowtime + the time in stream WP.MoveInTime(TimeSpan.FromSeconds(dt2 + dt / 2), WP.Volume / Depth); _waterInStream.Enqueue(WP); } #endregion Output.Outflow.AddSiValue(CurrentTime, NewTime, WaterToRoute / CurrentTimeStep.TotalSeconds); CurrentTime = NewTime; StartofFlowperiod = CurrentTime; }
/// <summary> /// Mixes the incoming water and sorts it in queue according to time /// </summary> private void PrePareIncomingWater() { double ControlVolume = Incoming.Sum(var => var.Third.Volume); Queue <DateTime> Starts = new Queue <DateTime>(); Queue <DateTime> Ends = new Queue <DateTime>(); List <Tuple <DateTime, DateTime> > TimeSpans = new List <Tuple <DateTime, DateTime> >(); foreach (DateTime D in Incoming.Select(var => var.First).OrderBy(var => var).Distinct()) { Starts.Enqueue(D); } foreach (DateTime D in Incoming.Select(var => var.Second).OrderBy(var => var).Distinct()) { Ends.Enqueue(D); } while (Starts.Count > 0 & Ends.Count > 0) { DateTime d = Starts.Dequeue(); if (Starts.Count > 0) { if (Starts.Peek() < Ends.Peek()) { TimeSpans.Add(new Tuple <DateTime, DateTime>(d, Starts.Peek())); } else { DateTime e = Ends.Dequeue(); TimeSpans.Add(new Tuple <DateTime, DateTime>(d, e)); Starts.Enqueue(e); var p = Starts.OrderBy(var => var).ToList(); Starts.Clear(); foreach (DateTime D in p) { Starts.Enqueue(D); } } } else { DateTime e = Ends.Dequeue(); TimeSpans.Add(new Tuple <DateTime, DateTime>(d, e)); Starts.Enqueue(e); } } //Store the volumes before substracting anything Dictionary <IWaterPacket, double> _vols = new Dictionary <IWaterPacket, double>(); foreach (var i in Incoming) { _vols.Add(i.Third, i.Third.Volume); } foreach (var v in TimeSpans) { var l = Incoming.Where(var => var.First <v.Item2& var.Second> v.Item1).ToList(); if (l.Count > 0) { double d = v.Item2.Subtract(v.Item1).TotalSeconds; IWaterPacket wp = l[0].Third.Substract(d / (l[0].Second.Subtract(l[0].First).TotalSeconds) * _vols[l[0].Third]); for (int i = 1; i < l.Count; i++) { wp.Add(l[i].Third.Substract(d / (l[i].Second.Subtract(l[i].First).TotalSeconds) * _vols[l[i].Third])); } _incomingWater.Enqueue(wp); } } //Check the mass balance if (_incomingWater.Sum(var => var.Volume) - ControlVolume > 1E-4) { throw new Exception("Error in algorithm to mix incoming water"); } Incoming.Clear(); }
public WaterViewModel(IWaterPacket Water) { _water = Water; BuildChemicalView(); }
protected virtual void DeepClone(IWaterPacket CloneToThis, double Volume) { WaterWithChemicals WCC = (WaterWithChemicals)CloneToThis; double factor = Volume / this.Volume; //DeepClone the properties of the base clas base.DeepClone(WCC); //Now clone the chemicals foreach (KeyValuePair<Chemical, double> KVP in _chemicals) WCC.AddChemical(KVP.Key, KVP.Value * factor); }
/// <summary> /// Sets the state. Also stores the state. I /// </summary> /// <param name="StateName"></param> /// <param name="Time"></param> /// <param name="WaterInStream"></param> public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream) { Queue<IWaterPacket> _water = new Queue<IWaterPacket>(); _water.Enqueue(WaterInStream.DeepClone()); Tuple<DateTime, Queue<IWaterPacket>> state = new Tuple<DateTime, Queue<IWaterPacket>>(Time, _water); if (_states.ContainsKey(StateName)) _states[StateName] = state; else _states.Add(StateName, state); RestoreState(StateName); }
public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water) { CurrentFlowRate = -Water.Volume / TimeStep.TotalSeconds; if (FlowType== GWType.Darcy) WaterFlow.AddSiValue(Start, Start.Add(TimeStep), CurrentFlowRate); if (ReceivedWater == null) ReceivedWater = Water; else ReceivedWater.Add(Water); }
public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water) { WaterSample.Add(Water); Output.Log(WaterSample, Start, Start.Add(TimeStep)); }
public void Mix(double Volume, IWaterPacket WP) { if (_anythingToMix) { double d = Volume / _totalVolume; if (_inflow != null) WP.Add(_inflow.Substract(d*_inflowVolume)); WP.Evaporate(d*_evapoVolume ); WP.Substract(d*_sinkVolume); } }
public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water) { }
/// <summary> /// Distributes water on downstream connections. /// </summary> /// <param name="Water"></param> /// <param name="Start"></param> /// <param name="End"></param> protected void SendWaterDownstream(IWaterPacket Water, DateTime Start, DateTime End) { //Send water to downstream recipients if (_downStreamConnections.Count == 1) _downStreamConnections[0].AddWaterPacket(Start, End, Water); else if (_downStreamConnections.Count > 1) { double fraction = Water.Volume/_downStreamConnections.Count; foreach (IWaterBody IW in _downStreamConnections) IW.AddWaterPacket(CurrentTime, End, Water.Substract(fraction)); } }
/// <summary> /// Adds W to this water. This has no effect on W. However, it would be non-physical to use W subsequently /// </summary> /// <param name="W"></param> public virtual void Add(IWaterPacket W) { if (Log) LogString.AppendLine("Added mass: " + W.Volume); if (Volume == 0) { WaterAge = W.WaterAge; } Temperature = Temperature * Volume + W.Volume * W.Temperature; double Multiplier = Volume; Volume += W.Volume; Temperature /= Volume; Multiplier /= Volume; foreach (var key in Composition.Keys.ToArray()) { _composition[key] *= Multiplier; } foreach (var KVP in W.Composition) { if (_composition.ContainsKey(KVP.Key)) _composition[KVP.Key] += KVP.Value*(1-Multiplier); else _composition.Add(KVP.Key, KVP.Value * (1 - Multiplier)); } foreach (KeyValuePair<Chemical, double> KVP in ((WaterPacket)W)._chemicals) { if (_chemicals.ContainsKey(KVP.Key)) _chemicals[KVP.Key] += KVP.Value; else _chemicals.Add(KVP.Key, KVP.Value); } }
/// <summary> /// Logs chemical /// </summary> /// <param name="Water"></param> /// <param name="Start"></param> /// <param name="End"></param> public void Log(IWaterPacket Water, DateTime Start, DateTime End) { WaterPacket wc = Water as WaterPacket; //Log chemicals if the water is based on WaterPacket if (wc!=null) { if (LogAllChemicals) foreach (var c in wc.Chemicals.Keys) { TimestampSeries ts; if (!ChemicalsToLog.TryGetValue(c, out ts)) { ts = CreateChemicalSeries(c); } ts.AddSiValue(End, wc.GetConcentration(c)); } else { foreach (KeyValuePair<Chemical, TimestampSeries> ct in ChemicalsToLog) { ct.Value.AddSiValue(End, ((WaterPacket)Water).GetConcentration(ct.Key)); } } } //Log the water composition if (LogComposition) { foreach (var id in Water.Composition) { TimestampSeries ts; if (!CompositionLog.TryGetValue(id.Key, out ts)) ts = CreateCompositionTimeSeries(id.Key); ts.AddValue(End, id.Value); } } }
protected virtual void DeepClone(IWaterPacket CloneToThis, double Volume) { WaterPacket W = (WaterPacket)CloneToThis; double factor = Volume / this.Volume; //Copy the properties W.RelativeTimeTag = this.RelativeTimeTag; W.WaterAge = WaterAge; W.Temperature = Temperature; W.LogString = new StringBuilder(LogString.ToString()); foreach (KeyValuePair<int, double> KVP in _composition) W._composition.Add(KVP.Key, KVP.Value); //Now clone the chemicals foreach (KeyValuePair<Chemical, double> KVP in _chemicals) W.AddChemical(KVP.Key, KVP.Value * factor); }
/// <summary> /// Sets the state. Also stores the state. If the state name already exists it will be overwritten /// </summary> /// <param name="StateName"></param> /// <param name="Time"></param> /// <param name="WaterInStream"></param> public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream) { var state = new Tuple<DateTime,IWaterPacket>(Time,WaterInStream.DeepClone()); if (_states.ContainsKey(StateName)) _states[StateName] = state; else _states.Add(StateName, state); RestoreState(StateName); }