How to Model Waiting Times in Microsoft Project

Mandatory waiting times between certain tasks are a common feature of many project schedules.  In construction, the typical example is concrete curing time.  That is the time interval (typically under a week) after a batch of concrete is placed but before it gains sufficient strength to remove/strip the formwork and continue working.  Similar wait times can be required in non-construction projects. Common features of such waiting times are:

  • The waiting time is not associated with productive work;
  • The waiting time is independent of any Project, Task, or Resource calendar.  That is, it takes place around the clock, independent of weekends and holidays.

Consider a 5-day curing time in a Microsoft Project (MSP) schedule using the default Standard calendar (i.e. 5dx8h Monday-Friday work week).  The curing process always occurs over a mix of working and non-working (night and weekend) time.  Since the number of workdays included in this period varies from three to five depending on the time and day of the week that the concrete placement finishes, it is not possible to specify a fixed curing duration (in Standard-calendar workdays) without introducing an unnecessary delay in the schedule.

Instead, there are four obvious modeling techniques to accurately schedule the curing and follow-on activities:

  1. Create a “cure” task with a “5-day” duration and assign a 7-day x 24-hour calendar to the task.
  2. Create a “cure” task and assign a duration of 5 “elapsed” days.
  3. Don’t create a “cure” task.  Instead model the curing time as a 5-elapsed-day lag between the “place concrete” and “strip forms” tasks.
  4. Create a “cure” task with a 5-day duration and assign a modified 7-day weekly calendar to the task.

As shown in the figures, all four techniques can be used to generate the same (early) schedule dates for the project.  Which technique to use depends on a few factors.

  •  Within MSP, a “day” is fundamentally defined according to the “hours per day” setting for the project, and any “day” entries are automatically converted to minutes using that setting.  With default settings, one “day” is 8 hours (i.e. 480 minutes).  This can lead to confusion when calendars are changed or assigned without taking the setting into account.  For example, when a 24-hour calendar is assigned to a 3-day-duration task in a project with default (i.e. 8 hours/day) settings, then the task will finish in 24 hours (i.e. 1 calendar day).   Under the same conditions, a curing time of 5 calendar days (i.e. 120 hours) would require a specified task “duration” of 120/8 = 15 days.  To minimize such confusion, it is a good practice to specify durations in hours when 24-hour calendars are applied, as shown in the figure.
  • For most purposes, assigning an “elapsed days” duration is functionally equivalent to applying a 24-hour calendar to the task and making the necessary duration adjustments.  This can reduce confusion associated with the hours per day setting.  The two techniques yield identical results in the example.
  •  Using an elapsed-lag instead of a dedicated task is functionally simple to implement, and many project schedulers routinely use this approach.  Nevertheless, lags are generally discouraged or prohibited by some scheduling specifications and recommended practices for good reasons.  Chiefly, lags can substantially affect schedule dates while remaining relatively invisible on typical schedule documents – this makes them easy to abuse for date-manipulation.  In addition, unlike tasks, lags are not easily incorporated into external algorithms for evaluation or manipulation of project schedules – e.g. for risk simulation. This can substantially degrade the value of such algorithms.
  • Total Slack calculations are substantially complicated by the impacts of multiple calendars (including the use of elapsed durations).  Since MSP relies solely on Total Slack to identify “Critical” tasks, the true Critical Path for the project can be inadequately described for any of these techniques.  For example, when the curing time finishes at the end of a workday in the middle of the work week, the “cure” task (on a 24-hour calendar) possesses 15 hours of Total Slack – MSP therefore excludes it from the Critical Path.  If instead of a 24-hour calendar, a modified (i.e. 7d x 8h, no-weekend) calendar is applied to the curing task, then the positive Total Slack is eliminated in this case, and the Critical Path is correct.  (This is shown at the top of the figure below.)  Unfortunately, the modified calendar is no better than the others if the curing time finishes on the weekend.  The 1 day of Total Slack causes the Critical Path to be truncated.  (See the lower half of the figure below.) 

Unfortunately, the only out-of-the-box method to ensure that the entire critical path is captured is to raise the Total Slack threshold from the default value (zero) to some number that is judged high enough to capture all the truly critical tasks. I have found such an approach unsatisfactory for a variety of reasons.  In any case, the true Critical Path – i.e. the driving logical path to project completion – remains obscured.

Fortunately, the Longest Path algorithm in BPC Logic Filter is indifferent to which modeling approach is used.  As shown in the figure below, the driving logical paths are correctly identified for each case.  (The number to the right of each bar is the task’s path relative float with respect to the project completion task – zero for the longest path.  BPC Logic Filter typically depicts logical driving paths with a dark red bar.)

Problems with Driving Logic in Task Inspector and Task Paths (Microsoft Project 2010-2016)

Neither the Task Inspector nor the “Task Path” bar highlighter is a reliable indicator of task driving logic in Microsoft Project in the presence of mixed-type predecessor relationships or Backward Scheduling. 

