// TODO: Performance improvement if TDNode had its TDNode successors & predecessors retrievable directly. /// <summary> /// Performs a depth-first propagation along a path for which all predecessors' computations are complete, /// adjusting early start & finish according to a PERT methodology. /// </summary> /// <param name="tdNode">The TimingData node.</param> private void PropagateForward(TimingData tdNode) { tdNode.EarlyFinish = tdNode.EarlyStart + tdNode.NominalDuration; foreach (TimingData successor in m_successors(tdNode.Subject).Select(n => TimingDataNodeFor(n))) { if (!successor.IsFixed) { successor.EarlyStart = DateTimeOperations.Max(successor.EarlyStart, tdNode.EarlyFinish); } successor.RegisterPredecessor(); if (successor.AllPredecessorsHaveWeighedIn) { PropagateForward(successor); } } }
private static void Propagate() { while (_changedMilestones.Count > 0) { Milestone ms = (Milestone)_changedMilestones.Dequeue(); if (_debug) { _Debug.WriteLine("\tPerforming propagation of change to " + ms.Name); } #region Create a Hashtable of Lists - key is target Milestone, list contains relationships to that ms. Hashtable htol = new Hashtable(); foreach (MilestoneRelationship mr in ms.Relationships) { if (!mr.Enabled) { continue; // Only enabled relationships can effect change. } if (mr.Dependent.Equals(ms)) { continue; // Only relationships where we are the independent can effect change. } //if ( m_debug ) _Debug.WriteLine("\tConsidering " + mr.ToString()); if (!htol.Contains(mr.Dependent)) { htol.Add(mr.Dependent, new ArrayList()); } ((ArrayList)htol[mr.Dependent]).Add(mr); // We now have outbounds, grouped by destination milestone. } #endregion //if ( m_debug ) _Debug.WriteLine("\tPerforming change assessments for relationships that depend on " + ms.Name); // For each 'other' milestone with which this milestone has a relationship, we will // handle all of the relationships that this ms has with that one, as a group. bool fullData = false; foreach (Milestone target in htol.Keys) { if (_debug) { _Debug.WriteLine("\t\tReconciling all relationships between " + ms.Name + " and " + target.Name); // E : RCV Liquid1.Xfer-In.Start and E : RCV Liquid1.Xfer-In.End } IList relationships = (ArrayList)htol[target]; // Gives us a list of parallel relationships to the same downstream. // if ( ms.Name.Equals("B : RCV Liquid1.Xfer-In.Start") && target.Name.Equals("B : RCV Liquid1.Temp-Set.End") ) { // fullData = true; // } if (fullData) { foreach (MilestoneRelationship mr2 in relationships) { _Debug.WriteLine(mr2.ToString()); } } DateTime minDateTime = DateTime.MinValue; DateTime maxDateTime = DateTime.MaxValue; foreach (MilestoneRelationship mr2 in relationships) { /*foreach ( MilestoneRelationship recip in mr2.Reciprocals) { * recip.PushEnabled(false); * m_pushedDisablings.Push(recip); * }*/ if (fullData) { if (_debug) { _Debug.WriteLine("\t\tAdjusting window to satisfy " + mr2); } } DateTime thisMinDt, thisMaxDt; mr2.Reaction(ms.DateTime, out thisMinDt, out thisMaxDt); // Get the relationship's acceptable window. minDateTime = DateTimeOperations.Max(minDateTime, thisMinDt); // Narrow the range from below. maxDateTime = DateTimeOperations.Min(maxDateTime, thisMaxDt); // Narrow the range from above. if (fullData) { if (_debug) { _Debug.WriteLine("\t\t\tThe window is now from " + minDateTime + " to " + maxDateTime + "."); } } } //if ( m_debug ) _Debug.WriteLine("\t\tThe final window is from " + minDateTime + " to " + maxDateTime + "."); if (minDateTime <= maxDateTime) { DateTime newDateTime = GetClosestDateTime(minDateTime, maxDateTime, target.DateTime); if (!target.DateTime.Equals(newDateTime)) { if (_debug) { _Debug.WriteLine("\t\t\tWe will move " + target.Name + " from " + target.DateTime + " to " + newDateTime); } if (!_changedMilestones.Contains(target)) { _changedMilestones.Enqueue(target); } if (!_oldValues.Contains(target)) { _oldValues.Add(target, target.m_dateTime); } if (fullData) { if (_debug) { _Debug.WriteLine("\t\t\tThere are now " + _changedMilestones.Count + " milestones with changes to process."); } } target.m_dateTime = newDateTime; } else { if (_debug) { _Debug.WriteLine("\t\t\t" + target.Name + " stays put."); } } // } else { // if ( m_debug ) _Debug.WriteLine("\t\t\tThis is an unachievable window."); // throw new ApplicationException("Can't find a new datetime value for " + target.ToString()); } fullData = false; } } }