Overlapping Tasks in Project Schedules

In a project schedule, overlapping tasks are tasks that are BOTH sequential and concurrent.  The effective and efficient scheduling of overlapping tasks typically requires the use of time lags and logic relationships that are not Finish-to-Start.

Introduction

In a project schedule, overlapping tasks are tasks that are BOTH sequential and concurrent, with neither condition being absolute.  They can exist in highly-detailed schedules for project engineering, design, production, and construction, though they are much more common in high-level summary schedules.  Essentially, Task A and Task B are overlapping when:

  1. Task B is a logical successor of Task A; and
  2. Task B can start before Task A is finished.

Handling the second condition typically requires the use of time lags and logic relationships that are not Finish-to-Start.  These elements were not supported in the original Critical Path Method (CPM), and some scheduling guidelines and specifications still prohibit or discourage their use.  Nevertheless, they remain the most effective tools for accurately modeling the plan of work in many cases.

There are essentially two categories of overlapping task relationships: Finish-Start Transitions and Progressive-Feeds.

Finish to Start Transitions

Overlapping tasks with Finish-Start Transition relationships can be described in terms of a relay (foot)race, where an exchange zone for handing over the baton exists between each pair of “legs” (i.e. the 4 stages of the race).  At the end of Leg 1, Runner 2 must start running before Runner 1 arrives, timing his acceleration to ensure an in-stride passing of the baton in the exchange zone, simultaneous with the completion of Leg 1.  Runner 2 does not care about Runner 1’s fast start nor his awkward stumble at the midway point; his only focus is on gauging Runner 1’s finishing speed and starting his own run at the precise instant necessary to match speeds in the transition zone.  In practice, Runner 2 establishes a mark on the track – paced backward from the exchange zone – and starts his own run when Runner 1 reaches the mark.

Real-world examples of such overlap include the cleanup/de-mob and mob/setup stages of sequential tasks in construction projects.  In engineering/design, many follow-on tasks may be allowed to proceed after key design attributes are “frozen” at some point near the finish of the predecessor task.  In general, the possibility of modest overlap exists at many Finish-Start relationships in detailed project schedules, sometimes being implemented as part of a fast-tracking exercise.  The most common front-end planning occurrence of these relationship in my experience is in logic driven summary schedules, where analysis of the underlying detailed logic indicates that the start of a successor summary activity is closely associated with, but before, the approaching finish of its summary predecessor.

In terms of a project schedule, this kind of relationship is most easily modeled as Finish-to-Start with a negative lag (aka “lead”).  This is illustrated by the simple project below, where tasks A, B, and C are sequentially performed between Start and Finish milestones.  Each task has a duration of 9 days to complete 90 production-units of work.  (A linear production model is shown for simplicity.)  Because of the Finish-Start Transition, Task B and Task C are allowed to start 1 day before their predecessor finishes. 

Negative lags can be used for date manipulation, such as to hide an apparent delay.  Negative lags can also be the source of float (and critical path) complications for project schedules with updated progress, particularly when the lag spans the data date.  Consequently, negative lags are discouraged or explicitly prohibited in many schedule standards and specifications.

When negative lags are prohibited, overlapping tasks with Finish-Start transitions may be modeled by breaking the tasks into smaller, more detailed ones – all connected with simple Finish-Start links and no lags.  In the example, the two negative-lag relationships can be replaced by two pairs of concurrent 1-day tasks – the last part of the predecessor and the first part of the successor – that are integrated with FS links.  Thus, the overlapping linear production of the three tasks now requires 7 tasks and 8 relationships to model, rather than the original 3 tasks and 2 relationships.  Alternately, each pair of concurrent tasks could be combined into a single “Transition” task, though such an approach could involve additional complication if resource loading is required.

In practice, the extra detail seems hardly worth the trouble for most schedulers, so simply ignoring the overlap seems fairly common.  This has the consequence of extending the schedule.

By ignoring the overlap, the scheduler here has added two days (of padding/buffer/contingency) to his overall schedule, extending the duration from 25 to 27 days.  This is unlikely to be recovered.

Overlapping Tasks with Progressive Feeds

The predominant category of overlapping tasks involves repetition of sequentially-related activities over a large area, distance, or other normalized unit of production.  The activities proceed largely in parallel, with the sequential relationships based on progressive feeding of workfront access or work-in-process units from predecessor to successor.  In construction, a simple example might include digging 1,000 meters of trench, laying 1,000 meters of pipe in the trench, and covering the trench.  The most timely and profitable approach to the work is to execute the three tasks in parallel while providing adequate work space between the three crews whose production rates are well matched.  This is often described as a “linear scheduling” problem; common examples in construction are railways, roadways, pipelines, wharves, industrial facilities, and even buildings (e.g. office towers – where steel, concrete, mechanical, plumbing, electrical, finishing, and trim activities need to be repeated for each floor.)  Many large-scale production/manufacturing operations are set up to maximize overall throughput by optimizing the progressive feeding of production units through the various value-adding activities.  Proper scheduling of such activities is necessary when similar techniques are applied in non-manufacturing industries like construction, e.g. production lines for precast concrete piles or panels.

Below is a simple table and associated linear production chart summarizing three sequential tasks (A, B, and C) that must be repeated 90 times along a workfront to complete a specified phase of work.  Each task can be executed 10 times per day, resulting in a 9-day duration for the required 90 units of production.  For safety and productivity reasons, it is necessary to maintain a minimum physical separation of 30 units (i.e. 3 days’ work) between the tasks at all times.  Thus, Task B must not be allowed to start until Task A has completed 30 units of production (~3 days after starting), and it must not be allowed to complete more than 60 units of production (~3 days from finishing) until Task A has finished.  Task C must be similarly restrained with respect to Task B.  As a result, the overall duration of the three tasks is 15 days.

The three tasks must now be incorporated into a logic-based project schedule model.  When doing so, the following potential issues should be kept in mind:

  • In most scheduling tools, relationship lags are based on an implied equivalence between production volume (or workfront advancement) and time spent on the task. The validity of the lags needs to be confirmed at each schedule revision or progress update.  (One exception, Spider Project, may offer more valid methods.)
  • Using progressive-feed assumptions with unbalanced production rates can have unintended consequences. For example, if the production rate of Task B is doubled such that the task can be completed in half the time, then the start of the task may be delayed to meet the finish restraint.  This is consistent with a line-of-balance planning philosophy that places the highest priority on the efficient use of resources, such that scarce or expensive resources will not be deployed until there is some assurance that the work may proceed from start to finish at the optimum production rate, without interruption.  In the example, the delayed start of Task B also delays the start of Task C, leading to an increase in the overall project duration from 15 days to 20 days.  Some writers refer to this phenomenon as “Lag Drag.”  The overall schedule is optimized when progressive-feed tasks are managed to the same balanced production rate, and disruptions are minimized.
  • A progressive-feed model may not be valid if the physical or temporal requirements underlying the lags at task Start and Finish are violated during task execution. For example, if the daily production rate of Task A follows a classic S-curve profile (“Task A Logistic”) while Task B’s stays linear, then maintaining the required 30-unit minimum physical separation may require additional delay at the start of the second task.

Compound Relationships: The Typical Approach in Oracle Primavera P6

As shown in the following figure, scheduling these overlapping tasks is fairly straightforward in P6.  Because P6 supports multiple relationships between a single pair of tasks, it is possible to implement the required Start and Finish Separations as combined Start-Start and Finish-Finish relationships, each with a 3-day lag.  These are also called “Compound Relationships.”  The resulting representation of the linear schedule is completed with 3 tasks and 4 relationships (excluding the Start and Finish milestones.)  The three tasks are likely well aligned with the labor and cost estimates for the project, so resource and cost loading of the schedule should be straightforward.  The scheduler must still ensure that the three concerns above are addressed, namely: validating lag equivalence to work volumes or workfront advancement, balancing of production rates, and confirming lag adequacy when used with differing task production profiles.

One-sided Relationships: The Typical Approach in MSP

Microsoft Project does not permit more than one relationship between any two tasks in a project schedule (see Ladder Logic in Microsoft Project).  As a result, the scheduler in MSP will typically choose to implement either a Start-to-Start or Finish-to-Finish restraint with a corresponding lag.  Both options are shown in the following figure.

In either case, the resulting schedule will have the lowest number of tasks {3} and relationships {2} to manage (for both cost and schedule) through the project.  This approach is easy to implement.

The most obvious problem with this typical approach is the inadequate logic associated with the dangling starts and dangling finishes (Dangling Logic).  As a result, the typical CPM metrics of Slack (i.e. Float) and identification of the Critical Path will not be reliable, especially after the start of progress updates.

PDM with Dummy Start Milestones

Correcting the dangling logic issues in MSP schedules is most simply addressed using dummy milestones to carry either the start or finish side of the logic flow.  Below I’ve shown two variations using dummy Start milestones:

Alternate A involves trailing start milestones.  Here, the milestones exist as start-to-start successors of the corresponding tasks, effectively inheriting their dates from the corresponding task start dates.  The trailing start milestones pass logic to the successor tasks via relationships of the form, start-to-start-plus-lag.

Alternate B involves leading start milestones.  Here the milestones exist as start-to-start successors of the preceding tasks (plus lags) and as start-to-start predecessors of their corresponding tasks (no lags).

The two alternates are largely equivalent, though Alternate B (leading start milestones) has one significant advantage: it works with percentage lags.  When a percentage lag is imposed, the imposed time lag increases or decreases as the predecessor’s duration increases or decreases.  This reduces some of the risks of the assumed production volume = time equivalence.  (Be careful, though; the imposed lag is always a percentage of the overall Duration of the predecessor task, having nothing to do with the Actual (i.e. to-date) Duration.  Moreover, all lags in MSP are imposed using the successor-task’s calendar, so mis-matched predecessor and successor calendars can bring surprises.)

Using the dummy milestones leads to valid schedule logic with a relatively modest addition of detail (i.e. medium number of tasks {5} and relationships {6}.)  The schedule stays fully aligned with labor/cost estimates; no deconstruction is required, and it responds well to unbalanced and varying production rates.  Unfortunately, the dummy milestones can cause visual clutter, so presentation layouts need filters to remove them from view.

Full-Detail: the CPM Ideal

Non-finish-to-start relationships were not supported in the original CPM, and they are discouraged or prohibited in some scheduling standards and specifications.

If only finish-to-start relationships are allowed, then accurate modeling of the three overlapping tasks requires substantial deconstruction into a larger number of detailed subtasks.  For the three-task example, the schedule model below breaks each 9-day task into nine 1-day tasks, all integrated with finish-to-start relationships.  The model is depicted using MSP; a similar model could be constructed in P6.

Overall, this approach appears to be more “valid” with respect to pure schedule logic.  That is, there are no leads, no lags, and no non-finish-to-start relationships.  The resulting model can also respond well to unbalanced and varying production rates, and it is likely to stay valid through progress updates.

On the “con” side, this model has the maximum level of detail (i.e. highest number of tasks {27} and relationships {39}.)  Consequently, it will introduce substantial complications to resource and cost loading, and it will be the hardest to manage through completion.  More importantly, the logic relationships that accompany such additional detail are not always technologically required.  While the ordering of Units 21-30 prior to Units 31-40 may appear perfectly reasonable in the office, all that really matters is that ten units of production are received, completed, and passed on to the next task each day.  The addition of such (essentially) preferential logic increases the chances that the actual work deviates substantially from the plan, as field conditions may dictate.  That can severely complicate the updating of the schedule, with no corresponding value added.