At first glance, the Task Inspector pane in Microsoft Project (MSP) seems to be a reasonable tool for revealing the logic that is largely hidden in project schedules.  After all, you just select a task, click “Inspect Task”, and MSP provides a hyperlinked list of “Predecessor Tasks” that are controlling the schedule dates of the selected task.  For simple (i.e. Finish-to-Start) relationships between tasks with no progress, this assumption seems generally correct.

Unfortunately, many times Task Inspector is just plain wrong. (The examples below are taken from a ~1000-task real-world project schedule with actual progress updates.  Task names were obfuscated for confidentiality).  Each example represents many more cases in the schedule.

1. Once an actual start is recorded, logical drivers constraining the finish are ignored.

2. In case of parallel FS and SS driving predecessors, the FS driver is ignored.

Here is the corresponding bar highlighting from Task Path’s Driving Predecessors (MSP 2016).  The noted red bar should be orange like the one below it.

3. In case of parallel FS and FF driving predecessors, the FF driver is ignored.

3. In some (but not all) cases, an FF predecessor with substantial relative float is identified as the driving predecessor, while the true FS driver is ignored.

In general, the issues are present mainly in tasks with multiple predecessors of different types.  In forward scheduled projects, they are not found in un-started tasks whose predecessors are all of type Finish-to-Start.

The “Driving Predecessors” bar highlighter of the Task Path tool in Microsoft Project Professional 2016 has the same issues as the Task Inspector results shown here.  They are both consistent with the StartDriver object for each task.  Any driving-logic tracer based on the StartDriver object – including those provided in my blog (Macro for Listing Driving Predecessors and QuickTrace Macros ) – has similar issues.

In the examples above, the task predecessors are displayed in Logic Inspector views from BPC Logic Filter (our MSP Add-in).  Predecessors are “driving” if their relative floats are zero; i.e. there is no working time between the corresponding predecessor and successor dates.  The driving predecessors identified in the examples are easily confirmed by examining the dates.  [Though illustrated mostly using Microsoft Project Professional 2010, all examples have been confirmed in Microsoft Project Professional 2016.]

Though not really highlighted here, it bears noting that MSP’s “driving logic” indicators are completely oblivious to resource-leveling decisions.  Thus, resource-driving logic is not addressed.  In contrast, BPC Logic Filter handles resource-driving logic quite well.

On Manually Scheduled Tasks [Aug’18 Edit]

If a manually scheduled task has predecessors, then MSP will identify one or more of them as the driving predecessor even when the manual scheduling has substantially delayed the task compared to the logic requirements.  This is one of the few factors differentiating a manually scheduled task from a normal (i.e. automatically scheduled) task with a mandatory constraint.  In this case, the Task Path “Driving Predecessors” bar highlighter ignores the delay and continues to trace “driving” logic through the identified start drivers.  (The Task Inspector suggests that the user either accelerate the task to remove the delay or convert the task to automatic scheduling.)  As a consequence, a schedule with manually scheduled tasks can have a driving path to project completion (according to Task Path) that is substantially different from the Critical Path that is based on Total Slack.

In Backward Scheduled Projects [Jan’19 Edit]

As pointed out in this recent article, neither the Task Inspector nor Task Path bar styles are useful in backward scheduled projects.

 

 

Inspecting Task Links with BPC Logic Filter for Microsoft Project

BPC Logic Filter – an add-in for Microsoft Project (desktop) – includes an advanced Logic Inspector feature to greatly simplify the examination and navigation of logic-driven schedule activities.

When building or managing a complex project schedule, it’s often necessary to examine the logical relationships between tasks for a variety of reasons.  Particular questions for any given task include:

  1. What other tasks must finish (or start) before this task may start (or finish)? (i.e. what are its predecessors and how are they related?)
  2. Of all the task’s predecessors, which ones are actually controlling the scheduled dates for this task? – i.e. what are its driving predecessors?
  3. For the task’s non-driving predecessors, how much may each be allowed to slip before it becomes driving (for this task)? – i.e. what is the relative float?
  4. a)What other tasks must wait for this task to finish (or start) before they can proceed? – i.e. what are its successors?  b)Which successors are driven? c)How much relative float exists?

For users of Microsoft Project (MSP), questions 1 and 4a are most easily answered using the “Predecessors and Successors” view of one of the Task Forms in the lower pane.  For simple schedules, question 2 can be answered by the “Predecessors” list of the Task Inspector pane.  For more complex schedules – and for all other questions – the user must visually cross-reference the scheduled dates of the various linked tasks from several views, estimating relative floats and identifying driving relationships.  This can be time consuming and error prone.  Beginning with the 2013 version, MSP provides “Task Path” bar styles, which visually identify driving and non-driving predecessor and successor paths (i.e. logically connected task chains) of any selected task on the bar chart.  These can be difficult to read, however, when the project logic is complex.

BPC Logic Filter has always answered these questions on the way to visualizing logic flow through a schedule, and several of the tracer analyses can be easily customized to examine only a single task and its links.  Since the tracers generally apply a custom filter to the schedule, however, the time to examine a single task could become unwieldy for a very large project.

