diff --git a/CatiaNetTest/AndOrDataExtraction.vb b/CatiaNetTest/AndOrDataExtraction.vb
index ce6bec4f319946779e1300d8152b21a7d4c8e921..c0b1e046abef1884107f2a77c5a3001054c1d66e 100644
--- a/CatiaNetTest/AndOrDataExtraction.vb
+++ b/CatiaNetTest/AndOrDataExtraction.vb
@@ -79,9 +79,11 @@ Public Class AndOrDataExtraction
             Dim l2 As Integer = prt(1).Count
             'Check both subassemblies for connectedness
             If SubassemblyIsConnected(prt(0)) = False Then
+                Debug.Print("First subassembly not connected!")
                 Continue For
             End If
             If SubassemblyIsConnected(prt(1)) = False Then
+                Debug.Print("Second subassembly not connected!")
                 Continue For
             End If
             'Check whether disassembly is possible by checking for
@@ -130,6 +132,8 @@ Public Class AndOrDataExtraction
                     nodes.Add(prt(1))
                     AndOrGraph(prt(1), nodes)
                 End If
+            Else
+                Debug.Print("No feasible assembly directions found!")
             End If
         Next
 
@@ -288,7 +292,7 @@ Public Class AndOrDataExtraction
         For i = 0 To cRelevantProducts.Count - 1
 
             '########## this won't work if part document name is not = part number ######
-            ''Dim partI As Part
+            'Dim partI As Part
             Dim prodI As Product
             prodI = cRelevantProducts.Item(i)
             Dim docName As String
diff --git a/CatiaNetTest/AssemblyTiers2.vb b/CatiaNetTest/AssemblyTiers2.vb
index cb54f91d2f3f3f38dbac3301948abe0db8938c94..1ab43c67e075eaacfe6713adaffc64c79f208f51 100644
--- a/CatiaNetTest/AssemblyTiers2.vb
+++ b/CatiaNetTest/AssemblyTiers2.vb
@@ -10,6 +10,7 @@ Imports Microsoft.Office.Interop.Excel
 
 Public Class AssemblyTiers2
 
+    Public bCoherenceCheck As Boolean
     Public intStep As Integer
     Public dCollSens As Double
     Public intParts As Integer
@@ -23,6 +24,7 @@ Public Class AssemblyTiers2
     Public aAssemblyBoundaries(5) As Double
     Public aPartBBGlob(,) As Double
     Public aInitPos(,) As Double
+    Public liaisonMatrix(,) As Integer
     Public sChosenDirection As String
     Public oList As Object
     Public CATIA As INFITF.Application
@@ -170,10 +172,11 @@ Public Class AssemblyTiers2
         Debug.Print("Number of faces in assembly: " & CStr(intNumFaces))
 
         'Collision parameters
-        Dim dGeomMean As Double
-        dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
-        dGeomMean = dGeomMean ^ (1 / 3)
-        intStep = Math.Round(dGeomMean / 50, 0)
+        'Dim dGeomMean As Double
+        'dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
+        'dGeomMean = dGeomMean ^ (1 / 3)
+        'intStep = Math.Round(dGeomMean / 50, 0)
+        intStep = 13
         Debug.Print("Movement step: " & CStr(intStep))
 
         dCollSens = 2
@@ -221,6 +224,18 @@ Public Class AssemblyTiers2
         Dim bInitPosRecorded(cRelevantProducts.Count - 1) As Boolean
         Dim bDeactivated(cRelevantProducts.Count - 1) As Boolean
 
+        'Before trying to remove a component, check whether it would break liaison graph coherence / connectedness
+        bCoherenceCheck = True
+        Dim coherenceCheckNodeIndices As New List(Of Integer)
+        If bCoherenceCheck Then
+            Dim componentIndex As Integer
+            componentIndex = 0
+            For Each oComponent In cRelevantProducts
+                coherenceCheckNodeIndices.Add(componentIndex)
+                componentIndex = componentIndex + 1
+            Next oComponent
+        End If
+
         intI = cRelevantProducts.Count - 1   'the index of base components will be simply skipped (cRelevantProducts includes cBaseProducts, unlike in the paper!)
         intJ = 6                          'number of disassembly directions (6 - only global axes, 12 - including local axes)
         intTier = 1                       'counts current disassembly tier (lower number means earlier disassembly possible) - this gets reversed in the end
@@ -256,6 +271,11 @@ Public Class AssemblyTiers2
         Dim StartTime As DateTime
         StartTime = Now
 
+        'Liaison graph extraction for coherence checks
+        If bCoherenceCheck Then
+            Liaison()
+        End If
+
         Do
 
             'Processing next Product