Compromise: PDM with Partial Detail

The next figure presents a compromise, providing additional task details as needed to address the initial separation requirements but minimizing the use of lags and non-finish-start relationships.  The result is a moderate schedule with “mostly valid” logic and only modest level of detail (i.e. medium number of tasks {6} and relationships {7}.)  Such a schedule presents medium difficulty of implementation and is less susceptible to the “preferred logic” traps identified earlier.  It also responds well to unbalanced and varying production rates, and it stays valid (mostly) during progress updating.

This schedule still requires consideration and validation of the progressive-feed assumptions.  Since this schedule is only partly aligned with existing labor/cost estimates, some de-construction of those estimates may be required for resource and cost loading.

Resource Leveling Changes from MSP 2010 to MSP 2016 – Revisited

In a departure from an earlier study, the resource-leveled schedule generated using Microsoft Project (MSP) 2016 may sometimes be substantially shorter than the comparable schedule from MSP 2010.  The result suggests a more sophisticated leveling algorithm that, while sometimes generating shorter schedules, may increase the associated resource-related risks.

Several years ago I wrote an article examining some reported differences in resource leveling behavior between Microsoft Project (MSP) 2010 and 2013 versions.  In general, those observations implied that the newer software was generating longer schedules under default conditions.  (The observations were by others, since at the time I was only using MSP 2010.)  I concluded the article with a speculation that the leveling algorithm may have been adjusted to preserve the appearance of the pre-leveling “Critical Path,” but at the expense of a longer schedule.

A recent test case using MSP 2016 does nothing to confirm that speculation, and an opposite conclusion is implied.

Below is an idealized schedule for construction and commissioning of a small processing plant, including resource loading.  Only technologically-required logic is included, so that a) the resources are all severely overallocated, and b) the schedule is unrealistic.  The same schedule is shown in both MSP 2010 and MSP 2016 forms, with only cosmetic differences.  There is a Deadline of 25Feb’05 on the Substantial Completion task, and no explicit risk buffers are present.  [The MSP 2010 form was used to illustrate the resource-leveled critical path in a technical paper I presented at AACE International in 2017.] 

To resolve the resource over-allocations and generate a more realistic schedule, the resource leveler is applied in both MSP 2010 and MSP 2016 using simple leveling options with no task priorities defined.

As shown below, these options lead to completely different schedules in the two tools, with MSP 2016 generating a leveled schedule that is 10-days shorter than the MSP 2010 version.

Key observations:

  1. The MSP 2010 schedule failed to meet the Deadline, so more tasks are marked Critical due to zero-or-negative Total Slack. Six tasks including the two milestones have TS=-10d (i.e. the “most critical” as defined by Total Slack.)
  2. The MSP 2010 leveler did not impose any task splits, even though they were allowed.
  3. The MSP 2016 schedule meets the Deadline, so no negative slack is imposed. Seven tasks including the two milestones have TS=0 (the “most critical.”)
  4. The MSP 2016 leveler imposed a task split on one task (A3 Structures).

A close look at the Resource-leveled Critical and Near Critical paths – Using the Near Longest Path Filter in our BPC Logic Filter add-in – demonstrates that MSP 2016’s leveler creates a more condensed schedule.  Specifically:

  1. MSP 2010 generates a single continuous Resource-leveled Longest Path (BPC Relative Float = 0) comprised of eight tasks in sequence. The other 12 tasks possess 10 to 70 days of relative float.
  2. MSP 2016 generates a continuous Resource-leveled Longest Path of 13 tasks in sequence, with 2 additional tasks (and a split part of one of the original 13) in parallel branches.  The other 5 tasks possess from 20 to 60 days of relative float.  As a result, more of the work is both concurrent AND Critical. It turns out that the splitting of the A3 Structures task is not the key to the more condensed schedule in MSP 2016.  In fact, re-running the leveler while disallowing splits leads to a schedule that – with no splits and with a completely different sequential arrangement – finishes at the same time. The corresponding Resource-leveled Longest Path is comprised of only 8 tasks in sequence, with 1 additional, parallel/concurrent task.  This leveled schedule has fewer resource mobilizations and disruptions along the longest path while still finishing at the earliest leveled time; it appears to be lowest risk.

This example suggests that MSP 2016’s default resource leveling algorithm may be substantially more sophisticated than MSP 2010’s, and it promises – under the right circumstances – to offer shorter leveled schedules in the absence of explicit user-defined priorities.  The shorter schedules may also be accompanied by technical and resource risks associated with multiple, concurrent branches of the resource-critical-path.  Project managers using resource leveling are advised to consider and buffer these risks appropriately.

In contrast with this finding and in keeping with the prior version of this article, others have continued to observe consistently longer schedules being generated by MSP 2016 (compared to MSP 2010 and earlier), on some standardized schedule models.  These observations are noted in the comments.

What is the Longest Path in a Project Schedule?

In Project schedules, the Longest Path yields the Shortest Time.  Aside from the mental gymnastics needed to digest that phrase, the concept of Longest Path – especially as implemented in current software – has deviated enough from its origins that a different term may be needed.   

Critical Path as Longest Path

Authoritative definitions of the “Critical Path” in project schedules typically employ the words “longest path,” “longest chain,” or “longest sequence” of activities … (that determine the earliest completion date of the project.)  In other words, the path, chain, or sequence with the greatest measured length is the Critical Path.  As a rule, however, none of the associated documents are able to clearly define what constitutes the length of a logic path, nor how such length will be measured and compared in a modern project schedule.  Without a clear standard for measuring the length of something, explicitly defining the Critical Path in terms of the longest anything is just sloppy in my view.

The Original Path Length

Assessing path length used to be much easier.  In the early days of CPM (Critical Path Method) scheduling, any project schedule could be guaranteed to have ALL Finish-to-Start relationships, NO constraints, NO lags or leads, NO calendars, and only ONE Critical Path.  Under these conditions, the length of a logic path could be clearly defined (and measured) as the sum of the durations of its member activities.  Thus, the overall duration of a Project was equal to the “length” (i.e. duration) of its Critical Path, which itself was made up of the durations of its constituent activities.  That result is indicated in the figure below, where the 64-day project length is determined by the durations of the 5 (highlighted) activities on the Critical Path.  Adding up the activity durations along any other path in the schedule results in a corresponding path length that is less than 64-days – i.e. not the “longest” path. [The network diagram was taken from John W. Fondahl’s 1961 paper, “A Non-Computer Approach to the Critical Path Method for the Construction Industry,” which introduced what we now call the Precedence Diagramming Method.  Unfortunately, Microsoft Project (MSP) has an early limit on dates, so his presumed ~1961 dates could not be matched.]

Fortunately, in such simple projects, it’s never been necessary to aggregate and compare the lengths of every logic path to select the “longest path.”  The CPM backward pass calculations already identify that path by the activities with zero-Total Float/Slack, and successively “shorter” paths are identified by successively higher Total Float/Slack values.  This fact has been verified in countless student exercises involving simple project schedule networks, typically concluding with the axiom that “the Critical Path equals the longest path, which equals the path of zero-Total Float/Slack.”

Float/Slack and Path-Length Difficulties

In general, modern complex project schedules have, or can be expected to have, complicating factors that make Total Float/Slack unreliable as an indicator of the Critical Path – e.g. non-Finish-to-Start relationships, various early and late constraints, multiple calendars, and even resource leveling.  See this other article for details.  Therefore, as noted earlier, the axiomatic definition has been shortened to “the Critical Path equals the longest path.”

Unfortunately, finding the “longest path” by arithmetically summing the activity lengths (i.e. durations) along all possible logic paths and comparing the results – not easy to begin with – has gotten more difficult.  Lags, excess calendar non-working time, and resource leveling delays all add to the apparent “length” of a logic path compared to the simple summation of activity durations.  Early date constraints may introduce delays that are not justified by task durations or logic relationships, breaking the path altogether.  On the other hand, leads (negative lags), excess calendar working-time, and the use of overlapping-activity relationships (e.g. SS/FF) reduce its length.  In addition, any hammocks, level-of-effort, and summary activities need to be excluded.  All such factors must be accounted for if the “longest path” is to be established by the implied method of measuring and comparing path lengths in the project schedule.  I don’t know of any mainstream project scheduling software that performs that kind of calculation.  Alternatively, Deep Schedule AnalysisTM using the proprietary HCP (Hidden Critical Path) Method – from HCP Project Management Consulting – appears to compute and compare the lengths of all logic paths in Primavera and MSP schedules.

Longest Path as Driving Path

Contrary to summing up and comparing logic path lengths, most current notions of the “longest path” are based on an approach that does not involve path “length” at all.  As a key attribute, the longest path in a simple, unconstrained and un-progressed project schedule also happens to be the driving logic path from the start of the first project activity to the finish of the last project activity.  It is a “driving logic path” because each relationship in the path is “driving”, that is it prevents its successor from being scheduled any earlier than it is.  Driving relationships are typically identified during the forward-pass CPM calculations.  Subsequently, the driving path to the finish of the last activity can be identified by tracing driving logic backward from that activity, terminating the trace when no driving predecessors are found or the Data Date is reached.  The resulting driving path to project finish is sometimes called the “longest path” even though its “length” has not been established.  This is the “Longest Path” technique that has been applied for nearly two decades by (Oracle) Primavera and adopted more recently in other project scheduling tools.

As of today, MSP continues to define Critical tasks on the basis of Total Slack, but it provides no explicit method for identifying the “Critical Path” using a “longest path” criterion.  How is the responsible MSP scheduler supposed to respond to a demand for the “critical path” when the longest path has been obscured?  Here are several options:

  1. Continue to make simple projects, avoiding all complicating factors like calendars (including resource calendars), early and late constraints, deadlines, and resource leveling. Then assume that “Total Slack = 0” correctly identifies the Critical Path.
  2. If you are using MSP version 2013 or later,
    • Ensure that your project is properly scheduled with logic open-ends only present at a single start and single finish task/milestone, then select the single finish task,
    • Try to use the “Task Path” bar highlighter to highlight the “Driving Predecessors” of your selected finish task.  In the example below, a Deadline (a non-mandatory late-finish constraint) has been applied to task Op12 in the 1961 example, and MSP has responded by applying the “Critical” flag (based on TS=0) to Op12 and its predecessors Op10 and Op2.  As a result, the Critical Path is obscured.  Applying the bar highlighter and selecting task Op18 (the project’s finish task) correctly identifies the driving path to project completion, i.e. the “longest path.”  (For clarity, I manually added the corresponding cell highlighting in the table; the bar highlighter doesn’t do that.)
    • If necessary, create and apply a corresponding filter for the highlighted bars. I’ve posted a set of macros to make and apply the filter automatically in this article.
  3. If you are using MSP version 2007 or later,
    • Ensure that your project is properly scheduled with logic open-ends only present at a single start and single finish task/milestone, then select the single finish task,
    • Try to use the Task Inspector to identify the driving predecessor of the selected task, then go to it and flag it as being part of the driving path. Repeat this until the entire driving path is marked.
    • If necessary, create and apply a filter and/or highlighting bar styles for the flagged tasks.
    • I’ve posted another set of macros to do all this (except bar highlighting) automatically in this other article.
  4. Note: The previous two approaches both rely on MSP’s StartDriver task object to identify driving relationships. As noted in this article, however, the resulting driving logic is not reliable in the presence of tasks with multiple predecessors, non-FS predecessors, or actual progress.
  5. Use BPC Logic Filter or some other appropriate add-in to identify the “longest path” in the schedule.