The native MSP predecessor and successor tables provide only limited information: ID, Name, Type, and Lag – all sorted according to the order the links were initially created.  Here they are shown as part of the Task Details Form.  Further examination of any linked task can be achieved by double-clicking an entry in the Predecessor or Successor list to open the corresponding Task Information dialog.

In the LLI Edition of  BPC Logic Filter, clicking the Logic Inspector button creates two new floating windows that summarize logic-related information about the selected task as well as its predecessor and successor tasks.

Logic-related properties for the selected task – remaining duration, total slack, constraints, deadlines, scheduled dates, resources, and calendar – are included for reference above each table.  Colored highlighting and other indicators are used to emphasize properties with notable influence or relevance to the current schedule.  E.g. summary or inactive status, effective constraints, violated constraints and deadlines, actualized dates, and leveled resources.

In contrast to the native forms, Logic Inspector provides a richer relationship table, including scheduled dates (with Actual indicators), % complete, total slack, and two user-selected fields for each predecessor and successor task.  Inactive tasks (in MS Project Pro 2010+) are also highlighted gray.  The scroll and fix buttons allow dynamic resizing and other controls of window appearance.  In the LLI Edition, the predecessor and successor tasks are ordered the same as in the native lists, which generally reflect the sequence in which the relationships have been added to the model.

Most importantly, the JUMP button allows logic-based navigation forward and backward through the schedule network one task at a time.  Jumping to another task using the button automatically updates the predecessor and successor forms.  [See also Video – Inspect and Jump through Network Logic Links Using BPC Logic Filter – LLI Edition]

While the LLI (for Limited Logic Inspector) Edition of BPC Logic Filter is aimed at schedulers looking to quickly inspect and jump through relationships, the STD Edition adds robust analysis and reporting of driving logic in the schedule.  Thus, the Logic Inspector of the STD Edition also analyzes and sorts relationships on the basis of driving logic flow.

As a result, driving logic relationships are highlighted yellow and shown at the top of each list.  The first of these becomes the default target for the Jump button, allowing quick navigation through driving logic paths.  The relationships that are furthest from driving are shown at the bottom.  (As a corollary to this, Inactive tasks in MSP 2010 are relegated to the bottom of the list, while Inactive tasks in later versions may sometimes be shown as driving or near driving, depending on their dates.)  The Std Edition also allows display of MSP’s internal “driving/driven” flag for each relationship: the basis of the corresponding Task Path bar styles as well as the Predecessors portion of the Task Inspector pane.  These internal flags are sometimes incorrect, leading to a false “Driving Predecessors” Task Path.    Finally, several types of hierarchical driving logic can be added to the Logic Inspector Windows.

The Std Edition also adds the ability to Jump to and/or through tasks that are hidden in the current view and to build a custom task filter using Jump.

The Pro version adds extensive capabilities for analysis of relationship and path relative float.  Within the Logic Inspector, this means additional columns to display up to four different types of relative float for each relationship.  More importantly, late-driving and bi-directional-driving relationships are highlighted by default.  These are particularly useful for prioritizing multiple driven successors of a particular task.  In the example, this option leads to a re-sorting of the successor tasks, with one of the two driven successors from the Std Edition now being flagged and prioritized.  (This successor task, 1439, controls the late-dates of the selected task; the relationship is driving in both directions.)

Since implementation, I’ve found Logic Inspector to be an invaluable – and fast – complement to the rest of the features in BPC Logic Filter.  The two new windows are passive readers of existing project data; they are not for adding, removing, or modifying relationships.  MSP already provides a number of different approaches there.

Here’s another, older video showing an earlier, less-capable version of the feature in action.

Using Logic Inspector to examine resource drivers is addressed in another post.

AACE International Annual Meeting 2017

June of 2017 marked my first attendance at the Annual Meeting of AACE International (formerly Association for the Advancement of Cost Engineering). It was in Orlando – kind of a bummer since I had just attended the Construction CPM Conference in Orlando back in January.

Attendees were treated to two excellent keynote addresses: On Monday, Frank Abagnale gave lessons learned from his early life as a globe-trotting teen criminal followed by 42 years in the FBI.  (Leonardo DiCaprio played Abagnale in Catch Me if You Can .)  On Tuesday, Justin Newton of Walt Disney Imagineering gave an excellent presentation on the use of Cost and Schedule controls in constructing Disney’s latest attractions.

The technical sessions were first-rate, and I was continually facing the need to decide between multiple sessions of major interest that were taking place at the same time.  In sum, I wound up participating in four sessions on project risk analysis, two sessions on advanced forensic schedule analysis, and three sessions on advanced planning and scheduling topics.  I also sat in on Dr. Dan Patterson’s showcase of his latest AI-assisted, “knowledge-driven planning” effort, called Basis.   Judging from Dan’s previous successes with Pertmaster and Acumen Fuse/360/Risk, Basis is going to take project management to a whole new level. Finally, I participated in a very robust business meeting of AACE’s Planning and Scheduling Subcommittee.