@@ -269,6 +289,32 @@ Public Class AssemblyTiers2
                 GoTo entry0
             End If
 
+            If bCoherenceCheck Then
+                'If a component is allowed to be moved, check whether removing it will break up the coherence of product liaison graph
+                'Remove int_i from index list
+                Dim listIndex As Integer
+                listIndex = 0
+                For Each partIndex In coherenceCheckNodeIndices
+                    If partIndex = int_i Then
+                        Exit For
+                    Else
+                        listIndex = listIndex + 1
+                    End If
+                Next
+                coherenceCheckNodeIndices.RemoveAt(listIndex)
+                'Check whether all node of LG can be visited from any other node (= connected graph)
+                If SubassemblyIsConnected(coherenceCheckNodeIndices) Then
+                    'Put int_i back at listIndex
+                    coherenceCheckNodeIndices.Insert(listIndex, int_i)
+                Else
+                    'If coherence will be broken, skip this component
+                    Debug.Print("Removing " & product1.Name & " would violate liaison graph coherence!")
+                    'Put int_i back at listIndex
+                    coherenceCheckNodeIndices.Insert(listIndex, int_i)
+                    GoTo exit2
+                End If
+            End If
+
             'Remember initial position P_i (initPos)
             Dim initPos(11)
             Dim oPosition1 As Object
@@ -293,9 +339,9 @@ Public Class AssemblyTiers2
             Dim iStaticProduct As Integer
             For iStaticProduct = 0 To cRelevantProducts.Count - 1
                 If iStaticProduct <> int_i And Not bDeactivated(iStaticProduct) Then
-                    If BoundingBoxesOverlap(int_i, iStaticProduct) Then
-                        group2.AddExplicit(cRelevantProducts.Item(iStaticProduct))
-                    End If
+                    'If BoundingBoxesOverlap(int_i, iStaticProduct) Then
+                    group2.AddExplicit(cRelevantProducts.Item(iStaticProduct))
+                    'End If
                 End If
             Next iStaticProduct
 
@@ -361,7 +407,7 @@ entry1:
                                         'if the disassembly tier is 1 lower (attention: tiers get reversed in the end to the assembly tiers!)
                                         If secTier = intTier - 1 And Not (secTier = 0 And intTier = 1) Then
 
-                                            Debug.Print("Collision with higher tier: " & oConflict1.FirstProduct.Name & " - " & oConflict1.SecondProduct.Name & " = " & oConflict1.Value)
+                                            'Debug.Print("Collision with higher tier: " & oConflict1.FirstProduct.Name & " - " & oConflict1.SecondProduct.Name & " = " & oConflict1.Value)
 
                                             'record precedence relation, because secProduct is an obstacle in the way of the current product
                                             precedenceMatrix(int_i, iIndex) = 1
@@ -392,6 +438,21 @@ exit1:
                             'all directions were checked
                             total_coll = total_coll + intJ
                             Debug.Print("Disassembly trials: " & total_coll)
+                            'if this component can be disassembled, remove its index from coherence check list
+                            If bCoherenceCheck And productHasValidDisassDir(int_i, disassDir) Then
+                                Dim listInd As Integer
+                                listInd = 0
+                                For Each partIndex In coherenceCheckNodeIndices
+                                    If partIndex = int_i Then
+                                        Exit For
+                                    Else
+                                        listInd = listInd + 1
+                                    End If
+                                Next partIndex
+                                'Remove int_i from index list (only after all directions were checked)
+                                coherenceCheckNodeIndices.RemoveAt(listInd)
+                            End If
+exit2:
                             int_i = int_i + 1
                             int_i_cycle = int_i_cycle + 1
                             int_j = 0
@@ -794,7 +855,114 @@ exitCD:
         End If
 
     End Function