Whichever method or software is used, expressing the Longest Path using the Driving Path methodology has one key weakness: it has not been proved generally useful for analysis of near-critical paths.  While the Longest Path may be known, its actual length is not readily apparent.  More importantly, there is no generally-accepted basis for computing the lengths, and hence the relative criticality, of the 2nd, 3rd, and 4th etc. Longest Paths.  Consequently, Near-Critical paths continue to be identified based on Total Float/Slack, which is still unreliable, or – in P6 – based on unit-less “Float Paths” from multiple float path analysis.

“Longest Path” and Early Constraints

As noted several times here, the methods described for identifying the “longest path” are in fact describing the “driving path to the project finish.”  This distinction can raise confusion when one or more activities in the project schedule are delayed by an early constraint.  Consider the case below, where an activity on the longest path (Op13) has been delayed 2 days by an early start constraint.  Consequently, its sole predecessor relationship (from Op3) is no longer driving, and Op3 gains 2 days of Total Float/Slack.  As shown by MSP’s “Driving Predecessor” bar highlighter, the driving logic trace is terminated (going backwards) after reaching the constrained task.

Identical results are obtained from Primavera’s (P6) Longest Path algorithm.  This is neither surprising nor incorrect; the project’s completion is in fact driven by the external constraint on Op13, and its predecessor Op3 is quite properly excluded.

In this case, the application of an early constraint on a longest-path task simply truncates the longest path, which may be re-established using a logic tracing routine that jumps the constraint.  In general, however, early date constraints can substantially change the driving path to project completion, such that the length (i.e. aggregate duration) of any particular logic path becomes irrelevant.  For example, the next figure shows the consequences of imposing a one week (external) delay to Task Op11 in lieu of the earlier constraint.  This leads to a 3-day delay of the project’s finish and a shift of the both the driving path and the zero-float path from Task Op13 to Op11.  The total length of the corresponding critical path (including Op11’s formerly-driving predecessors) is 62 days.  The 64-day path leading through Op13 and Op15 still exists, but it now has 3 days of total slack and is no longer driving the project completion.  Thus, the mathematical longest path carries no significance in this constrained project schedule.

 

It’s clear therefore that the driving path to project completion and the longest path from the project start (or Data Date) to the project completion can differ when early constraints are present.  P6’s “Longest Path” algorithm automatically defaults to the driving path, not the aggregate longest path, and to date there have been no built-in alternatives to that behavior.  As a result, some consultants suggest that P6 Longest Path analyses should be rejected when external constraints – even legitimate ones like arrival dates for Customer Furnished Equipment – are present.  Unfortunately, a position that requires strict duration-summing to identify critical (i.e. “longest”) paths in schedules containing early constraints appears to be both misleading and inconsistent with standard schedule calculating methods.  (A P6 add-in, Schedule Analyzer Software, does claim to provide a true Longest Path representation in the presence of early constraints.)

BPC Logic Filter – Longest Path Filter

BPC Logic Filter is a schedule analysis add-in for MSP that my company developed for internal use.  The Longest Path Filter module is a pre-configured version of the software’s Task Logic Tracer.  The module is specifically configured to identify the project’s longest path (as driving path) through the following actions:

  1. Automatically find the last task (or tasks) in the project schedule.
    • Excluding tasks or milestones that have no logical predecessors. (E.g. completion milestones that are constrained to be scheduled at the end of the project but are not logically tied to the actual execution of the project. The resulting trace would be trivial.)
    • Excluding tasks or milestones that are specifically flagged to be ignored, e.g. (“hammocks”)
  2. Trace the driving logic backwards from the last task to the beginning of the project.
    • Driving logic is robustly identified by direct computation and examination of relative floats. (Driving relationships have zero relative float according to the successor calendar.)  The unreliable StartDriver task objects are ignored.
    • Neither completed nor in-progress tasks are excluded from the trace.
  3. Either apply a filter to show only the driving logic path, or color the bars to view the driving logic path together (in-line) with the non-driving tasks. The example below is identical to the previous one, but BPC Logic Filter formats the bar chart to ignore the impacts of the applied deadline.  The resulting in-line view is substantially identical to the bar chart of the original, unconstrained project schedule. 

BPC Logic Filter and the (True) Longest Path

As noted earlier, even a a single early constraint can truncate the driving path to project completion or change the driving path altogether.  In either case, it is debatable in my view whether the addition of non-driving, float-possessing activities into the “longest path” makes that term itself more or less useful with respect to the typical uses of the “Critical Path” in managing and controlling project performance.  If necessary, it is easy to add such activities – as unconstrained drivers of any constrained task – in BPC Logic Filter by checking a box.  The bar chart below shows the results of the Longest Path Filter on the first early-constrained example schedule, as set up according to the driving-path (Primavera) standard.  Results are identical to those of the built-in “Driving Predecessors” highlighter in MSP (above) and of P6.

The next chart shows the complete “longest path” for the project, including the non-driving Op3 activity.

The second chart is different because the check box for “Override if successor task is delayed by constraint” has been checked in the analysis parameters form.  Checking the box causes the non-driving predecessor with the least relative float to be treated as driving, and therefore included in the Longest Path, in the event of a constraint-caused delay.

For a quick illustration, see Video – Find the Longest Path in Microsoft Project Using BPC Logic Filter.

BPC Logic Filter and Near Longest Paths

As noted earlier, the normal methods for identifying the “longest path” (i.e. the driving path) in a project schedule have not been generally adopted for analyzing near-longest paths.  P6 offers multiple float path analysis, which I wrote about here.  In addition,  Schedule Analyzer (the P6 add-in mentioned earlier) computes what it calls the “Longest Path Value” for each activity in the schedule – this is the number of days an activity is away from being on the Longest Path (i.e. the driving path to project completion.)   In the absence of demonstrated user demand, however, MSP seems unlikely to gain much beyond the Task Path bar highlighters.

BPC Logic Filter routinely computes and aggregates relative float to identify driving and near-driving logic paths in MSP project schedules.  In this context, “near-driving” is quantified in terms of path relative float, i.e. days away from driving a particular end task (or days away from being driven by a particular start task.)  Its “Longest Path” and “Near Longest Path” analyses are special cases where the automatically-selected end task is the last task in the project.  For the Near Longest Path Filter, tasks can be shown in-line (with bar coloring) or grouped and sorted based on path relative float.  The “override if successor is delayed by constraint” setting has no effect when the Near Longest Path Filter is generated.  In that case, the non-driving task will be displayed according to its actual relative float.  For example Op3 is shown below with a relative float of 2 days (its true value), not 0 days as shown on the earlier Longest Path Filter view.

Recap

  1. In the development of the Critical Path Method, the “longest path” originated as one of several defining characteristics of the “Critical Path” in simple project schedules. Specifically, the “Critical Path” included the sequence of activities with the highest aggregated duration – i.e. the “longest path”.  Actual computation and comparison of path lengths was not necessary since relative path lengths could be inferred directly from Total Float – a much easier calculation.
  2. Complicating factors in modern project schedule networks tend to confuse the interpretation of Total Float, such that it is no longer a reliable surrogate for path length. As a result, the most recent, authoritative definitions of the Critical Path tend to omit references to float while retaining references to “longest path” and, typically, logical control of the project completion date.  [Notably, the measurement and comparison of aggregated path durations (path lengths) has not been an explicit feature of any mainstream project scheduling tool, so the “longest-path” part of the definition cannot be definitively tested in general practice.]
  3. Notions of “longest-path” among current schedule practitioners are heavily influenced by the deceptively-named “Longest Path” feature in Oracle/Primavera’s P6 software. Perversely, that feature DOES NOT aggregate activity durations along any logic paths.  Rather, it identifies the driving/controlling logic path to the project’s early finish date.
  4. The “Longest Path” in P6 (i.e. the Driving Path to Project Completion) and the “longest path” (i.e. the logic path with highest aggregated duration) are NOT equivalent, particularly when the “Longest Path” is constrained by an early date constraint. There is at least one P6 add-in claiming to identify the true “longest path” (and near-“longest paths”) in this case.
  5. Microsoft Project provides several inefficient methods to identify the Driving Path to Project Completion in simple projects, but these methods are not reliable in the presence of non- Finish-to-Start relationships. There are no native MSP methods for identifying near-driving tasks nor the true “longest path” in the presence of early date constraints.  BPC Logic Filter is an MSP add-in that automatically fills these gaps.
  6. As conceived, the “longest path” criterion implied the transparent calculation and comparison of aggregated activity durations along each logic path in a project schedule. As for Total Float, however, such calculations in complex schedules have been obfuscated by complications like non- Finish-to-Start relationships, lags, and multiple calendars.  Since such obfuscation makes path lengths essentially un-testable, it appears that future Critical Path definitions should omit the “longest path” criterion in favor of a simple “driving path to project completion.”

Longest Paths in Backward Scheduled Projects (MSP) [Jan’19 Edit]

As pointed out in this recent article, the Longest Path in a backward scheduled project is essentially the “driven path from the project start,” not the “driving path to project completion.”

For more information, see the following links:

Article – Tracing Near Longest Paths with BPC Logic Filter

Video – Analyze the Near-Longest Paths in Microsoft Project using BPC Logic Filter

 

Avoid Out-of-Sequence Progress in Microsoft Project 2010-2016

[For the corresponding video presentation, see Construction CPM Conference 2020 – Avoid Out of Sequence Progress in Microsoft Project.]

Recording Actual dates that violate existing schedule logic can cause conflicts in Microsoft Project’s internal schedule calculations. The resulting Total Slack values and Critical task flags can be incorrect and misleading.  These issues are aggravated by recent (e.g. MSP 2016) versions of the software, and users are advised to minimize out-of-sequence progress.

Recording of actual progress in a logic-driven project schedule can be problematic.  As the “Actual” dates override or otherwise constrain the computed dates, the customary definitions of Float or Slack – and their resulting impacts on the “Critical” task flag in Microsoft Project (MSP) – no longer apply.  While I hope to undertake a general review of progress updating issues in a future article, this one has a special focus on out-of-sequence progress for two primary reasons:

  1. In all modern versions of Microsoft Project (e.g. ~MSP 2007+), the Total Slack values of “Critical” tasks with out-of-sequence successors can be altered unexpectedly.
  2. In MSP 2016 (and possibly beginning with MSP 2013), the Total Slack values of ALL tasks (not just “Critical” tasks) with out-of-sequence progress among their successors can be altered unexpectedly. As a result, many tasks can be shown incorrectly as “Critical” in MSP 2016 when they are not “Critical” in earlier versions.

What is Out-of-Sequence Progress

Out-of-sequence progress exists when actual progress is recorded (via, e.g. Actual Start, Actual Duration, Actual Work, %Complete, etc.) at times when the logical constraints of the schedule would normally preclude it.  For example:

  • An Actual Start is recorded for a task (the out-of-sequence, or OOS, task) whose Finish-to-Start predecessor has not finished. I.e. the Actual Start precedes the Early Start;
  • An Actual Start is recorded for an OOS task whose Start-to-Start predecessor has not started. Again, the Actual Start precedes the Early Start;
  • An Actual Finish is recorded for an OOS task whose Finish-to-Finish predecessor has not finished. Here the Actual Finish precedes the Early Finish.
  • An Actual Start is recorded for an OOS task whose Finish-to-Finish predecessor subsequently delays the completion of the work (on the OOS task).  Again the Actual Start precedes the Early Start that would have existed in its absence.