Besides participating as a regular member of the association, I presented two papers in the Planning and Scheduling Technical Program.  The first is a paper I wrote to address the deduction of resource-driving links in BPC Logic Filter(PS-2413) Extracting the Resource-Constrained Critical/Longest Path from a Leveled Schedule. 

The second is one where I made only a modest contribution in review but agreed to present the paper on behalf of the primary authors who were unable to attend the meeting:  (PS-2670) Draft Recommended Practice No. 92R-17 – Analyzing Near-Critical Paths.

The resulting discussions were stimulating, but judging from the quantitative scoring (based on the speaker evaluation cards), there’s some room for improvement in communicating with this audience.  Lessons learned: 1) Despite the refereed papers, this is not an academic meeting.  Most attendees are seeking professional development (i.e. training) hours on familiar subjects.  Presenting on an esoteric subject like the first paper  – especially one without means of direct application in the prevailing software – is guaranteed to disappoint some; 2) When someone asks you to present their word-choked slide deck on a subject that you don’t completely own – especially a prescriptive procedure like the draft RP – don’t do it.  Nobody will be happy with the result.

I look forward to returning to the annual meeting in 2019.

 

 

 

Microsoft Project Schedule Health Checking and Fixing using BPC Logic Filter

Regular users of BPC Logic Filter will have noticed some modest changes with the recent release of version 1.2.  The ribbon has been slightly revised, and two new buttons have been added: “Project Logic Checker” and “Logic Quick Check”. The second is essentially an abbreviated version of the first.

The Project Logic Checker examines every task in the project and flags the following logic issues for closer review or action:

Task Definition Issues
  • Manually-scheduled tasks (By definition, these are incompatible with logic-driven scheduling.)
  • Inactive tasks (In MSP 2010, these are essentially ignored. In MSP 2013+ they are essentially included in the schedule calculations as zero-duration tasks.)
  • External tasks and external links (Scheduling of tasks with external links can change depending on whether the source schedules of the external tasks are available and open.)
  • (Hammock) tasks made with OLE links (OLE links typically impose persistent logic constraints.)
  • Summary tasks with Logic (Hierarchical logic can override precedence logic in the schedule calculations and cause confusion.)
  • Tasks with Logic on Parent Summaries  (These tasks may be controlled by non-precedence logic.)
  • Constraints and Deadlines (“Must Start/Finish On” constraints are “Hard” constraints since they can override logic.  In addition, “Start/Finish No Later Than” constraints are included as “Hard” constraints ONLY when “Tasks will always honor their constraint dates” is checked (i.e. the default value).  These are always “Hard” constraints according to 2009 DCMA 14-Point Assessment guidance.)
  • Duplicate Task Names (Duplicate task names force reliance on a task’s outline hierarchy for recognition of task scope.  Development and analysis of the project logic then becomes inefficient or impossible.)    
TASK Relationship ISSUES
  • Missing logic; that is “Open Ends,” including Dangling Starts and Finishes.  (Schedules with these conditions are unreliable.)
  • Relationship Lags and Leads (i.e. negative lags) that that are excessive with respect to the associated task durations (Ideally, logic driven schedules use explicit tasks for all time-consuming activities.  Substantial leads and lags are incompatible with schedule risk assessment and are generally considered poor practice.)
  • Relationships that are not Finish-to-Start (Some scheduling philosophies mandate only Finish-to-Start relationships.)
  • Relationships that are Start-to-Finish (These relationships are extremely rare in actual project schedules, but they are often used incorrectly.)
  • Merge Points in the schedule (i.e. tasks with a high number of immediate predecessors)
  • Reverse Logic Flow through the task’s duration; i.e. shortening the task delays the successor, and lengthening the task may accelerate the successor.  (See this entry).
  • Neutral Logic Flow through the task’s duration; i.e. shortening or lengthening the task has no impact on the successor.
  • Links to inactive tasks  (Depending on the MSP version being used, such links can alter the schedule unexpectedly.)
Task Update ISSUES
  • Invalid Dates, including incomplete work in the past and completed work in the future (with respect to the Status Date)
  • Splits
  • Out-of-sequence progress
  • Tasks that have missed their target/baseline finish date (as of the status date.)
Other TASK ISSUES
  • Overlong task durations
  • False Milestones (i.e. “Milestones” with non-zero durations)
  • Excessive or negative values for Total Slack

Users can include or exclude any desired checks from the analysis – or adjust associated thresholds – using the Checker Preferences.

The tool automatically restricts the view to show only tasks with logic issues, then it presents an output form that a) summarizes the analysis, and b) allows the user to dynamically modify the filter for pinpoint focus.

For example, here is a highly summarized, ~3300-task, proposed recovery schedule for a troubled international construction project. The Settings window confirms that the logic checker will examine most non-resource-related issues but will ignore the long-duration and high-slack checks for now.