+    Sub Liaison()
+
+        Dim n As Integer = cRelevantProducts.Count
+
+        ReDim liaisonMatrix(n - 1, n - 1)
+
+        'access the clash technology object
+        Dim cClashes As Clashes
+        cClashes = CATIA.ActiveDocument.Product.GetTechnologicalObject("Clashes")
+        'access the groups technology object
+        Dim cGroups As Groups
+        cGroups = CATIA.ActiveDocument.Product.GetTechnologicalObject("Groups")
+
+        'Clash analysis between all products (clash type = contact)
+        Dim int_i, int_j As Integer
+        For int_i = 1 To cRelevantProducts.Count
+            For int_j = 1 To cRelevantProducts.Count
+                If int_j > int_i Then 'only need one half of the combinations
+                    Dim group1 As Group
+                    Dim group2 As Group
+                    group1 = cGroups.Add
+                    group2 = cGroups.Add
+                    group1.AddExplicit(cRelevantProducts.Item(int_i - 1))
+                    group2.AddExplicit(cRelevantProducts.Item(int_j - 1))
+                    'create a new clash analysis
+                    Dim oClash As Clash
+                    oClash = cClashes.Add
+                    oClash.ComputationType = CatClashComputationType.catClashComputationTypeBetweenTwo
+                    oClash.FirstGroup = group1
+                    oClash.SecondGroup = group2
+                    oClash.InterferenceType = CatClashInterferenceType.catClashInterferenceTypeContact
+                    oClash.Compute()
+                    Dim cConflicts As Conflicts
+                    cConflicts = oClash.Conflicts
+                    If cConflicts.Count > 0 Then
+                        'For each contact, write 1 in the spreadsheet
+                        'The matrix is symmetric and 0-diagonal
+                        liaisonMatrix(int_i - 1, int_j - 1) = 1
+                        liaisonMatrix(int_j - 1, int_i - 1) = 1
+                    Else
+                        liaisonMatrix(int_i - 1, int_j - 1) = 0
+                        liaisonMatrix(int_j - 1, int_i - 1) = 0
+                    End If
+                ElseIf int_j = int_i Then
+                    liaisonMatrix(int_i - 1, int_j - 1) = 0
+                End If
+            Next int_j
+        Next int_i
+
+    End Sub
+
+    Function SubassemblyIsConnected(prt As List(Of Integer)) As Boolean
+
+        'List of visited nodes
+        Dim visitedNodes As New List(Of Boolean)
+        Dim prtCount As Integer = prt.Count
+        For x = 0 To prtCount - 1
+            visitedNodes.Add(False)
+        Next
+
+        'Submatrix of liaison adjacency matrix that contains only the nodes of this subassembly
+        Dim liaisonSubmatrix(,) As Integer
+        ReDim liaisonSubmatrix(prtCount, prtCount)
+        For m = 0 To prtCount - 1
+            For k = 0 To prtCount - 1
+                liaisonSubmatrix(m, k) = liaisonMatrix(prt(m), prt(k))
+            Next
+        Next
+
+        'Depth-first search to explore the liaison subgraph from the first node
+        DFS(liaisonSubmatrix, visitedNodes, 0)
+
+        'Check whether all nodes could be visited via liaison connections
+        For i = 0 To prtCount - 1
+            If visitedNodes(i) = False Then
+                Return False
+            End If
+        Next
+
+        Return True
+
+    End Function
+
+    Sub DFS(liaisonSubmatrix(,) As Integer, visitedNodes As List(Of Boolean), v As Integer)
+        'Depth-first search
+
+        If visitedNodes(v) = True Then
+            Exit Sub
+        End If
+
+        visitedNodes(v) = True
 
+        'Neighbors of v
+        Dim neighbors As New List(Of Integer)
+        For i = 0 To visitedNodes.Count - 1
+            If liaisonSubmatrix(v, i) = 1 Then
+                neighbors.Add(i)
+            End If
+        Next
+
+        'Do DFS on all neighbor nodes if they were not visited
+        For Each u In neighbors
+            If visitedNodes(u) = False Then
+                DFS(liaisonSubmatrix, visitedNodes, u)
+            End If
+        Next
+
+    End Sub
     Function DeactivateFasteners(objProduct As Product)
 
         Dim objParts As New ArrayList
@@ -1550,7 +1718,7 @@ exitCD:
                 If oConflict.Type = SPATypeLib.CatConflictType.catConflictTypeClash Then
                     If oConflict.Value < -dCollSens Then
                         collisionDetected = True
-                        Debug.Print("Clash detected: " & oConflict.FirstProduct.Name & " - " & oConflict.SecondProduct.Name & " = " & oConflict.Value)
+                        'Debug.Print("Clash detected: " & oConflict.FirstProduct.Name & " - " & oConflict.SecondProduct.Name & " = " & oConflict.Value)
                         Exit For
                     End If
                 End If
diff --git a/CatiaNetTest/HierarchicalAssemblyTiers.vb b/CatiaNetTest/HierarchicalAssemblyTiers.vb
index a6dab04571715d2babb81a514eb056f3b946cb5e..ac763d0145119196f15c774b1412cf8553941c5e 100644
--- a/CatiaNetTest/HierarchicalAssemblyTiers.vb
+++ b/CatiaNetTest/HierarchicalAssemblyTiers.vb
@@ -139,7 +139,7 @@ Public Class HierarchicalAssemblyTiers
             For j = 0 To cElements.Count - 1
 
                 '########## this won't work if part document name is not = part number ######
-                ''Dim partI As Part
+                'Dim partI As Part
                 Dim prodI As Product
                 prodI = cElements.Item(j)
                 Dim docName As String
@@ -181,10 +181,11 @@ Public Class HierarchicalAssemblyTiers
         Debug.Print("Number of faces in assembly: " & CStr(intNumFaces))
 
         'Collision parameters
-        Dim dGeomMean As Double
-        dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
-        dGeomMean = dGeomMean ^ (1 / 3)
-        intStep = Math.Round(dGeomMean / 50, 0)
+        'Dim dGeomMean As Double
+        'dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
+        'dGeomMean = dGeomMean ^ (1 / 3)
+        'intStep = Math.Round(dGeomMean / 50, 0)
+        intStep = 54
         Debug.Print("Movement step: " & CStr(intStep))
 
         dCollSens = 2
@@ -727,9 +728,12 @@ exitCD:
         'Once we are done on this level, generate precedence diagrams for each subassembly recursively
         Dim subassembly As Product
         For Each subassembly In cRelevantProducts
-            Dim leafProducts As New ArrayList
-            ExtractProducts(subassembly, leafProducts)
-            If leafProducts.Count > 5 Then
+            'Dim leafProducts As New ArrayList
+            'ExtractProducts(subassembly, leafProducts)
+            'If leafProducts.Count > 5 Then
+            '    AssemblyTiersDetermination(subassembly)
+            'End If
+            If subassembly.Products.Count > 5 Then
                 AssemblyTiersDetermination(subassembly)
             End If
         Next subassembly
diff --git a/CatiaNetTest/bin/Debug/CatiaNetTest.exe b/CatiaNetTest/bin/Debug/CatiaNetTest.exe
index 6831f4de9d7aa37f0171ea57245af57abe0e8f20..e09982ee09f61a910f46adf8c13a9e2a75aef273 100644
Binary files a/CatiaNetTest/bin/Debug/CatiaNetTest.exe and b/CatiaNetTest/bin/Debug/CatiaNetTest.exe differ
diff --git a/CatiaNetTest/bin/Debug/CatiaNetTest.pdb b/CatiaNetTest/bin/Debug/CatiaNetTest.pdb
index 8a459496ce726433a93890ed6461cd883cd898ae..10b8f13e3bd8bf2e5bad681d59d90b83f5d5131a 100644
Binary files a/CatiaNetTest/bin/Debug/CatiaNetTest.pdb and b/CatiaNetTest/bin/Debug/CatiaNetTest.pdb differ
diff --git a/CatiaNetTest/obj/Debug/CatiaNetTest.exe b/CatiaNetTest/obj/Debug/CatiaNetTest.exe
index 6831f4de9d7aa37f0171ea57245af57abe0e8f20..e09982ee09f61a910f46adf8c13a9e2a75aef273 100644
Binary files a/CatiaNetTest/obj/Debug/CatiaNetTest.exe and b/CatiaNetTest/obj/Debug/CatiaNetTest.exe differ
diff --git a/CatiaNetTest/obj/Debug/CatiaNetTest.pdb b/CatiaNetTest/obj/Debug/CatiaNetTest.pdb
index 8a459496ce726433a93890ed6461cd883cd898ae..10b8f13e3bd8bf2e5bad681d59d90b83f5d5131a 100644
Binary files a/CatiaNetTest/obj/Debug/CatiaNetTest.pdb and b/CatiaNetTest/obj/Debug/CatiaNetTest.pdb differ
diff --git a/CatiaNetTest/obj/Debug/CatiaNetTest.vbproj.ResolveComReference.cache b/CatiaNetTest/obj/Debug/CatiaNetTest.vbproj.ResolveComReference.cache
index 2dd5a0db036cfd6ded31ddbe13c62f2f21104559..f9fd5b2db8d07a16c65f5d449088c3156f85779a 100644
Binary files a/CatiaNetTest/obj/Debug/CatiaNetTest.vbproj.ResolveComReference.cache and b/CatiaNetTest/obj/Debug/CatiaNetTest.vbproj.ResolveComReference.cache differ
diff --git a/CatiaNetTest/obj/Debug/CatiaNetTest.vbprojAssemblyReference.cache b/CatiaNetTest/obj/Debug/CatiaNetTest.vbprojAssemblyReference.cache
index 4788ac6375fce3d9e11ed6d39b91e57428ed94aa..7e0968d4938a6fd3504f231b9b910fa003dd79d5 100644
Binary files a/CatiaNetTest/obj/Debug/CatiaNetTest.vbprojAssemblyReference.cache and b/CatiaNetTest/obj/Debug/CatiaNetTest.vbprojAssemblyReference.cache differ