In all cases there is a presumption that the recorded actual progress is more correct than the (theoretical) schedule model, so Early and Late dates are routinely overwritten by Actual dates during the schedule calculations.  When the actual progress occurs out of sequence, however, computing the Late dates (and slack values) of incomplete predecessors (during the “Backward Pass” calculations) is complicated by logical conflicts.  The software typically resolves these conflicts in a way that satisfies the needs of most users.

Completed, Out-of-Sequence Tasks

The issues discussed here are of primary concern in those cases where a task has started out of sequence and a) it remains incomplete; and b) the violated predecessor relationships remain unsatisfied (e.g. the FS predecessor remains incomplete.)  If either the OOS task or its unfinished predecessor task become complete, then they are treated like other completed tasks in Microsoft Project.  That is, they can influence the Early dates of their successors but have no impact on the Late dates of their predecessors.  As a result of this latter condition, an incomplete task whose sole successor has been completed out of sequence becomes effectively open-ended, i.e. without successors.  Under default conditions (i.e. “calculate multiple critical paths” NOT checked), the task’s Late Finish is set equal to the project’s Early Finish Date, and a high value of Total Slack is computed.

Obviously, this can have a major impact on the apparent Critical Path of a project.  In the example below (which is further described in later paragraphs), tasks CP2 and SP2 have both been completed out-of-sequence, and at a duration of only 20% of their baseline durations.  The overall project has been shortened, but the Critical Path has been truncated at CP3.  CP1 is no longer “Critical” because, in effect, it no longer has any successors.  It appears necessary to add a new FS relationship from CP1 to CP3 (and equivalently from SP1 to SP3) to re-establish the logic chain that has been broken by the completed, out-of-sequence tasks.

In Oracle Primavera P6, by contrast, the Retained Logic schedule setting automatically adjusts for activities completed out of sequence.  Thus, the need to finish CP1 before proceeding with CP3 is already included.  The result is a (presumably more realistic) 2-day delay in completion compared to the MSP result.

In-Progress, Out-of-Sequence Tasks

Key issues arise when the out-of-sequence task and its predecessor are both incomplete.  Because this behavior is sometimes different for MSP 2016 than it is for MSP 2010, we’ll look at both versions for the remaining examples.

For exploring the behavior of in-progress, out-of-sequence tasks, we examine the simple project schedule below.  The schedule is comprised of a single start milestone, a single finish milestone, a “Critical Path” string of four tasks, and a “Slack Path” string of four tasks.  The “Slack Path” is two days shorter than the “Critical Path,” with the last two tasks each having a shorter duration.  There is an unachievable Deadline applied to the finish milestone, and this creates negative Total Slack on the Critical Path.  Thus, the Critical Path tasks all have TS=-1d, and the Slack Path tasks have TS=1d.

With no progress, the project is scheduled identically in both versions of MSP.  Notably, P6 also starts with the same schedule dates.

Now let’s examine what happens when we record an out-of-sequence Actual Start on some future task.  In the example, the last task in each string (CP4 and SP4) is given an Actual Start that is one day earlier than its predecessors allow.  To keep things simple, no progress beyond the actual starts are recorded (i.e. %Complete = 0%.)  I’ve kept the “Split in-progress tasks” scheduling option checked (per default), so re-scheduling the project creates an initial split in tasks CP4 and SP4 and delays their remaining parts to satisfy the predecessor relationships.  As a result, all the tasks keep the same finish dates as before, and the project finishes on the same date as before, one day after the Deadline.

Although their start and finish dates have not changed, the logic-related information of the predecessors of the OOS tasks have been altered substantially.

  1. In both MSP 2010 and MSP 2016:
  • The Total Slack values of the Critical Path tasks that precede the OOS task (i.e. tasks CP1, CP2, and CP3) are all changed from TS=-1d to TS=0d.
  • This behavior is not justified: if the tasks are all executed according to the scheduled dates, the project will still finish one day late. The tasks should still have TS=-1d.
  • This is in fact a general result (see also Comment 1): (Presumably for MSP 2007 through MSP 365), any super-critical (TS < 0) task with an out-of-sequence, in-progress task in its successor chain will automatically have its Total Slack re-set to zero. Thus, out-of-sequence progress can cause a task with 60 days of negative Total Slack to appear much less Critical than it is.
  • This behavior can present a problem for project managers operating in a negative-slack (i.e. behind-schedule) regime, where schedule-recovery efforts are typically prioritized based on Total Slack values. Entering a single OOS Actual Start value (whether correct or not), can substantially alter the overall schedule recovery picture.
  • It seems most MSP users pay no attention to Total Slack values beyond the application of the “Critical” flag, and the observed behavior doesn’t change that. Consequently, for most users up through MSP 2010, out-of-sequence progress appears to have no substantial impact on the “Critical Path.”
  1. In MSP 2016, in addition to the prior behavior:
    • In the example, the Total Slack values of the Slack Path tasks that precede the OOS task (i.e. tasks SP1, SP2, and SP3) are all changed from TS=1d to TS=0d.
    • This behavior is also not justified. The tasks could all be delayed one day from their scheduled dates without compromising the project’s completion Deadline.  The tasks should still have TS=1d.
    • This is also a general result (see also Comment 1): (presumably for MSP 365 and maybe MSP 2013), ANY task (Critical or non-Critical) with an out-of-sequence, in-progress task in its successor chain will automatically have its Total Slack re-set to zero. Consequently, it will automatically and unavoidably be flagged as a Critical task.
    • For general MSP users after MSP 2010, therefore, out-of-sequence progress can have a substantial, even major, impact. In particular, tasks that are actually far from the Critical Path may be incorrectly flagged as Critical.
  2. The results in Oracle P6, however, appear more realistic.  The Late dates and corresponding Float values are unchanged from the initial schedule.

Below I’ve shown another perhaps more realistic example of the same simple project.  There has been a simple progress update on the Status Date of 1Oct’18, four working days into the project.  As of that date (the first Monday in the project), tasks CP1 and SP1 are still in-progress and have fallen one day behind the original plan.  Their successors (CP2 and SP2) have been allowed to start early, however, with each recording one day of actual progress.

Similar logical results are observed.  Task CP1 – the Critical predecessor of the Critical OOS task CP2 – now has TS=0d instead of TS=-1d in both software versions, and its Critical flag remains unchanged.

In MSP 2016 only, task SP1 – the non-critical predecessor of the non-critical OOS task SP2 – now also has TS=0d and is flagged as Critical.  This is incorrect.

As before, however, the late dates and Float values in the P6 version of the schedule are aligned with expectations.

Out-of-Sequence Progress and Task Path Driving Predecessors in MSP 2016

The “Task Path” bar styles provide useful methods for identifying related tasks, including the Driving Predecessors path, for any selected task in MSP 2013+.  The Driving Predecessors Task Path is particularly useful for confirming the Critical Path of a project when Total Slack is complicated by other factors.  Unfortunately, the method is not successful when out-of-sequence progress is encountered.  As shown in the figure below – repeating the two previous examples in MSP 2016 – the Driving Predecessors Task Path (orange-colored bars) is terminated when an Actual Start is reached on the backward (right-to-left) pass.  Thus, driving Task Path functionality is not compatible with out-of-sequence progress.

[The Task Path functionality is equally incompatible with in-progress schedules that involve Finish-to-Finish relationships among overlapping tasks, even if none of the progress occurs out of sequence.  Any Actual Start value terminates the progression of the associated bar formatting flag.]

Out-of-Sequence Progress and BPC Logic Filter

The impacts of out-of-sequence progress on the Total Slack of some tasks are the result of specific decisions in MSP’s backward-pass algorithms for computing Late dates and Total Slack.  Obviously, the algorithm has been tweaked between MSP 2010 and MSP 2016 leading to the even more undesired results.