Running the Project Logic Checker identifies and presents over 1500 tasks with logic issues (perhaps a hint to the source of the project’s “troubles.”) The user can then use the output form to reduce or expand the view.

Here’s a close-up of the output/filter form, slightly improved from the one shown in the other figures:

For example, by un-checking all but the Dangling Start box and then clicking filter, I can choose to see only the tasks with Dangling Starts, i.e. tasks with predecessors but without start-predecessors.

Then, I can check only the False Milestones box to see – and correct – the 17 tasks that are coded as milestones but possess a non-zero duration.

Of course, if I’m only interested in one issue – Logic on Summary Tasks for example, than I can begin by excluding all the other issues from the analysis. The result is a (slightly) less cluttered picture.  This one highlights the four summary tasks with logic and the forty-four subtasks that are (or may be) affected.

The dynamic re-filtering requires full data persistence (in the general settings), and the bar labeling only works if “Re-color Bars” is selected (in the bar settings).

For schedulers and schedule reviewers, the new Project Logic Checker provides an action-focused basic schedule health check functionality that can be leveraged off the various logic tracers included in the tool.  There is no fancy dashboard and no pass/fail metrics based on odd ratios.  For now I think I prefer it that way.

Macro for Tracing, Filtering, and Sorting Task Paths in Microsoft Project

Here are three macros (collectively called QuickTrace) to display the logical predecessors or successors (or both) of the selected task – filtering out all others – and sorted by logical path.  The filter can be limited to show all logic or only “driving” logic.  There is also a highlight-only option.

With the apparent demise of Mike Dahlgren’s site, masamiki.com, his “Trace” macro seems to no longer be generally available.  (It’s also a violation of his site’s terms of use to re-distribute code that was obtained there.)  My entry on Listing Driving Predecessors has been getting a lot of traffic from people who (I suspect) are trying to find a variation of Trace.  In response to a question over at MPUG today, I decided to write up something – what I call QuickTrace – to generate similar output for sharing.  It is after all less than a hundred lines of code.  [Note: The code here works for all modern – i.e. 2007 and later – versions of MSP.  If you are already using the “Task Path” bar styles in MSP 2013+ and are looking for a compatible filter, then have a look at my other article: Macro for Filtering based on “Task Path” in Microsoft Project.]

For determining driving relationships, QuickTrace relies on MSP’s “StartDriver” task object, the basis of the Task Inspector pane (and the “Task Path” Driving Predecessors and Driven Successors bar styles in MSP 2013+).  This is a substantial improvement over the original Trace macro, which used Free Slack as the driving indicator.  Still, I’ve found StartDriver to be unreliable in the presence of non-FS relationships (See here.)  BPC Logic Filter (our MSP Add-In) instead identifies driving relationships directly by computing and examining relationship free floats – quite a bit more involved.

[Jan’19 Edit: QuickTrace also relies on recursion (a sort of repeated self-cloning process), and this makes it susceptible to crashing if the path length (i.e. the number of tasks in sequence) is too long.  In MSP 2010, I’ve analyzed path lengths a bit over 4,000 tasks before crashing.  The same analysis in MSP 2016 leads to a crash after only 700 tasks.

Version 1.5 of BPC Logic Filter now includes a QuickTrace option.

This implements the same recursive tracing algorithm that I’ve included in the macro code.  It’s blazing fast, and its results are perfectly aligned with the Task Path bar styles of MSP 2013+, no matter how flawed.  It also handles much longer path lengths (just under 8,000 tasks in MSP 2016) before running out of memory.]

Here’s the code. There are basically three front-end macros that you can assign buttons or hot keys to, one for predecessor chains, one for successor chains, and one for both.  (Using the last one can make the resulting path sort a little jumbled, so I made re-sorting optional.)    These call the other procedures to a) collect user input; b) clear existing values in the Flag4 and Number5 fields; c) recursively run through the chains of related tasks and and mark them using those fields; d) apply the filter and sort using those fields; and e) display a message box summarizing the filter/highlighting.  Note, this is provided as-is and is not supported by anyone.  I have not taken the time to accommodate every possible situation and won’t be doing so in the future.  If you are new to vba, please google around a bit before asking questions that are already answered somewhere else – that includes, “how do I install this and make it work?”  (Short answer: copy and paste the entire block into a new module in the visual basic editor.  Then add the three front-end macros to a custom group on one or more of your ribbon tabs.)

'QuickTrace Module
'Coded by T.Boyle, PE, PSP on 16Mar'17 [25Sep'18 edits - to allow highlighting, to provide a descriptive message box
'   after running, and to streamline the code.]  This Module is intended to trace logical paths from the selected task
'   to all of its predecessors or successors, then show only related tasks.  Tasks are sorted in the order of analysis,
'   which generally corresponds to identified logical "paths".
'CAVEATS:
'   1. This code WILL OVER-WRITE fields FLAG4 and NUMBER5.  Make sure these fields are not needed before running.  Otherwise,
'      edit the code to use different fields, as shown below.
'   2. This code relies on the StartDriver object for defining driving path logic.  It may not always be reliable for non FS
'      relationships.
'   3. Install all code into a new module, with "QuickTrace Module" above as the top line.
'   4. Assign buttons or hotkeys to the first three procedures only (the others are called by these three):
        'a. CallQTraceP() - Traces predecessors.
        'b. CallQTraceS() - Traces successors.
        'c. CallQTraceB() - Traces both predecessors and successors (Added 15Nov'17)
