Simple Macro for Imposing Zero Free Float Constraints in Microsoft Project

Here I outline a method – including the ImposeZFF macro – to provide “just-in-time” scheduling of flagged tasks in MSP.  I also include a separate macro, RemoveZFF, to restore the tasks to as-soon-as-possible scheduling.

Another missing feature for anyone coming to MSP from Primavera’s planning tools is the “Zero Free Float (ZFF)” constraint.  (Primavera now calls this the “As Late as Possible (ALAP)” constraint – NEVER to be confused with MSP’s identically-named version, which is pretty useless for forward scheduling.)  The ZFF constraint delays an activity as much as possible without impacting any successor activities.  It is useful for scheduling just-in-time works and deliveries while preserving the correct logic flow through the project schedule.

Consider the simple project shown here.  The overall project completion is limited by a constraint on task B.  (I never use such mandatory constraints in practice but use it here to avoid having to add other extraneous logic to the example.)  Task A must be completed before B, but for maximum efficiency it is desired to perform this work just-in-time.  Because MSP has no other obvious feature to arrive at the desired schedule outcome, the scheduler is tempted to make task A a Start-to-Finish successor of B.  Such an approach is unsound and is to be avoided for a number of reasons.  All links in a logic-driven project schedule must reflect real logical constraints, and real Start-to-Finish constraints are extremely rare.

ZFF1a

So what is the scheduler to do?  Most situations are easily solved by adding logical milestones to the project schedule.  For example, a logic-driven “Site Ready for Delivery” milestone as a Finish-to-Finish predecessor of “Eqpt Delivery” would be quite normal.  In the very few occasions when suitable logical workarounds cannot be devised, then it may be useful to impose early-start constraints to achieve the zero-free-float objectives.  For good control over the process, I use a custom flag field to designate specific tasks requiring ZFF constraints.  Then I run a macro that automatically computes and assigns the appropriate constraint to all the ZFF tasks in the project at once.  This makes ZFF constraints easy to audit, review, and justify.

For our simple project example, I inserted the Flag20 local field into the Gantt Chart entry table and called it ZFF.  Then I marked task A with the ZFF flag and ran the macro.  The macro automatically imposed a new early-start constraint on the task.  As a result, the 12 days of Total Slack (like the 12 days of Free Slack) that previously existed have been consumed.  Task A is now correctly shown as Critical.ZFF2a

If your project has a logical chain of tasks that are all ZFF-flagged, then you’ll have to re-run the macro several times (or add a simple iteration loop to the code.  I have one but didn’t include it here for simplicity.)

[May 2019 Edit: Though I don’t use this macro, one user has reminded me that when used to delay a string of connected tasks, selecting the tasks in reverse order may be more efficient than the forward order first included in this article.  I.e. use the “For i…” block shown here in place of the “For each t” block originally included.  I might get around to modifying that code eventually.]

    Dim i As Long
    For i = ActiveProject.Tasks.Count To 1 Step -1
        Set t = ActiveProject.Tasks(i)
        If Not t Is Nothing Then

            'If t.GetField(Application.FieldNameToFieldConstant(FieldName))....
               '...
               '...
             End If  
        End If
    Next i

 

The code for imposing the constraints is shown below.  Drop it into a VBA module in your Global.mpt file (or in a specific .mpp file if necessary), then look for and run macro “ZFFImpose”.  I normally use another function to find the ZFF flag field in a project, but that function was too big to include here.  So if you want to use a custom flag field other than Flag20, just change the “FieldName = “Flag20″” statement in the code.

Sub ZFFImpose()
' Macro Coded 31-08-16 by Thomas Boyle PE PSP PMP.
On Error GoTo 0
    
    Dim i As Integer
    Dim t As Task
    Dim L1 As String
    Dim L2 As String
    Dim SW1 As Boolean
    Dim SW2 As Boolean
    Dim SW3 As Boolean
    Dim FieldName As String
    
    'FieldName = FindField_Flag("ZFF") 'Function not included here
    Fieldname="Flag20"
    If FieldName = "" Then
        MsgBox Prompt:="No ZFF Flag Field Found", Title:="ZeroFreeFloat Constraints"
        Exit Sub
    End If
                
    CalculateProject

        For Each t In ActiveProject.Tasks
            If Not t Is Nothing Then
                If t.GetField(Application.FieldNameToFieldConstant(FieldName)) = "Yes" Then
                    If t.FreeSlack > 0 Then
                        t.ConstraintType = pjSNET
                        If t.Calendar = "None" Then
                            t.ConstraintDate = Application.DateAdd(t.Start, t.FreeSlack)
                        Else
                            t.ConstraintDate = Application.DateAdd(t.Start, t.FreeSlack, t.CalendarObject)
                        End If
                        CalculateProject
                        L1 = L1 & t.ID & " " & t.Name & " " & t.ConstraintDate & vbCrLf
                        SW1 = True
                    Else
                        L2 = L2 & t.ID & " " & t.Name & vbCrLf
                        SW2 = True
                    End If
                End If
            End If
        Next t
    GoTo Finish

tEHandler:
    MsgBox ("Failed to impose Zero Free Float Constraints")
    Exit Sub
    
Finish:
    CalculateProject
    If SW1 = True Then MsgBox Prompt:="Imposed Early Start Constraints to remove free float:" & vbCrLf & L1, Title:="ZeroFreeFloat Constraints"
    If SW2 = True Then MsgBox Prompt:="No free float to remove on tasks: " & vbCrLf & L2, Title:="ZeroFreeFloat Constraints"
    If SW1 = False And SW2 = False Then MsgBox Prompt:="No tasks marked for ZFF", Title:="ZeroFreeFloat Constraints"
    
End Sub

What is done with the “ZFFImpose” macro is easily undone with the “ZFFRemove” macro shown below.  This macro returns all ZFF-flagged tasks to “As Early As Possible” scheduling.

Sub ZFFRemove()
' Macro Coded 31-08-16 10:30 by Thomas Boyle PE PSP PMP.
On Error GoTo 0
    
    Dim t As Task
    Dim L1 As String
    Dim SW1 As Boolean
    Dim FieldName As String
    
    FieldName = "Flag20"
    'FieldName = FindField_Flag("ZFF")
    If FieldName = "" Then
        MsgBox Prompt:="No ZFF Flag Field Found", Title:="ZeroFreeFloat Constraints"
        Exit Sub
    End If
                
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            If t.GetField(Application.FieldNameToFieldConstant(FieldName)) = "Yes" Then
                If t.ConstraintType = pjSNET Then
                    t.ConstraintType = pjASAP
                    CalculateProject
                    L1 = L1 & t.ID & " " & t.Name & vbCrLf
                    SW1 = True
                End If
            End If
        End If
    Next t
    GoTo Finish

tEHandler:
    MsgBox ("Failed to remove Zero Free Float Constraints")
    Exit Sub
    
Finish:
    CalculateAll
    If SW1 = True Then MsgBox Prompt:="Removed Early Start Constraints from designated ZFF tasks:" & vbCrLf & L1, Title:="ZeroFreeFloat Constraints"
    If SW1 = False Then MsgBox Prompt:="No tasks marked for ZFF", Title:="ZeroFreeFloat Constraints"
End Sub

 

2 thoughts on “Simple Macro for Imposing Zero Free Float Constraints in Microsoft Project”

  1. Hello Tom!

    Its embarassing that im writing to you in 2020 on an issue that is there from 1998 but here we are.

    Im a project planner in charge of a project with about 3000 lines and the project plan is used for financial planning and EVM reporting. All of the bells and whistles, so to speak.

    I and even my management are getting pretty frustrated since from the beginning of the project we have stumbled upon ms project constraints way too often than we would like. Still, having primavera floating licenses is not an option.

    Anyways, what i wanted to ask is this: why in your opinion it is better to use a milestone with a finish to finish constraint instead of a SF constraint to a task that follows both?

    For me the macro is nice but i guess since it uses the “start not sooner than” functionality – then i wouldnt be able to use it for other purposes and i don’t want to limit myself now.

    Kind regards,
    Alexander
    Antwerp, Belgium

    1. Hi Alexander. Thanks for the comment. I don’t fully grasp your proposal to use SF relationship with a milestone, but here’s what I can say: 1) If it could be guaranteed that a milestone always remains a milestone (i.e. zero duration), then its start and finish would always be identical, and there would be no effective difference between SF and FF successor relationships. In MSP, however, no such guarantee can be made – sloppy and/or deceptive status updating practices routinely lead to different start and finish dates for “milestones.” Since here (i.e. “ready for delivery”) only its finish matters, only an FF successor is valid. 2) Looking at the A-B-C example of the article, the novice scheduler is tempted to schedule A just-in-time using B->SF->A. The SF restraint dictates solely that A may not finish before B starts, but what is the impact on B if A is delayed by a month? NONE!, which is clearly wrong. In this case the true logic relationship (FS) between A and B has been sacrificed to just-in-time date manipulation, and total slack throughout the network is unreliable or incorrect! There is a similar discussion of the issue at http://www.planningplanet.com/forums/microsoft-project/691256/alap-constraint-behavior-question. Of course, for those who don’t care about such issues, there is still the frustration of having the just-in-time activity finishing at the start of a day.

Leave a Reply to Tom Boyle Cancel reply

Your email address will not be published.