BPC Logic Filter – my company’s MSP add-in for logic analysis – generally ignores MSP’s Deadlines, Late dates, Actual dates, and Total Slack values.  Instead, it performs separate backward and forward traces to determine driving logic paths and relative float values.  The latter, like Free Float, can never be negative.  Thus, when BPC Logic Filter encounters out-of-sequence progress during a trace, zero relative float is applied, and a driving relationship is inferred.  As shown in the examples below, this approach results in the correct identification of driving and near-driving paths to project completion, even when out-of-sequence progress is encountered.  [In the bar charts, the path relative float is listed to the right of each bar.  A zero-value represents the driving path with the bar characteristically colored (maroon), positive values and associated bar colors indicate the number of days away from driving the project completion.  

BPC Logic Filter also includes a Project Logic Checker to identify logic issues in Microsoft Project tasks.  Like many such tools, it automatically flags OOS tasks, along with their immediate predecessors, for correction. (Beginning with release, 1.5.5.5, the tool also differentiates the important categories of OOS tasks.  The “-I” suffix in the bar chart below identifies out-of-sequence conditions where both predecessor and successor of the violated relationship remain Incomplete; total slack in such cases cannot be trusted.)

In addition, the Logic Inspector in BPC Logic Filter automatically flags tasks with out-of-sequence progress as well as all the relationships that are violated by such progress.  Here it is shown that the out-of-sequence progress on task SP2 violates its predecessor relationship with SP1.  The late dates and total slack of the predecessor (SP1) are incorrect.

Out-of-Sequence Progress in the Real World

This examination was prompted by an associate who, after a recent “upgrade” from MSP 2007 to MSP 2016, encountered numerous unexplained changes in the “Critical Path” during project updating.  As it turned out, the updated schedule contained extensive out-of-sequence progress that explained the observed behavior.  The out-of-sequence progress was the result of a schedule model that was ultimately invalid – a poor representation of the work, either as planned or as actually executed.  As is often the case in construction, this was aggravated by the persistent executive schedule pressure that converts some technological restraints (e.g. don’t start interior finishes until the building roof and skin are closed up) from mandatory requirements into mere preferences.

A typical invalid schedule model involves the representation of multiple overlapping activities as an over-simplified Finish-to-Start string.  For example, the schedule below shows five sequentially-related, non-critical tasks, of roughly equivalent work content, that are scheduled to occur over a five-week period.  Although they are shown sequentially, it is in fact customary to execute these five tasks nearly concurrently, with each task commencing as soon as its predecessor’s progress allows – and thereafter suspending or pacing progress to match that of its predecessors.

[Some schedule purists would suggest that these tasks should be broken down into many small, repetitive work packages, all arranged with pure Finish-to-Start logic relationships.  The resulting schedule is extremely detailed and reflects a true logical plan for executing the work.  In my experience, however, such a detailed plan can often be riddled with preferential logic that is ultimately over-ruled by field decisions.  Out-of-sequence progress – in spades – is the inevitable result; the scheduling workload multiplies with no added value.

Another approach might involve five parallel tasks, each of five weeks duration, modeled with continuous relationships or at the very least with compound (joint SS + FF) relationships.  Unfortunately, neither relationship is supported by MSP.  The dummy-milestone approach that I use to mimic compound relationships in MSP seems fairly esoteric, and the common alternative – using solely SS or FF relationships – can be problematic.]

The scheduler here has chosen the most expedient route, a simplified Finish-to-Start string of five activities.  Four weekly updates of actual progress then lead to the progressed schedule shown at the bottom of the figure.  While its appearance is substantially changed compared to the original plan, the progressed schedule – in MSP 2010 – seems to correctly depict the status and slack of the multiple in-progress, out-of-sequence tasks.  Thus MSP 2010 seems largely indifferent to the consequences of invalid logic combined with out-of-sequence progress, as long as the affected tasks are non-critical.

As my associate discovered, however, MSP 2016 is far less tolerant of such practices.  When the progressed schedule is recalculated in MSP 2016, the in-progress predecessors of the in-progress, out-of-sequence tasks are shown as Critical (with TS=0).  This is incorrect, as the tasks could all slip by 15 days without delaying the project.

For comparison, here are the corresponding updates for the identical project schedule in Oracle P6 (R18.8.10).  The dates and Float values are identical to those for MSP 2010; they are correct for these non-critical tasks.  (Original and Actual Durations in P6 are handled differently than in MSP, so those are not comparable.)

Review and Recommendations

Out-of-sequence progress is an unwelcome but often unavoidable occurrence in projects with logic-driven schedules.  It happens when the actual project execution is allowed to deviate from the plan in a way that creates logical conflict in the automatic scheduling calculations.  It typically results from a combination of the following circumstances:

  1. The schedule plan includes logic relationships that are not technologically mandatory. I.e. there are a number of alternative methods available for sequencing a group of related activities, and only one (preferred) method is incorporated into the schedule.  In addition:
    • Procedural controls are inadequate to ensure that project execution conforms to the preferred logic sequence; or
    • Subsequent to initial schedule development, the preferred logic sequence is altered due to field conditions, resource limitations, or other factors.
  2. Subsequent to initial schedule development, technologically-mandatory logical constraints are allowed to be violated – typically under schedule performance pressure – and the resulting technical risks are accepted.
  3. The schedule is based on scope and logic definitions that are overly simplified compared to the actual or achievable plan of execution. E.g. simple Finish-to-Start relationships are used to represent overlapping, partly-concurrent activities.
  4. Subsequent to occurrence of any of the prior circumstances, the schedule logic is not revised appropriately.
  5. Schedule updates do not include regular review and correction of invalid logic in light of out-of-sequence progress.

In MSP, a task that is both started and completed out-of-sequence may cause the incomplete tasks in its predecessor and/or successor chains to become effectively open-ended, with impacts on Early and Late dates, Total Slack, and Critical task definition.  Consequently, the updated schedule may be invalid.

A task that is started out-of-sequence but remains in progress may cause substantial alterations to the Late dates, Total Slack, and Critical definitions of the incomplete tasks in its predecessor chains.  In particular:

  1. (In all modern MSP versions) Total Slack of behind-schedule tasks will change from negative to zero and in some cases turn positive. [See also comment 1.] Although the Critical flag won’t always change, any identification of driving and driven logic paths that is based on negative Total Slack will be incorrect.
  2. (In recent versions – e.g. MSP 2016) Total Slack of non-Critical tasks will change from positive to zero (with some exceptions), and each task will be incorrectly marked as Critical. [See also comment 1.]  Thus, the “Critical Path” and any other Slack-based identification of driving or driven logic paths will be incorrect.

These are pretty major consequences, yet their persistence suggests that they reflect as-designed behavior, not bugs.  It might even be suggested that the most recent “improvements” are intended to highlight the out-of-sequence progress – for correction of the associated logic.

In MSP, the only reliable way to avoid the negative consequences of out-of-sequence progress, in my opinion, is to avoid and/or minimize its occurrence.  Fundamentally, this means:

  1. Ensure that project schedules are based on sound consideration of the scope and logic of project execution.
  2. Ensure that procedural controls are put into place to a) validate, b) revise where necessary, and c) enforce the preferred sequence of activities.
  3. Where necessary, revise the schedule logic to reflect the actual/required sequence of execution.
  4. During regular progress updates, identify all out of sequence progress, and revise associated logic as appropriate to avoid the consequences noted above.

 

Macro for Filtering based on “Task Path” in Microsoft Project

Here in the TaskPathFilters module, I provide five simple macros for applying a filter (or table highlighting) that corresponds to Task Path bar highlighting output.

For users of Microsoft Project 2013+, including the desktop versions of Project for Office 365, the Task Path bar styles provide a useful method for highlighting logical connections between tasks.  Four different sets of bar styles can be created, corresponding to the Predecessors, Driving Predecessors, Successors, and Driven Successors of the selected task.  Unfortunately, the “show for…” criteria used to apply the bar styles are not available for creating a filtered display of tasks – say the driving path to a key milestone – while hiding the non-driving tasks.

[The “driving” and “driven” Task Paths are defined (by MSP) using the task StartDriver object, the same as in the Task Inspector.  As shown here, StartDriver has proven unreliable in identifying driving logic in the presence of non-FS relationships, actual progress, splits, and resource leveling.

In another blog entry here, you can find a set of macros for duplicating the results of the Task Path bars, with the added benefit of being able to re-sort tasks according to logic flow, so concurrent logic paths are easily separated.  Those macros use the same underlying data as Task Paths, so their results should be identical to these.  Unlike these, they can be used in versions of MSP prior to 2013.]

Here’s the code (requires MSP 2013+).

Note, for real logic analysis, have a look at BPC Logic Filter.

'TaskPathFilters Module
'This module includes five procedures to mark tasks according to their TaskPath
'characteristics.  A sixth procedure applies a filter to display only the marked tasks.
'The module is intended only for users of Microsoft Project 2013+, which incorporates TaskPath
'formatting of task bars.  If the applicable TaskPath formatting has not been applied,
'then no filter will be created.  VBA code developed by TMBoyle, 14Sep'18
'   1. Install all code into a new module, with "TaskPathFilters Module" above as the top line.
'   2. Assign buttons or hotkeys to the first five procedures only (the other one is called by these):
        'a. AllTaskPathFilter() - Filters all the marked task paths.
        'b. TaskPathPredecessorFilter() - Filters the marked "predecessors" of the selected task.
        'c. TaskPathDrivingPredecessorFilter() - Filters the marked "driving predecessors" of the selected task.
        'd. TaskPathSuccessorFilter() - Filters the marked "successors" of the selected task.
        'e. TaskPathDrivenSuccessorFilter() - Filters the marked "driven successors" of the selected task.
'
Public MsgBase As String, Tsel As Task
Sub AllTaskPathFilter()
    Dim t As Task
    Dim Apply As Boolean
    
    Set Tsel = ActiveCell.Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            If (t.PathPredecessor = True) Or (t.PathDrivingPredecessor = True) Or _
                (t.PathSuccessor = True) Or (t.PathDrivenSuccessor = True) Then
                t.Marked = True
                Apply = True
            Else
                t.Marked = False
            End If
        End If
    Next t
    Tsel.Marked = "Yes"
    If Apply Then
        MarkedFilter
        MsgBox (MsgBase & "All Selected for task " & vbCrLf & _
            Tsel.ID & " - " & Tsel.Name)
    Else
        MsgBox "No Filter Applied."
    End If
End Sub
Sub TaskPathPredecessorFilter()
    Dim t As Task
    Dim Apply As Boolean
    
    Set Tsel = ActiveCell.Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            If t.PathPredecessor = True Then
                t.Marked = True
                Apply = True
            Else
                t.Marked = False
            End If
        End If
    Next t
    Tsel.Marked = "Yes"
    If Apply Then
        MarkedFilter
        MsgBox (MsgBase & "Predecessors of task " & vbCrLf & _
            Tsel.ID & " - " & Tsel.Name)
    Else
        MsgBox "No Filter Applied."
    End If
End Sub

Sub TaskPathDrivingPredecessorFilter()
    Dim t As Task
    Dim Apply As Boolean
    
    Set Tsel = ActiveCell.Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            If t.PathDrivingPredecessor = True Then
                t.Marked = True
                Apply = True
            Else
                t.Marked = False
            End If
        End If
    Next t
    Tsel.Marked = "Yes"
    If Apply Then
        MarkedFilter
        MsgBox (MsgBase & "Driving Predecessors of task " & vbCrLf & _
            Tsel.ID & " - " & Tsel.Name)
    Else
        MsgBox "No Filter Applied."
    End If
End Sub

Sub TaskPathSuccessorFilter()
    Dim t As Task
    Dim Apply As Boolean
    
    Set Tsel = ActiveCell.Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            If t.PathSuccessor = True Then
                t.Marked = True
                Apply = True
            Else
                t.Marked = False
            End If
        End If
    Next t
    Tsel.Marked = "Yes"
    If Apply Then
        MarkedFilter
        MsgBox (MsgBase & "Successors of task " & vbCrLf & _
            Tsel.ID & " - " & Tsel.Name)
    Else
        MsgBox "No Filter Applied."
    End If
End Sub

Sub TaskPathDrivenSuccessorFilter()
    Dim t As Task
    Dim Apply As Boolean
    
    Set Tsel = ActiveCell.Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            If t.PathDrivenSuccessor = True Then
                t.Marked = True
                Apply = True
            Else
                t.Marked = False
            End If
        End If
    Next t
    Tsel.Marked = "Yes"
    If Apply Then
        MarkedFilter
        MsgBox (MsgBase & "Driven Successors of task " & vbCrLf & _
            Tsel.ID & " - " & Tsel.Name)
    Else
        MsgBox "No Filter Applied."
    End If
End Sub

Sub MarkedFilter()
Dim HL As Boolean

    If MsgBox("Apply Highlighting Only?", vbYesNo) = vbYes Then
        HL = True
        MsgBase = "Highlighting TaskPath "
    Else
        MsgBase = "Filtered for TaskPath "
    End If
    On Error Resume Next
    FilterApply Name:="Marked Tasks", Highlight:=HL
    If Err.Number <> 0 Then
        FilterEdit Name:="Marked Tasks", TaskFilter:=True, Create:=True, OverwriteExisting:=True, _
           FieldName:="Marked", Test:="equals", Value:="Yes", ShowInMenu:=True, ShowSummaryTasks:=True
        FilterApply Name:="Marked Tasks", Highlight:=HL
    End If
    EditGoTo ID:=Tsel.ID
End Sub


Why I Left LinkedIn Groups

LinkedIn Groups are dead to me.  Today I removed my membership in all 22 Groups that I had joined since creating my LinkedIn account nearly 13 years ago.  For a long while during those 13 years, Groups seemed to provide the main forums for interesting discussions on project management topics, and a few web boards that had previously hosted those discussions became comparatively barren as a result.  Over the last several years, however, Groups have transformed from discussion forums into bazaars crowded with hawkers.  They’ve now become too noisy to stay and listen.