'
 
Option Explicit
Private Cnt As Long, Driv As Boolean, HL As Boolean, ShowSums As Boolean, Tsel As Task, DirGlob As String
 
Sub CallQTraceP()
    'This procedure finds, marks, filters, and sorts predecessors of the selected task.
    'Run this directly using a button or hot key
     
    Cnt = 0
    DirGlob = "P"
        
    ClearFields
    CollectInput
    'Run Trace from Selected cell
    Call QTrace(Tsel, "P")
    Call Filter("P")
 
End Sub
 
Sub CallQTraceS()
    'This procedure finds, marks, filters, and sorts successors of the selected task.
    'Run this directly using a button or hot key
     
    Cnt = 0
    DirGlob = "S"
        
    ClearFields
    CollectInput
    'Run Trace from Selected cell
    Call QTrace(Tsel, "S")
    Call Filter("S")
 
End Sub
 
Sub CallQTraceB()
    'This procedure finds, marks, filters, and sorts both predecessors and successors of the selected task.
    'Run this directly using a button or hot key
     
    Cnt = 0
    DirGlob = "B"
        
    ClearFields
    CollectInput
    'Run Trace from Selected cell
    Call QTrace(Tsel, "P")
    Call QTrace(Tsel, "S")
    Call Filter("P")
 
End Sub
 
Sub QTrace(ByRef t As Task, ByVal dir As String)
    'This procedure marks a task (as related) and calls itself for each related predecessor or successor.
    'This procedure is called by another procedure.
     
    Dim d As TaskDependency
    Dim ds As TaskDependency
     
    'Mark this task as related
    Cnt = Cnt + 1
    '''''''''''''''''''''''''''''''''''''''''''''Edit Fields Flag4 and Number5 as Needed'''''''''''''''''''''''''''''''''''''''''
    t.Flag4 = True
    t.Number5 = Cnt
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
     
    'Recurse to next dependency
    If Driv Then
        If dir = "P" Then
            For Each d In t.StartDriver.PredecessorDrivers
                Call QTrace(d.From, "P")
            Next d
        Else 'i.e. dir="S"
            For Each ds In t.TaskDependencies
                If ds.From = t Then
                    For Each d In ds.To.StartDriver.PredecessorDrivers
                        If d.From = t Then Call QTrace(d.To, "S")
                    Next d
                End If
            Next ds
        End If
    Else
        For Each d In t.TaskDependencies
            If dir = "P" And d.To = t Then Call QTrace(d.From, "P")
            If dir = "S" And d.From = t Then Call QTrace(d.To, "S")
        Next d
    End If
End Sub
 
Sub CollectInput()
    'This procedure collects user input.
    'This procedure is called by another procedure.

    Driv = False
    HL = False
    ShowSums = False
    
    Set Tsel = ActiveCell.Task
    If MsgBox("Driving Path only?", vbYesNo) = vbYes Then Driv = True
    If MsgBox("Highlight only?", vbYesNo) = vbYes Then
        HL = True
    Else
        If MsgBox("Show Summary Tasks?", vbYesNo) = vbYes Then ShowSums = True
    End If

End Sub
Sub ClearFields()
    'This procedure runs through the tasks of the active project and clears two selected fields for use.
    'This procedure is called by another procedure.
     
    Dim t As Task
    'Clear Fields
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
    '''''''''''''''''''''''''''''''''''''''''''''Edit Fields Flag4 and Number5 as Needed'''''''''''''''''''''''''''''''''''''''''
            t.Flag4 = False
            t.Number5 = 0
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        End If
    Next t
End Sub
 
Sub Filter(ByVal dir As String)
    'This procedure creates and applies a filter to show only related tasks.
    'This procedure is called by another procedure.
     
            '''''''''''''''''''''''''''''''''''''''''''''Edit Field Flag4 as Needed'''''''''''''''''''''''''''''''''''''''''
            FilterEdit Name:="Flag4", TaskFilter:=True, Create:=True, _
                OverwriteExisting:=True, FieldName:="Flag4", Test:="equals", _
                Value:="Yes", ShowInMenu:=True, ShowSummaryTasks:=ShowSums
            FilterApply Name:="Flag4", Highlight:=HL
            '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        
        If ShowSums Then '(HL is False)
            'Sort by path order
            If MsgBox("Resort to show paths?", vbYesNo) = vbYes Then
            '''''''''''''''''''''''''''''''''''''''''''''Edit Field Number5 as Needed'''''''''''''''''''''''''''''''''''''''''
                If dir = "P" Then Sort Key1:="Number5", Ascending1:=False, Renumber:=False, Outline:=True
                If dir = "S" Then Sort Key1:="Number5", Ascending1:=True, Renumber:=False, Outline:=True
            '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
            End If
        Else '(ShowSums is False and HL may be true or false)
            If Not HL Then
            'Sort by path order
                If MsgBox("Resort to show paths?", vbYesNo) = vbYes Then
            '''''''''''''''''''''''''''''''''''''''''''''Edit Field Number5 as Needed'''''''''''''''''''''''''''''''''''''''''
                    If dir = "P" Then Sort Key1:="Number5", Ascending1:=False, Renumber:=False, Outline:=False
                    If dir = "S" Then Sort Key1:="Number5", Ascending1:=True, Renumber:=False, Outline:=False
            '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                End If
            End If
        End If
        EditGoTo ID:=Tsel.ID
        FilterBox
End Sub
        
Sub FilterBox()
    'This procedure creates and displays a message box describing the filter/highlight basis.
    'This procedure is called by another procedure.
    Dim Msg As String
    
    If HL Then
        Msg = "Highlighting "
    Else
        Msg = "Filtering for "
    End If
    
    Select Case DirGlob
        Case "P"
            If Driv Then Msg = Msg & "driving "
            Msg = Msg & "predecessors "
        Case "S"
            If Driv Then Msg = Msg & "driven "
            Msg = Msg & "successors "
        Case "B"
            If Driv Then Msg = Msg & "driving & driven "
            Msg = Msg & "predecessors & successors "
    End Select
    
    Msg = Msg & "of task " & Tsel.ID & ": " & Tsel.Name & " (inclusive)"
    MsgBox Msg
    
End Sub


[Aug’18 Edit:] One of the commenters sent an example of a schedule where the macro includes in the driving path to project completion two tasks that are in fact neither critical nor driving .  As shown below, the Task Path functionality is used to highlight the “Driving Predecessors” to Task 13 (orange bars).

Tasks 21 and 22 are included in the Task Path highlighting, and they are also flagged as part of the Driving Path (to Task 13) by the QuickTrace macros.  This is because MSP has marked Task 22 as the StartDriver predecessor for Task 26.  As a manually-scheduled task, however, Task 26 really has NO StartDriver predecessor, and the reference to Task 22 is incorrect.  Neither the macro nor the Task Path function has been adapted to account for this.  (BPC Logic Filter correctly excludes these non-driving tasks, and MSP marks them as non-critical because they possess positive Total Slack.)

Troubleshooting Circular Task Relationships with BPC Logic Filter

Planners attempting to build complex project schedules in Microsoft Project will typically come across the circular logic warning at some point when trying to link tasks.

In general, most such messages come from assigning logic to summary tasks, which experienced schedulers don’t do.

When an experienced scheduler encounters the circular logic warning, it often means that he has made an earlier error in the logic that is only now being detected as the loop is closed.  For example, a normal construction “fragnet” for concrete structures may include the following task sequence: Form -> Pour -> Finish -> Cure – > Strip(forms), repeated over and over for different structures on the project. If I get the warning when trying to impose one of these obvious links – say from Pour to Finish, then I know that Pour and Finish are already connected.  I have to find the logical error in that path of task connections.

Fortunately,  BPC Logic Filter includes a little feature that’s been variously referred to as “Bounded Network Analysis,” “Truncated Logic Tracing,” and “Logic Tracing to Target.”  It finds all the connections between any two tasks in the project and filters out all the others.  This makes finding the error that much easier.  The figure below highlights the selected task (Form3) in yellow and the target task (Pour3) in orange.  In the example, I can trace the problem linking Form3 and Pour3 to a “dummy string” of tasks that was inserted between Cure3 and Cure2.

Early last year I wrote about a method for finding the connections between two arbitrary activities in a CPM schedule.  Most of that post was aimed at using the circular logic error handler in Oracle Primavera P6 to accomplish the objective.  Obviously, this turns that method around.

Mandatory Constraints in Microsoft Project and Primavera P6

Here I review some impacts of “hard constraints” on the calculation of total float (or total slack) in logic-driven schedules. 

First a Note on Defining “Soft” and “Hard” Constraints

Some project scheduling guidance documents routinely categorize date constraints as either soft or hard depending on their ability to contradict or override network scheduling logic.  Mandatory date constraints — must-start-on (MSON) and must-finish-on (MFON) — are uniformly considered hard constraints because they can impose schedule dates that cause logic restraints to be violated.  As a result, the logic flow through the network is obstructed.  Early date constraints — start-no-earlier-than (SNET) and finish-no-earlier-than (FNET) — are uniformly considered considered soft constraints, presumably because they act in addition to, never in opposition to, the logic.

