コード例 #1
0
        /// <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);
        }
コード例 #2
0
ファイル: StreamTest.cs プロジェクト: msruzy/hydronumerics
        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();
        }
コード例 #3
0
ファイル: WaterMixer.cs プロジェクト: msruzy/hydronumerics
        /// <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);
            }
        }
コード例 #4
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
 /// <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));
     }
 }
コード例 #5
0
        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);
        }
コード例 #6
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
 /// <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;
     }
 }
コード例 #7
0
 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());
     }
 }
コード例 #8
0
        /// <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);
                }
            }
        }
コード例 #9
0
        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);
            }
        }
コード例 #10
0
ファイル: Model.cs プロジェクト: msruzy/hydronumerics
        /// <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));
            }
        }
コード例 #11
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
            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);
                }
            }
コード例 #12
0
        /// <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);
        }
コード例 #13
0
 /// <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));
         }
     }
 }
コード例 #14
0
        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);
            }
        }
コード例 #15
0
        /// <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);
        }
コード例 #16
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
        /// <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);
        }
コード例 #17
0
ファイル: WaterOutput.cs プロジェクト: msruzy/hydronumerics
        /// <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);
                }
            }
        }
コード例 #18
0
 /// <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;
   }
 }
コード例 #19
0
        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]);
        }
コード例 #20
0
        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);
            }
        }
コード例 #21
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
            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;
            }
コード例 #22
0
 /// <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;
     }
 }
コード例 #23
0
 public void ReceiveWater(DateTime Start, DateTime End, IWaterPacket Water)
 {
   throw new NotImplementedException();
 }
コード例 #24
0
 /// <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);
 }
コード例 #25
0
 /// <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);
 }
コード例 #26
0
 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());
   }
 }
コード例 #27
0
ファイル: Stream.cs プロジェクト: XiBeichuan/hydronumerics
      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;
      }
コード例 #28
0
ファイル: Stream.cs プロジェクト: XiBeichuan/hydronumerics
 /// <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));
 }
コード例 #29
0
 public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water)
 {}
コード例 #30
0
ファイル: Model.cs プロジェクト: XiBeichuan/hydronumerics
    /// <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));
    }
コード例 #31
0
ファイル: MixingStream.cs プロジェクト: msruzy/hydronumerics
 public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream)
 {
     throw new NotImplementedException();
 }
コード例 #32
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
        /// <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;
        }
コード例 #33
0
ファイル: Stream.cs プロジェクト: msruzy/hydronumerics
        /// <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();
        }
コード例 #34
0
 public WaterViewModel(IWaterPacket Water)
 {
     _water = Water;
     BuildChemicalView();
 }
コード例 #35
0
 public void SetState(string StateName, DateTime Time, IWaterPacket WaterInStream)
 {
   throw new NotImplementedException();
 }
コード例 #36
0
    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);

    }
コード例 #37
0
ファイル: Stream.cs プロジェクト: XiBeichuan/hydronumerics
    /// <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);
    }
コード例 #38
0
    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);
    }
コード例 #39
0
ファイル: Stream.cs プロジェクト: XiBeichuan/hydronumerics
 /// <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;
   }
 }
コード例 #40
0
 public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water)
 {
   WaterSample.Add(Water);
   Output.Log(WaterSample, Start, Start.Add(TimeStep));
 }
コード例 #41
0
ファイル: Stream.cs プロジェクト: XiBeichuan/hydronumerics
      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);
        }
      }
コード例 #42
0
 public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water)
 {
     WaterSample.Add(Water);
     Output.Log(WaterSample, Start, Start.Add(TimeStep));
 }
コード例 #43
0
 public void ReceiveSinkWater(DateTime Start, TimeSpan TimeStep, IWaterPacket Water)
 {
 }
コード例 #44
0
    /// <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));
      }

    }
コード例 #45
0
    /// <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);
      }

    }
コード例 #46
0
    /// <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);
        }
      }
    }
コード例 #47
0
    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);

    }
コード例 #48
0
 public WaterViewModel(IWaterPacket Water)
 {
   _water = Water;
   BuildChemicalView();
 }
コード例 #49
0
 /// <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);
 }
コード例 #50
0
ファイル: Lake.cs プロジェクト: XiBeichuan/hydronumerics
    /// <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);
    }
コード例 #51
0
ファイル: Lake.cs プロジェクト: XiBeichuan/hydronumerics
 /// <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);
 }
コード例 #52
0
ファイル: MixingStream.cs プロジェクト: msruzy/hydronumerics
 public void ReceiveWater(DateTime Start, DateTime End, IWaterPacket Water)
 {
     throw new NotImplementedException();
 }