Here is a list of Groups’ problems that I’ve been mulling over the last 12 months or so:

  1. Barrage Marketing. I.e. >90% of thread initiators in some groups are links to external content, and there are few good discussions.  (One notable exception is the FIDIC Contracts group, which has a lot of active participants and seems to be extraordinarily well curated.  I’ll miss that one.)
  2. No retention of information. (Short memory and no search).  If you stumble upon or participate in a particularly edifying Group discussion – one that you may want to refer to later – don’t expect LinkedIn to archive it for you.  If it’s worth saving, copy and save it yourself.
  3. Classic Silos / Fragmentation of Discussion on common topics.  Whether asking a new and interesting question, sharing a Pulse article, or looking to drive traffic to an external website, thread-starters routinely cross-post the same entry to multiple groups.  (One day I encountered the same entry in eight or nine different groups.)  The scattered and disjointed comments that result can hardly be called discussions.
  4. Sloppy/repetitive discourse.  This is on the users.  E.g. ignoring all previous comments while simply repeating them.  Failure to “listen” before speaking. (There is no rational motivation for this.)
  5. Comments hierarchy.  The organization (i.e. grouping and sorting) of LinkedIn comments seems to vary depending on the client platform (e.g. mobile or desktop) and LinkedIn source (e.g. Group discussion, Pulse article, or Share).  Most of my interactions have been in Group discussions on a computer, where comments have been arranged (until recently) in flat chronological order.
  6. It’s difficult or impossible to filter views to see only “new” comments (i.e. since my last visit) or even “recent” comments (i.e. within the last day).  The “New conversations” control is not valid.
  7. Outright deletion of valid content by LI – e.g. truncation of discussions (while still leaving them open for further comments).  Deja vu!
  8. The last straw: it seems the September 2018 update to Groups has simply amplified all the negatives above.  Clicking a “Group” today reveals a simple stream of graphics-heavy linked content and ads for my consumption, hardly distinguishable from a Facebook or Twitter feed.  LinkedIn Groups is no longer a place to converse.  I’m done.

Relationship Free Float and Float Paths in Multi-Calendar Projects (P6 MFP Free Float Option)

This is a short article about the calculation and use of Relationship Free Float in Oracle Primavera P6, a project scheduling tool.  [It amends my previous entry on Total Float and Free Float Options in P6’s Multiple Float Path Analysis.  Both articles are further expanded (and corrected) by the technical paper presented at the 2020 Annual Meeting of AACE International.  An alternate version of the paper is hosted on our website.]

[The following few paragraphs are cribbed (with some edits to reflect improved understanding) from my own contribution to a discussion on Planning Planet a few years ago.]

Traditional notions of Total Float and Free Float are tied to the activities in the network, but they are not sufficient for evaluating logical float paths in complex CPM schedules, especially when variable calendars and/or late constraints are imposed.  Relationship floats are needed for identifying near-driving relationships and for multiple-float-path analyses.

Documentation seems very sketchy, but based on my own observations I believe relationship floats in P6 are calculated similarly to activity floats – that is

  1. The early and late dates of relationships are computed by treating them as activities (with single FS+0 links at each end) in the forward and backward passes through the network (Duration equals lag, normally zero).
  2. Relationship total float (RelTF) = relationship late finish (RelLF)  –  relationship early finish (RelEF); 
  3. Relationship free float (RelFF) = (Early Date of Relationship Successor Activity, ES for “FS” and “SS” links, EF for “FF” and “SF” links) – RelEF

The calendars used for the calculations seem to be as follows:

  • Early dates use predecessor calendar (from the forward pass)
  • Late dates use successor calendar (from the backward pass)
  • Relationship free float and total float use the predecessor calendar.

[Apr’19 Edit: Relationship Successor Total Float and Relationship Successor Free Float are derived from the same relationship dates, but using the successor calendar rather than the predecessor calendar.  (Figures now show both measures of relationship free float.)]

With multiple calendars, the driving and near driving paths revealed by Multiple Float Path (MFP) analysis are only partly correlated to the Relationship Free Float (and Relationship Successor Free Float) values displayed by P6.  These may require careful scrutiny to avoid misinterpretation in complex, multi-calendar projects, for the following reasons:

a) A relationship is “driving” when the successor activity possesses zero working time between the lag-adjusted predecessor and successor dates.  That is, the Relationship Free Float – according to the SUCCESSOR’s calendar (“Relationship Successor Free Float”) – is zero.

b) The Relationship Free Float that P6 displays (and that P6 appears to use as the primary path-allocation parameter for Float Paths >1, using the “Free Float” option) is computed according to the PREDECESSOR’s calendar.

Consider the simple schedule illustrated below, wherein the “Assembly” activity has three predecessors whose calendars differ from Assembly’s.  Assembly utilizes a standard 5-day calendar, while Machining 1 and Machining 2 are performed using automated equipment on a 7×24 calendar.  The Assembly Plan must be prepared during a weekly resource coordination meeting that only happens on Thursdays.

As the figure shows, the Longest Path (red bars) is comprised of the two Machining activities (finishing 12 hours apart) followed by Assembly.  As expected, both machining activities are marked as driving predecessors (there is zero relationship free float for either one according to Assembly’s calendar), and the Assembly Plan predecessor relationship is marked as non-driving.

P6’s MFP algorithm (Free Float option) allocates the three predecessors of the Assembly activity to three different Float Paths:

Float Path 1 (“most critical path”):  Machining 2, a driving predecessor, with Relationship Free Float (according to its own calendar) of 1.5 days.

Float Path 2 (“1st sub-critical path”): Assembly Plan, a non-driving predecessor, with Relationship Free Float (according to its own calendar) of 0.0 days.

Float Path 3 (“2nd sub-critical path”): Machining 1, a driving predecessor, with Relationship Free Float (according to its own calendar) of 2.0 days.

This is what the P6 Help file says for the MFP Free Float option.

Free Float – Choose this option to define critical float paths based on longest path. The most critical path will be identical to the critical path that is derived when you choose to define critical activities as Longest Path in the General tab. In a multicalendar project, the longest path is calculated by identifying the activities that have an early finish equal to the latest calculated early finish for the project and tracing all driving relationships for those activities back to the project start date. After the most critical path is identified, the module will calculate the remaining sub-critical paths.

Unfortunately, the underlined portion is not consistent with the observed behavior, where the Longest Path (i.e. the driving path to project completion) is divided between Float Paths 1 and 3.

Now we modify the schedule to give both machining activities exactly the same duration (2.5 days on a 7×24 calendar), so they both finish at 8:00 PM on Saturday.  They remain driving activities for Assembly and also have exactly the same Relationship Free Float (1.5d).  But now they trade Float Paths: Machining 1 is now on Float Path 1, while Machining 2 is on Float Path 3.

After restoring the original machining schedule (finishing 12 hours apart on Saturday), now we assign a different calendar to the one that finishes first – Machining 1 is now on a 6×24 calendar, with Sunday no longer a workday.  Consequently, the Machining 1 relationship now possesses only 1.0 days of Relationship Free Float, 0.5 days less than the Machining 2 relationship.  Nevertheless, Machining 2 stays on Float Path 1, while Machining 1 is still relegated to Float Path 3.

Several tentative conclusions seem apparent from these observations:

  1. For Float Path 1 only, the Float Path is allocated to the driving predecessor which is satisfied the latest of all the driving predecessors – without regard to Relationship Free Float.  Each of the remaining predecessors will be allocated to a new (higher-numbered) Float Path.
  2. If two or more driving predecessors finish at exactly the same time, then only one of them – selected by Activity ID, Activity Name, or some other non-logic-related criteria [Early Start, then Activity ID according to others] – will be assigned to Float Path 1.
  3. For Float Paths >1, the current Float Path is allocated to the remaining predecessor (driving or not) with the lowest Relationship Free Float of all remaining predecessors.  Each of the other remaining predecessors will be allocated to a new (higher-numbered) Float Path.  As  a consequence, legitimate members of the project’s Longest Path may be relegated to non-contiguous float paths far from the “most critical” Float Path 1.   (The fact that driving predecessors are NOT prioritized is an unfortunate weakness, in my opinion, of an otherwise robust logic analysis method.)

I’ve reviewed a number of P6 schedule submittals that seem to confirm these observations in addition to a few more:

  1. For Float Paths >1, if the remaining predecessors are driving AND have the same Relationship Free Float, then the current Float Path is allocated to the remaining predecessor that finishes latest.  Each of the other remaining predecessors will be allocated to a new (higher-numbered) Float Path.
  2. Consequently, in case of parallel driving paths, FF predecessors will be preferred (i.e. be allocated to lower-numbered Float Paths) over FS predecessors.
  3. [According to a paper first presented by Mssrs Roger Nelson and Patrick Kelly at the 2018 Annual Meeting of AACE International, and later presented at the AACE SoCal chapter meeting on 19Apr’19, the next two “tie-breakers” for path assignment are the latest Early Start date and, finally, the Activity ID.]
  4. In most cases, an ALAP-constrained predecessor automatically creates a parallel (and false) driving path with Relationship Free Float = 0.  Extensive use of ALAP constraints can lead to a proliferation of false Float Paths in the MFP results.

[Dec’20 Note:  These conclusions were tentative and reflected a relatively shallow appreciation (in July’18) of the underlying calculations.  In particular, the different rules for seeding and tracing of float paths – and the consequent impact on schedules with misaligned calendars, as shown here – had not yet presented themselves.   To learn more, have a look at the AACE paper and presentation noted earlier.]

How to Filter for Leads and Lags in Microsoft Project

Here are two macro procedures – LagFilter and LeadFilter – for creating and applying a filter to show only tasks with leads or lags above a certain threshold value.

Using Lags and/or Leads (i.e. negative lags) in Project Scheduling is discouraged for good reasons.  In most project scheduling software it is easy to identify violations by creating a filter to show only tasks with Lags (or Leads) in their predecessor relationships.

In Microsoft Project, lags are indicated by the presence of a “+” character in the task’s predecessors field.  Here is the corresponding filter specification.

You can augment the filter to show tasks on both sides of the lags:

Leads are indicated (in MSP) by the presence of a “-” character in the task’s predecessors field.  Here is the corresponding filter specification (showing both sides of the leads).

Unfortunately, these simple filters don’t help to differentiate high-lag/lead relationships from low-lag/lead relationships.  All of them are lumped together in the same filter.  It is possible to create filters for only the highest lead/lag values using a number of custom fields with complex formulas.  It is far simpler, however, to create the necessary filters using vba/macros.

Here are two macro procedures – LagFilter and LeadFilter – for creating and applying a filter to show only tasks with leads or lags above a certain threshold value.  Choosing a zero-value threshold leads to the same results as the simple filters above.  These procedures work by examining the lag of each predecessor relationship of every task in the active project, comparing it to the specified threshold value.  If the lag is high enough, then the Flag6 field of the task will be set to “yes”.  At the end, a new filter is made and applied.  Note that these macros will overwrite any values in the Flag6 field of your project, unless Flag6 is already controlled by a formula.  (In that case, the macros will crash with an error.)  You may need to edit the macros to select a different Flag field.

[I’ve edited these macros… a) to allow the user to select whether to show both sides or only one side (the successor) of each lead/lag; b) to avoid null filters (i.e. blank screens) by applying the filter only when leads or lags matching the criterion are found; and c) to allow work-time, elapsed-time, or percentage-based lead/lag criteria.]

To apply these, simply copy and paste them into a new module in your Project Visual Basic editor (VBE).  (I typically keep these modules in the global.mpt file, though that practice is not always recommended.)  You can then run them directly from the VBE or from custom buttons that you link to the macros through the  “Customize the Ribbon” dialog.

Sub LagFilter()
'Copyright 15August2018 by T.Boyle PE, PSP
'This macro collects user input and filters the active project to display only tasks
'with dependency lags that are less than the user-specified threshold.  The threshold
'may be specified in units of working time, elapsed time, or percentage.  The filter
'is applied using the Flag6 custom field.
'FLAG6 WILL BE OVER-WRITTEN, IF POSSIBLE,OR THIS MACRO WILL CRASH.

    Dim t As Task
    Dim d As TaskDependency
    Dim LagUnits As String
    Dim ElapsedUnits As Boolean
    Dim LagThreshold As Double
    Dim LagLimit As String
    Dim SuccsOnly As Boolean
    Dim Filtername As String
    Dim Found As Boolean
    
    Found = False
    'Get lag units from user
    LagUnits = (InputBox("Enter lag units (m,h,d,w,mo,em,eh,ed,ew,emo,%):"))
    'Validate units
    Select Case LagUnits
        Case "m", "h", "d", "w", "mo", "em", "eh", "ed", "ew", "emo", "%"
            'Get the filter limit from user
            LagThreshold = (InputBox("Enter lag threshold (" & LagUnits & "):"))
            LagLimit = LagThreshold & " " & LagUnits
            If Left(LagUnits, 1) = "e" Then ElapsedUnits = True
        Case Else
            MsgBox ("Invalid lag units entered (case-sensitive). Aborting.")
            Exit Sub
    End Select
    'Convert units
    Select Case LagUnits
        Case "m"
            'proceed
        Case "h"
            LagThreshold = LagThreshold * 60
        Case "d"
            LagThreshold = LagThreshold * 60 * ActiveProject.HoursPerDay
        Case "w"
            LagThreshold = LagThreshold * 60 * ActiveProject.HoursPerWeek
        Case "mo"
            LagThreshold = LagThreshold * 60 * ActiveProject.HoursPerDay * ActiveProject.DaysPerMonth
        Case "em"
            'proceed
        Case "eh"
            LagThreshold = LagThreshold * 60
        Case "ed"
            LagThreshold = LagThreshold * 60 * 24
        Case "ew"
            LagThreshold = LagThreshold * 60 * 24 * 7
        Case "emo"
            LagThreshold = LagThreshold * 60 * 24 * 30
        Case "%"
            'proceed
    End Select
    
    If MsgBox("Display both Predecessors and Successors?" & vbCrLf & "(""Yes"" shows each lag twice. Default " _
            & "shows Successors Only)", vbQuestion + vbYesNo + vbDefaultButton2, "???") = vbYes Then
        SuccsOnly = False
        Filtername = "HasLagsAboveThreshold"
    Else
        SuccsOnly = True
        Filtername = "HasPredecessorLagsAboveThreshold"
    End If
    
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            Call ClearT(t)
            For Each d In t.TaskDependencies
                If (d.To = t) Or (SuccsOnly = False) Then
                    If (d.Lag > 0 And LagThreshold = 0) Or (d.Lag >= LagThreshold And LagThreshold > 0) Then
                            If (d.LagType = 19 And LagUnits = "%") Then
                                Call MarkT(t, Found)
                            ElseIf (d.LagType Mod 2 = 1 And (Not ElapsedUnits) And (LagUnits <> "%")) Then
                                Call MarkT(t, Found)
                            ElseIf (d.LagType Mod 2 = 0 And ElapsedUnits) Then
                                Call MarkT(t, Found)
                            End If
                    End If
                End If
            Next d
        End If
    Next t
    
    If Found Then
        FilterEdit Name:=Filtername, TaskFilter:=True, Create:=True, OverwriteExisting:=True, FieldName:="Flag6", _
            Test:="equals", Value:="Yes", ShowInMenu:=True, ShowSummaryTasks:=True
        FilterApply Name:=Filtername
        MsgBox ("Filter applied: " & Filtername & vbCrLf & "Filter Threshold: " & LagLimit)
    Else
        MsgBox ("No lags found above threshold (" & LagLimit & "). No filter applied")
    End If

End Sub

Sub LeadFilter()
'Copyright 15August2018 by T.Boyle PE, PSP
'This macro collects user input and filters the active project to display only tasks
'with dependency leads (i.e. negative lags) that are less than the user-specified threshold.
'The threshold may be specified in units of working time, elapsed time, or percentage.
'The filter is applied using the Flag6 custom field.
'FLAG6 WILL BE OVER-WRITTEN, IF POSSIBLE,OR THIS MACRO WILL CRASH.

    Dim t As Task
    Dim d As TaskDependency
    Dim LeadUnits As String
    Dim ElapsedUnits As Boolean
    Dim LeadThreshold As Double
    Dim LeadLimit As String
    Dim SuccsOnly As Boolean
    Dim Filtername As String
    Dim Found As Boolean
    
    Found = False
    'Get Lead units from user
    LeadUnits = (InputBox("Enter Lead units (m,h,d,w,mo,em,eh,ed,ew,emo,%):"))
    'Validate units
    Select Case LeadUnits
        Case "m", "h", "d", "w", "mo", "em", "eh", "ed", "ew", "emo", "%"
            'Get the filter limit from user
            LeadThreshold = (InputBox("Enter Lead threshold (" & LeadUnits & "):"))
            LeadLimit = LeadThreshold & " " & LeadUnits
            If Left(LeadUnits, 1) = "e" Then ElapsedUnits = True
        Case Else
            MsgBox ("Invalid Lead units entered (case-sensitive). Aborting.")
            Exit Sub
    End Select
    'Convert units
    Select Case LeadUnits
        Case "m"
            'proceed
        Case "h"
            LeadThreshold = LeadThreshold * 60
        Case "d"
            LeadThreshold = LeadThreshold * 60 * ActiveProject.HoursPerDay
        Case "w"
            LeadThreshold = LeadThreshold * 60 * ActiveProject.HoursPerWeek
        Case "mo"
            LeadThreshold = LeadThreshold * 60 * ActiveProject.HoursPerDay * ActiveProject.DaysPerMonth
        Case "em"
            'proceed
        Case "eh"
            LeadThreshold = LeadThreshold * 60
        Case "ed"
            LeadThreshold = LeadThreshold * 60 * 24
        Case "ew"
            LeadThreshold = LeadThreshold * 60 * 24 * 7
        Case "emo"
            LeadThreshold = LeadThreshold * 60 * 24 * 30
        Case "%"
            'proceed
    End Select
    
    If MsgBox("Display both Predecessors and Successors?" & vbCrLf & "(""Yes"" shows each Lead twice. Default " _
            & "shows Successors Only)", vbQuestion + vbYesNo + vbDefaultButton2, "???") = vbYes Then
        SuccsOnly = False
        Filtername = "HasLeadsAboveThreshold"
    Else
        SuccsOnly = True
        Filtername = "HasPredecessorLeadsAboveThreshold"
    End If
    
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            Call ClearT(t)
            For Each d In t.TaskDependencies
                If (d.To = t) Or (SuccsOnly = False) Then
                    If (d.Lag < 0 And LeadThreshold = 0) Or (d.Lag <= -1 * LeadThreshold And LeadThreshold > 0) Then
                            If (d.LagType = 19 And LeadUnits = "%") Then
                                Call MarkT(t, Found)
                            ElseIf (d.LagType Mod 2 = 1 And (Not ElapsedUnits) And (LeadUnits <> "%")) Then
                                Call MarkT(t, Found)
                            ElseIf (d.LagType Mod 2 = 0 And ElapsedUnits) Then
                                Call MarkT(t, Found)
                            End If
                    End If
                End If
            Next d
        End If
    Next t
    
    If Found Then
        FilterEdit Name:=Filtername, TaskFilter:=True, Create:=True, OverwriteExisting:=True, FieldName:="Flag6", _
            Test:="equals", Value:="Yes", ShowInMenu:=True, ShowSummaryTasks:=True
        FilterApply Name:=Filtername
        MsgBox ("Filter applied: " & Filtername & vbCrLf & "Filter Threshold: " & LeadLimit)
    Else
        MsgBox ("No Leads found above threshold (" & LeadLimit & "). No filter applied")
    End If

End Sub

Sub ClearT(t As Task)
    t.Flag6 = "No"
End Sub
Sub MarkT(ByRef t As Task, ByRef Found As Boolean)
    t.Flag6 = "Yes"
    Found = True
End Sub

Neither the simple filter nor the macro provided here implements the algorithm used by the Project Logic Checker in our BPC Logic Filter Add-In, which incorporates a slightly different premise.  That is: a relationship (or combination of relationships) with (positive or negative) lag may be the most effective and efficient method for modeling the true sequential restraints of the work, but only when the lag represents a relatively small proportion of the durations of the related tasks.  Thus, the Project Logic Checker flags tasks where the relationship lead/lag exceeds a certain percentage of the associated task durations.

BPC Logic Filter in Microsoft Project 2013/2016

During its development, we targeted BPC Logic Filter – our Add-In for analyzing project schedules – for use with Microsoft Project (MSP) 2010.  After all, we developed the Add-In essentially for our own use, and MSP 2010 has been a regular tool for us (in Windows 7 boxes) since its inception.  Our most recent computer purchase brought with it necessary upgrades to 2016 versions of MS Office and MSP, all running the 64-bit flavor on a Windows 10 Workstation.

Now that I’ve had a chance to directly test BPC Logic Filter in an MSP 2016 environment, I must apologize to those users of our software who have suffered in silence with their MSP 2016 (and also MSP 2013) installations.  My initial testing experience with the filter functions was horribly slow, and I was finally able to repeat some crashing behavior – not encountered in MSP 2010 – that had been reported by a lone user.  No wonder the representative feedback from users on MSP 2013 and 2016 has been, love the Task Logic Inspector! (but silent on the other stuff).

With recent updates, we’ve managed to speed up the filter functions while completely eliminating the particular crashing issue.  As a result, with bar-coloring disabled, the new machine can complete a comprehensive Near-Longest Path Filter of a typical ~1000-task schedule in under 8 seconds.  This compares to an 11-second analysis of the same schedule on the old machine; I attribute the improvement primarily to the increased processing speed of the new machine.

Bar-coloring, however, remains sub optimal.  This is already time-consuming – manipulating Gantt bars and bar styles using essentially “foreground” processes.   As a result, the time to generate our comprehensive Near-Longest Path Filter on the old (MSP 2010) machine increases from 11 seconds to 33 seconds when bar-coloring with auto-ranging is selected.  Such an increase is justified by the improved communication that bar coloring allows.  Unfortunately, the time to perform the same task on the new (MSP 2016) machine increased from 8 seconds to 46 seconds, even after our optimizations and adjustments.  I would expect users with slower computers to have much worse experience.  It seems that manipulating graphic display objects involves substantially more processing power in MSP 2016 than in MSP 2010.  This is ironic in light of the general degradation in graphical output beginning with MSP 2013.  Unfortunately, we have not yet found a way around this problem.

Finally, there seems to be a bug in MSP 2016’s handling of the GanttBarFormat method when a) the method originates in a VSTO (Visual Studio Tools for Office) Add-In rather rather than in a native VBA (Visual Basic for Applications) procedure; and b) there is actual progress on the task.  (The GanttBarFormat method is used to apply format exceptions to a particular bar style of a particular task; like right-clicking on a bar and choosing “format bar”.)  Unfortunately, MSP 2016 ignores the selected bar style and applies the exception to the “Task Progress” bar if one exists.  This makes for some odd-looking outputs from our Add-In for schedules showing actual progress.  I’ll have to figure out a way to raise this issue and get it fixed.

Understand the Impact of Calendars on Schedule Slack Calculation in Microsoft Project

The most recent build of BPC Logic Filter includes improved calculation of relative floats for tasks whose Resource Calendars are substantially different from the effective Task and Project Calendars.  While reviewing those improvements, I compiled this summary of the three different Calendar types used in Microsoft Project (MSP) schedules – with particular attention to their use in logic-driven scheduling and Slack calculation.  The summary moves from the simplest (Project Calendar only) to the most complex (combined Task and Resource calendars) case.  The conclusions are based on my own (imperfect) testing in MSP Professional 2010 and 2016 environments, and I’d welcome any corrections.

Dale Howard of Sensei Project Solutions has provided an excellent general examination of Calendars in Microsoft Project.  It may prove useful to review his post before proceeding.

A. Project Calendar

  1. The Project Calendar is used to schedule all tasks in a project IN THE ABSENCE OF OTHER CALENDARS.  When present, Task Calendars supersede all of the Project Calendar’s functions, and Resource Calendars supersede some – but not all – of the Project Calendar’s functions.
  2. Without Task or Resource Calendars, each task’s early start date occurs when all logic constraints have been satisfied and the Project Calendar makes work time available.  The task’s early finish occurs when the assigned duration has been fully expended according to the Project calendar.
  3. Relationship lags are computed according to the Project Calendar.
  4. Start Slack, Finish Slack, and Total Slack are computed using the Project Calendar.
  5. The default calendar for ProjDateAdd, ProjDateSub, and ProjDateDiff functions is the Project Calendar.*
  6. Because only a single calendar is involved in all schedule calculations, Total Slack may be a reliable indicator of Critical Path within a single project schedule.
  7. If two projects with different project calendars are joined together with inter-project dependencies, then the interaction of working periods between linked tasks can cause Total Slack to vary along a single driving logic path.

B. Project Calendar PLUS Resource Calendars

  1. Each Resource possesses a unique Resource Calendar, which is comprised of a Base Calendar with specific modifications/exceptions.  For example, the Base Calendar for all resources in a particular country may include standard weekends and holidays for that country.  These are inherited by the Resource Calendar, while exceptions may be applied for specific Resource vacations.  By default, the Base Calendar is the Project Calendar at the time the resource is created.  An alternate Base Calendar can be assigned afterward.  The Resource Calendar has the same name as the Resource.
  2. When one or more resources are assigned to a task, the task is scheduled according to a) predecessor and successor logic, including lags; and b) the available working times in the Resource Calendars.  The task’s early start date occurs when all logic constraints have been satisfied and at least one assigned resource has available work-time.  The task’s early finish date occurs when the last resource assignment is completed – AND for Fixed-duration tasks with positive duration, the specified duration has been expended.  For tasks that are not of type “Fixed Duration,” the Duration is the sum of all the intervals (from start to finish) during which at least one resource is working.  Thus, a task with multiple resources (each with a unique calendar) may have a Duration and Start/Finish dates that do not directly correspond to ANY single defined Calendar.  For Fixed-Duration tasks, the Duration is the difference between the early start and early finish as computed using the Project Calendar.  Thus, a Fixed-Duration task with 12-hours of work by a night-shift resource can have a Duration of Zero, based on the Project’s Standard calendar.  Moreover, a Fixed-Duration task with a specified duration of 2 days and 16 hours of work by a weekend-working resource may start on Saturday (when the resource is available) and not be completed until Tuesday evening, when its specified duration has been expended according to the project calendar.  During the backward pass, Late dates are established similarly, based on (resource) working-time calendars.
  3. Relationship lags are computed using the Project Calendar.
  4. Start Slack, Finish Slack, and Total Slack are computed using the Project Calendar.
  5. The default calendar for ProjDateAdd, ProjDateSub, and ProjDateDiff functions used in custom Task fields remains the Project Calendar.  When used in custom Resource fields, the default calendar for these functions is the Resource’s Base Calendar, which is often the Project Calendar.*
  6. Since a resource calendar may delay a task from starting work during an available work period as defined in the Project Calendar, the task’s driving predecessor may possess slack.  Thus, Total Slack can vary along a single driving logic path.

C. Project Calendar PLUS Task Calendars (No Resource Calendars OR “Ignore Resource Calendars” Selected)

  1. A task calendar may be created and assigned to multiple tasks.  Each Task Calendar is a Base Calendar that may be created by copying and modifying an existing Base Calendar.  (Because it is a base calendar itself, a task calendar does not inherit information from other calendars.)
  2. Task Calendars may be used to refine schedule constraints based on the nature of the tasks being performed.  E.g. seasonal or environmental limitations.  Task Calendars may also be used to represent resource restrictions when no resources have been assigned (e.g. a year-end non-work period for certain tasks in a master/summary schedule.)  When “Ignore Resource Calendars” is checked, then assigned Resources will be compelled to work exactly according to the Task Calendar, possibly violating their own work time availability.
  3. Without effective Resource restrictions, the task’s early start date occurs when all logic constraints have been satisfied and the Task Calendar makes work time available.  The task’s early finish occurs when the assigned duration has been fully expended according to the Task Calendar.
  4. Relationship lags are computed according to the Task Calendar of the successor task, if it has one, or the Project Calendar.
  5. Start Slack, Finish Slack, and Total Slack for each task are computed using the Task Calendar, if it has one, or the Project Calendar.
  6. The default calendar for ProjDateAdd, ProjDateSub, and ProjDateDiff functions used in custom Task fields is the Task Calendar, if one exists, or the Project Calendar.*
  7. The interval between a driving predecessor and a driven successor may possess work time according to the predecessor’s calendar but not the successor’s.  The driving predecessor may possess slack.  Thus, Total Slack can vary along a single driving logic path.

D. Elapsed-Durations

  1. For most practical purposes, specifying a task duration using an “elapsed” unit (edays, for example), is essentially the same as: a) Applying a 24-hour task calendar with “ignore resource calendars” selected; AND b) Assigning a duration value that accounts for the project’s hours-per-day, hours-per-week, and days-per-month settings.  For example, 1 elapsed day is the same as 24 hours or 3 “days” (8-hours each) applied to a 24-hour working calendar.  (Since mixing duration “days” with 24-hour calendars routinely causes confusion, it is good practice to instead specify such durations in hours.)
  2. Any task with an elapsed duration will have the Task Calendar field disabled.  (A stored value may be visible, but it is inactive as long as the duration units are elapsed.)
  3. Since elapsed-duration tasks automatically ignore resource calendars, any assigned Resources will be compelled to work 100% without rest, possibly violating their own work time availability.  Consequently, it’s not a good idea to routinely apply elapsed durations together with resource loading.  Even machines need downtime for maintenance.
  4. Without effective Resource restrictions, the task’s early start date occurs when all logic constraints have been satisfied, period.  The task’s early finish occurs when the elapsed duration has been fully expended.
  5. Non-elapsed relationship lags are computed according to the Task Calendar of the successor task, if it has one, or the Project Calendar.
  6. Start Slack, Finish Slack, and Total Slack for each elapsed-duration task are computed on the basis of elapsed time.
  7. For tasks with elapsed durations, the default calendar for ProjDateAdd, ProjDateSub, and ProjDateDiff functions used in custom Task fields is the 24-Hour Calendar.*
  8. The interval between an elapsed-duration predecessor and its driven (non-elapsed) successor may possess non-working time according to the successor’s effective calendar (task, resource, or project).  The driving predecessor may possess slack.  Thus, Total Slack can vary along a single driving logic path.

E. Project Calendar PLUS Task Calendars PLUS Resource Calendars (NOT “Ignored”)

If the task’s “Ignore Resource Calendars” box is NOT checked, then:

  1. Each task is scheduled only during work time that is available in BOTH the Task Calendar and the applicable Resource Calendar for each assignment.
  2. The task’s early start date occurs when all logic constraints have been satisfied,  the Task Calendar makes work time available, AND at least one assigned resource has available work time.  The task’s early finish occurs when the last assignment is completed within the combined work time restrictions.
  3. Relationship lags are computed according to the Task Calendar of the successor task, if it has one, or the Project Calendar.
  4. Start Slack, Finish Slack, and Total Slack are computed using the Task Calendar, if any, or the Project Calendar.
  5. The default calendar for ProjDateAdd, ProjDateSub, and ProjDateDiff functions used in custom Task fields remains the Task Calendar, if one exists, or the Project Calendar.  When used in custom Resource fields, the default calendar for these functions remains the Resource’s Base Calendar.*
  6. As a result of either resource-delays or task calendar mismatches, Total Slack can vary along a single driving logic path.

*  Note: The comparable Project VBA functions (Application.) DateAdd, DateSubtract, and DateDifference always default to the Project Calendar of the ActiveProject.

F. Slack and Calendars Re-Cap

In general, the Project Calendar of a fully resource-loaded project schedule plays no direct role in the calculation of the Early and Late dates, but it plays a primary role in MSP’s subsequent calculation of Slack based on those dates.  Conversely, although resource calendars can fundamentally alter the logic-driven dates of a typical resource-loaded task, MSP ignores them in the Slack calculation.  As a consequence, both the calculation and interpretation of Total Slack in a resource-loaded schedule become greatly simplified, if sometimes misleading.

Alternately, whenever a task calendar is applied (with or without resource-loading), that same calendar is used to calculate the Dates AND the Slack.  Consequently, the calculation of Total Slack seems to be more correct and can be equally simple to calculate (using a Task- rather than Project-Calendar), but its interpretation can be confusing.

For example, the chart below illustrates two alternate methods for modeling a calendar-restricted Board-approval activity in a project schedule.  The Board meets on the third Wednesday of each month for, among other items, approving key project commitments.  If the project team fails to prepare the necessary documents in sufficient time for the meeting, then the approvals (and follow-on tasks) will be delayed by a month.  (This is exactly how project governance works in some organizations.)  For this example, the board-approval, preparation, and follow-up activities are not on the Critical Path for the project, finishing up about a month before the project’s finish milestone.

In the first case, the restraint on the Board Approval task is modeled by applying a Task Calendar with only the third Wednesday of each month as a working day.  In the second case, the restraint is modeled by loading a “Board Availability” resource whose Base Calendar is exactly the same as the Task Calendar applied above.  Early Dates and Late Dates for all tasks are identical for both cases, and the only difference is the Total Slack of the Board Approval task.  This value is computed as the difference between the task’s Late Finish (17Apr’19) and its Early Finish (20Mar’19).  When the restraint is applied using the Task Calendar, the Total Slack of 1 day reflects the fact that one Board Meeting/availability day exists between the two dates.  With the restraint applied using a resource calendar, the Project Calendar applies, and Total Slack of 20 days reflects the twenty weekdays between the two dates.

In either case, the example also illustrates the difficulty of identifying logic paths using Total Slack alone.

G. A Note on the Resource Availability Grid

The Resource Availability Grid (part of the Resource Information dialog window) is sometimes seen as an alternate/supplemental method for specifying resource working time.  Unlike the Resource Calendar, however, Resource Availability entries do not participate in the working-time definitions that drive the scheduling calculations.  Rather, they serve as a time-phased version of the Max Units property for identifying over-allocation of resources.  Once flagged, MSP can attempt to resolve these over-allocations through automatic resource-leveling.  This is distinct from logic-driven scheduling.