loading...

April 4, 2023

VCI Reproducibility Report

Author: Ruan Aucamp
Date: 2023-03-30

1. Introduction

The purpose of this report is to reproduce the VCI values contained inside the vcf file. The VCI value is used to calculate depreciation, remaining useful life and impairment in the infrastructure asset register.

More information and guidance with regard to Pavement Management Systems and Condition Assessments are available in the following documents:

The Draft TMH 9 Manual for Visual Assessment of Road Pavements – Part A and B
TMH 9 Manual for Visual Assessment of Road Pavements – Part A
TMH 9 Manual for Visual Assessment of Road Pavements – Part B

The Draft TMH 22 Road Asset Management Manual
TMH 22 Road Asset Management Manual

The TMH 18 Road Asset DataElectronic Exchange Formats Version 4
TMH 18 Road Asset DataElectronic Exchange Formats Version 4

The method used for the calculation of the visual condition index (VCI) for flexible paved roads can be found under appendix J-6 of the TMH 22 Manual.

VCI Calculation
Weight for defects

2. Data Wrangling

2.1 Loading Libraries

I used the following libraries:

library(tidyverse)
library(lubridate)
library(prettydoc)
library(xtable)
library(knitr)
library(data.table)

2.2 Data Import

Section 5.2 on Page 18 of The TMH 18 Road Asset DataElectronic Exchange Formats Version 4 gives a detailed explanation of the Fields included in the vcf file. The vcf file is a comma separated text file with a vcf extension. The file is converted to csv for importing into R. The csv file is available for download at https://irams.maps.arcgis.com/sharing/rest/content/items/aa9a81926ccb4475b9c6e37feed0a44a/data. I used fread to load the csv file into a data frame and looked at a summary of the data.

vcf <- fread("2022_23_unfiltered.csv")
summary(vcf)

2.3 Tidy Data

When looking at the summary, it can be seen that the VCI field is currently a character class. There are some NULL values included in the VCI column. This is because of various reasons but in most cases the segment is under construction and a condition assessment could not be performed. The segments with NULL values will be removed and the class changed to numeric.

vcf <- vcf %>%
  filter(VCI != "NULL")

vcf$VCI <- as.numeric(vcf$VCI)

The first part of the calculation is to determine the Fn value for all the defects. The degree, extend and weight of each defect is calculated and stored in a variable.

It is important to note that Functional defects are assessed up to a degree value of 5 but for the calculation the max value used is a 4. Therefore, a check is included to change the value to a 4 if it is assessed as a 5.

The extend rating for functional defects are assessed on a scale from 1 to 5 but a default value of 3 is used for the calculation.

Edge defects contains three different fields:

EDGE BREAKS, EDGE CRACKS and EDGE DROPOFFS

The maximum value out of the three is used for the Edge Defect category.

The FnMax value for aggregate loss is an average between active and non-active. (3 * 5 * 5) or 75.

#Calculating the Fn Value for each defect
surfacing_failures <- vcf$SURFACE_FAILURE_DEG * vcf$SURFACE_FAILURE_EXT * 6.5
surfacing_cracks <- vcf$SURFACE_CRACK_DEG * vcf$SURFACE_CRACK_EXT * 5.0
active_agreggate_loss <- ifelse (vcf$AGGR_LOSS_ACT == 'A', 
                                 vcf$AGGR_LOSS_DEG * vcf$AGGR_LOSS_EXT * 4.0, 0)
non_active_aggregate_loss <- ifelse (vcf$AGGR_LOSS_ACT == 'N', 
                                     vcf$AGGR_LOSS_DEG * vcf$AGGR_LOSS_EXT * 2.0, 0)
binder <- vcf$BINDER_CONDITION_DEG * vcf$BINDER_CONDITION_EXT * 3.0
bleeding_flushing <- vcf$BLEEDING_DEG * vcf$BLEEDING_EXT * 3.0
surface_deformation_shoving <- vcf$SURF_DEFORM_DEG * vcf$SURF_DEFORM_EXT * 8.0
block_cracks <- vcf$BLOCK_CRACK_DEG * vcf$BLOCK_CRACK_EXT * 6.0
longitudinal_cracks <- vcf$LONG_CRACK_DEG * vcf$LONG_CRACK_EXT * 4.5
transverse_cracks <- vcf$TRANSVERSE_CRACK_DEG * vcf$TRANSVERSE_CRACK_EXT * 4.5
crocodile_cracks <- vcf$CROCODILE_CRACK_DEG * vcf$CROCODILE_CRACK_EXT * 10.0
pumping <- vcf$PUMPING_DEG * vcf$PUMPING_EXT * 10.0
rutting <- vcf$RUTTING_DEG * vcf$RUTTING_EXT * 8.0
undulation_settlement <- vcf$UNDULATION_DEG * vcf$UNDULATION_EXT * 4.0
patching <- vcf$PATCHING_DEG * vcf$PATCHING_EXT * 8.0
potholes <- vcf$POTHOLES_DEG * vcf$POTHOLES_EXT * 15.0

#Adding the calculated Fn Value for defects to the data frame as new fields.
vcf <- vcf %>%
  mutate(surfacing_failures = surfacing_failures, 
         surfacing_cracks = surfacing_cracks, 
         active_agreggate_loss = active_agreggate_loss,
         non_active_aggregate_loss = non_active_aggregate_loss, 
         binder = binder, 
         bleeding_flushing = bleeding_flushing, 
         surface_deformation_shoving = surface_deformation_shoving, 
         block_cracks = block_cracks, 
         longitudinal_cracks = longitudinal_cracks, 
         transverse_cracks = transverse_cracks, 
         crocodile_cracks = crocodile_cracks, 
         pumping = pumping, 
         rutting = rutting, 
         undulation_settlement = undulation_settlement, 
         patching = patching, 
         potholes = potholes,
         #Choosing the Maximum value between Edge Breaks, Edge Cracks and Edge Dropoff
         edge_break_deg_max = pmax(EDGE_BREAK_DEG, EDGE_CRACKS_DEG, EDGE_DROPOFF_DEG))