Both the DCMA 14-Point Assessment guidance (Nov’11) and the GAO Schedule Assessment Guide (Dec’15) also list late date constraints — start-no-later-than (SNLT) and finish-no-later-than (FNLT) — as hard constraints, even though they do NOT cause violations of logic restraints in most scheduling software.   The reason for this is unclear, though it may be related to the default “tasks will always honor their constraint dates” setting in Microsoft Project.  Under normal scheduling, this setting automatically converts a late date constraint to a mandatory constraint when it creates negative slack/float.  Another document (Planning and Scheduling Excellence Guide – PASEG v.3 – from the National Defense Industry Association) seems to recognize this issue, stating “Hard constraints do not allow the logic to drive the schedule (i.e. either restricts all movement or restricts movement to the right) on the constrained task.”  In this context, “restricts movement to the right” describes the impact of the setting on early dates (i.e. the default Start and Finish dates) in MSP.  Unfortunately, the DCMA 14-Point Assessment guidance continues to equate negative float with the existence of a hard constraint.  Such a position seems unsupported by any consistent set of base principles.

Microsoft Project

A recent discussion on technet raised the issue of slack/float calculation for tasks with hard constraints – in this case Project’s “Must Start On” (MSO) constraint.  A novice user of Microsoft Project (MSP), was puzzled by MSP’s calculation of non-zero total slack for an MSO-constrained task who’s early and late dates were the same.  That is, the expected definition of Total Slack as “Late Finish minus Early Finish” [*] was clearly NOT being followed.

*[The traditional CPM definition of Total Slack/Float is TS=LF-ES-Dur.  When Duration is a constant (as in MSP and P6) this simplifies to:

TS=(LF-Dur)-ES ==> TS=LS-ES, and

TS=LF-(ES+Dur) ==> TS=LF-EF.]

Consider the simple example comprising a three-task schedule with an MSO constraint on the second task and a deadline (a soft late constraint) on the third task, which I’ve shown below.

There are two basic issues about MSO (and MFO) constraints in Microsoft Project that come into play:

  1. Under typical default conditions, Project sets both the early start and late start equal to the MSO constraint date. This completely blocks logic flow through the task, and TS is zero.  I’ve illustrated this in the first chart below, where I’ve set a lenient MSO constraint on task t2 but imposed a deadline on the completion task t3 to create some negative slack.  Clearly the first task t1 should have negative slack, but the backward pass calculations don’t show it.
  2. If the early start imposed by the MSO constraint precedes the early start derived from the forward pass (i.e. the logic), then a logical conflict is created. If the “Tasks will always honor their constraint dates” box is checked in the Schedule options (the default condition), then Project keeps the imposed early and late starts – violating the CPM logic – and “resolves the conflict” by over-writing Total Slack with a negative value.  This case is presented in the middle chart below.  If the checkbox is not checked, then the Early Start is allowed to slip with the logic while the Late Start is retained.  I’ve shown this on the bottom chart.

msp-mso-constraint

The example presented is a “Mandatory Constraint,” which is strongly discouraged in general and is explicitly prohibited in many contexts.  Unchecking the “Tasks will always honor their constraint dates” box softens the impact of the constraint, but logic flow through the task is still interrupted.  Because of these issues, users of MSP would be well advised to avoid MSO or MFO constraints in any context where scheduling logic (and Total Slack) are important.

MSP/Primavera P6 Comparison

With the checkbox checked (i.e. default conditions), Microsoft’s “Must Start On” constraint seems to behave almost identically to P6’s “Mandatory Start” constraint.

  1. Like Project’s MSO, P6’s Mandatory Start constraint over-writes early AND late dates, thereby imposing a null Total Float and interrupting logic flow through the schedule.
  2. In the absence of a logical conflict, Mandatory Start (in P6) results in the same dates AND Total Float (null-value) as MSO in MSP.
  3. There is one minor difference. Whereas Project separately computes and imposes negative Total Slack (on the constrained task only) to highlight a logical conflict, P6 preserves the CPM-defined Total Float of zero on the constrained activity.  (This was the basis for the original question on technet.)  Both constraints impose negative slack/float on the predecessors of the constrained task/activity based on the logical conflict alone; negative slack/float from a more stringent constraint later in the project will be blocked.

p6-vs-msp-mso-constraint

With the checkbox un-checked, the resulting MSP schedule appears similar at first to P6’s schedule when using a (softer) constraint like “Start-On”.  This should not be misinterpreted.  As shown in the next chart, MSP continues to over-write the late date with the constraint date, even when the CPM-based late date is more restrictive.  Resulting predecessor slack values may be incorrect.  P6’s “Start On” constraint, on the other hand, results in a correct float calculation for the imposed conditions.

p6-vs-msp-mso-constraint2

 

Video – Find the Driving Path for Key Milestones in Microsoft Project using BPC Logic Filter

In the presence of Deadlines, Constraints, variable Calendars, and resource leveling, Total Slack becomes unreliable as an indicator of the Critical Path (or of nearness to the Critical Path).  In addition, many projects include Key Completion Milestones that occur long before the final scheduled activity of the project, so a Longest-Path approach doesn’t apply.  For these projects, I use the Task Logic Tracer to find the Driving Path and Near-Driving Paths of each Key Completion Milestone.