#Ensure that Functional degree value is a maximum of 4 even if assessed as a 5 
vcf$edge_break_deg_max <- ifelse (vcf$edge_break_deg_max == 5, 
                                  4, vcf$edge_break_deg_max) 
vcf$RIDING_QUAL_DEG <- ifelse (vcf$RIDING_QUAL_DEG == 5, 
                               4, vcf$RIDING_QUAL_DEG)
vcf$SKID_RESISTANCE_DEG <- ifelse (vcf$SKID_RESISTANCE_DEG == 5, 
                                   4, vcf$SKID_RESISTANCE_DEG) 
vcf$DRAINAGE_SURF <- ifelse (vcf$DRAINAGE_SURF == 5, 
                             4, vcf$DRAINAGE_SURF) 
vcf$UNPAVED_SHOULDER <- ifelse (vcf$UNPAVED_SHOULDER == 5, 
                                4, vcf$UNPAVED_SHOULDER) 

#Calculating the Fn Value for Functional defects
edge_defects <- vcf$edge_break_deg_max * 3 * 3.5
riding_quality <- vcf$RIDING_QUAL_DEG * 3 * 5.5
skid_resistance <- vcf$SKID_RESISTANCE_DEG * 3 * 3.0
surface_drainage <- vcf$DRAINAGE_SURF * 3 * 3.0
unpaved_shoulders <- vcf$UNPAVED_SHOULDER * 3 * 3.5

#Adding the calculated Fn Value for defects to the data frame as new fields.
vcf <- vcf %>%
  mutate(edge_defects = edge_defects, 
         riding_quality = riding_quality, 
         skid_resistance = skid_resistance, 
         surface_drainage = surface_drainage, 
         unpaved_shoulders = unpaved_shoulders)

#Calculating the Fn Max Value for each defect
surfacing_failures_max <- 5 * 5 * 6.5
surfacing_cracks_max <- 5 * 5 * 5.0
aggregate_loss_max <- 3 * 5 * 5
binder_max <- 5 * 5 * 3.0
bleeding_flushing_max <- 5 * 5 * 3.0
surface_deformation_shoving_max <- 5 * 5 * 8.0
block_cracks_max <- 5 * 5 * 6.0
longitudinal_cracks_max <- 5 * 5 * 4.5
transverse_cracks_max <- 5 * 5 * 4.5
crocodile_cracks_max <- 5 * 5 * 10.0
pumping_max <- 5 * 5 * 10.0
rutting_max <- 5 * 5 * 8.0
undulation_settlement_max <- 5 * 5 * 4.0
patching_max <- 5 * 5 * 8.0
potholes_max <- 5 * 5 * 15.0
edge_defects_max <- 4 * 3 * 3.5
riding_quality_max <- 4 * 3 * 5.5
skid_resistance_max <- 4 * 3 * 3.0
surface_drainage_max <- 4 * 3 * 3.0
unpaved_shoulders_max <- 4 * 3 * 3.5

After calculation all the Fn and FnMax values for each defect the VCI calculation can be done. The vcf file already contains a VCI value calculated by the consultant. The recalculated VCI value is stored as VCI_2.

#Adding a new field to store the total value for Fn
vcf <- vcf %>%
  mutate(Fn = surfacing_failures + surfacing_cracks + active_agreggate_loss + non_active_aggregate_loss + binder + bleeding_flushing + surface_deformation_shoving +
           block_cracks + longitudinal_cracks + transverse_cracks + crocodile_cracks + pumping + rutting + undulation_settlement + patching +
           potholes + edge_defects + riding_quality + skid_resistance + surface_drainage + unpaved_shoulders)

#Adding a new field to store the total value for FnMax
vcf <- vcf %>%
  mutate(Fn_max = surfacing_failures_max + surfacing_cracks_max + aggregate_loss_max + binder_max + bleeding_flushing_max + surface_deformation_shoving_max +
           block_cracks_max + longitudinal_cracks_max + transverse_cracks_max + crocodile_cracks_max + pumping_max + rutting_max + undulation_settlement_max + patching_max +
           potholes_max + edge_defects_max + riding_quality_max + skid_resistance_max + surface_drainage_max + unpaved_shoulders_max)

#Calculating the segment length
vcf <- vcf %>%
  mutate(Seg_Length = vcf$END_KM - START_KM)

vcf <- vcf %>%
  mutate(C = 1/vcf$Fn_max)

vcf <- vcf %>%
  mutate(VCI_P = 100 *(1 - C * vcf$Fn))

vcf <- vcf %>%
  mutate(VCI_2 = (0.02509 * vcf$VCI_P + 0.0007568 * vcf$VCI_P^2)^2)

In order to make it easier to compare the two values only the needed field are selected.

vcf <- vcf %>%
  select(SEG_ID, VCI, VCI_2)

The values inside the vcf file is up to 3 decimal places and therefore I will also round the calculated values to 3 decimal places.

vcf$VCI_2 <- round(vcf$VCI_2, digits = 3)

Lastly I compare the VCI value from the consultant to the VCI value calculated.

comparison <- vcf %>%
  filter(VCI != VCI_2)

print(comparison)

3. Conclusion

The comparison did not return any values with a difference and therefore it is assumed that every VCI value calculated by the consultant can be reproduced by using the above formula.

Posted in RTaggs: