El grafo que se presenta a continuación representa la ejecuciòn de una obra elèctrica, en la que se contemplan cada uno de los pasos desde la reuniòn inicial, hasta la entrega del proyecto, inicialmente se plantean 24 días en total, como tiempo máximo de entrega sin contemplar los imprevistos que se puedan presentar.

Instalaciòn de un sistema solar residencial
Instalaciòn de un sistema solar residencial

CONSTRUCCIÓN DEL MODELO DE SIMULACIÓN

A continuación se construye el modelo de simulación para el ejemplo del Gantt. En este primer escenario se le permite a la función la asignación de los tiempos para cada actividad.

df_predec <- read_delim("datos_gantt_electrico.csv",delim = ";")



simulacion_gantt <- function(){
  
df_actividad <- data.frame(id = seq(1,10),time = runif(n = 10,5,10), status = 0,ini_tim  = NA, fin_tim = NA)

# identificar las actividades que no tienen presedencia e inician desde el principio
df_actividad$ini_tim[!(df_actividad$id %in% df_predec$actividad)] <- 0
# actualizar los tiempo de terminacion de la salida 
df_actividad$fin_tim <- df_actividad$time + df_actividad$ini_tim
# actualizar el estado
df_actividad$status[!(is.na(df_actividad$fin_tim))] <- 1

while(sum(is.na(df_actividad$fin_tim))> 0){
  # se actualiza la informacion de los tiempos de presedencia
  df_predec_temp <- df_predec %>% left_join(df_actividad %>% dplyr::select(id,status,fin_tim), by =c("predecedor" ="id"))
  # se identifican las presentes que todavia faltan por ser ejecutados
  df_faltantes <- df_predec_temp %>% filter( status == 0)
  # identificar las tareas que se pueden iniciar
  vt_habil <- df_actividad$id[df_actividad$status == 0 & !(df_actividad$id %in% df_faltantes$actividad)] 
  # identificar el tiempo de inicio de cada actividad
  df_time_fn <-  df_predec_temp %>% filter(status == 1) %>% group_by(actividad) %>% summarise(max_tim = max(fin_tim))
  # actualizar el tiempo de los que ya pueden iniciar
  df_actividad$status[df_actividad$id %in% vt_habil ] <- 1
  # traer el tiempo de inicio
  df_actividad <- df_actividad %>% left_join(df_time_fn, by =c("id" = "actividad"))
  # actualizar el tiempo de inicio
  df_actividad$ini_tim[df_actividad$id %in% vt_habil ] <- df_actividad$max_tim[df_actividad$id %in% vt_habil]
  # actualizar el tiempo de final
  df_actividad$fin_tim[df_actividad$id %in% vt_habil ] <- df_actividad$ini_tim[df_actividad$id %in% vt_habil] +  df_actividad$time[df_actividad$id %in% vt_habil]
  # elminiar la columna de ayuda
  df_actividad <- df_actividad %>% dplyr::select(-max_tim)
}

tiempo_final <- max(df_actividad$fin_tim)
return(tiempo_final)

}

Aplicación de la función simulacion_gantt

print(simulacion_gantt())
## [1] 52.99

vamos a realizar 4000 simulaciones para identificar

reps <- 1000
df_salidas <- data.frame(id = seq(1,1000), tiempo = NA)
for(k in 1:reps){
  df_salidas$tiempo[k] <- simulacion_gantt()
}

Histograma

library(ggplot2)

# Crear la gráfica con ggplot
D_tiempos <- ggplot(data = df_salidas, aes(x = tiempo)) + 
  geom_histogram(binwidth = 0.5, fill = "#0D0887", color = "#6BD7AF", alpha = 0.7) +  # Ajustar color y transparencia
  labs(title = "Distribución de Tiempos de Simulación", x = "Tiempo", y = "Frecuencia") +  # Agregar título y etiquetas de ejes
  theme_light() + # Seleccionar un tema de fondo claro
  theme(plot.title = element_text(hjust = 0.5)) +  # Centrar el título
  xlim(range(df_salidas$tiempo)) +  # Ajustar los límites del eje x
  scale_x_continuous(breaks = seq(min(df_salidas$tiempo), max(df_salidas$tiempo), by = 5))  # Definir los intervalos de las marcas en el eje x

D_tiempos

Probabilidades a través del metodo frecuentista

df_salidas %>% filter(tiempo <= 23) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 30) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 40) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 50) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 60) %>% summarise(cant = n(), prob = cant/reps)

CONCLUSIONES PRIMER ESCENARIO:

Se descarta la posibilidad de permitirle a la función la asignación de los tiempos sin restricción.

ESCENARIO 2:

ASIGNACIÓN DE TIEMPOS REALES

Al reconocer la variabilidad de los procesos relacionados en el Grafo inicial, se definen los tiempos posibles para cada actividad y sus posibles rangos de variación.

  1. Reunión inicial: 1-2 días
  2. Diseños eléctricos: 4-6 días
  3. Compra de materiales: 2-4 días
  4. Porvisional de obra: 1-3 días
  5. Campamento de obra: 3-5 días
  6. Instalación de ductos y conductores: 4-6 días
  7. Instalación de paneles solares: 3-5 días
  8. Prubeas eléctricas: 1-3 días
  9. Certificación:1-5 días 10.Capacitación al cliente 1-2 días
library(readr)
library(dplyr)

df_predec <- read_delim("datos_gantt_electrico.csv",delim = ";")



simulacion_gantt <- function(){
  
df_actividad <- data.frame(id = seq(1,10),time = c(runif(1,1,2),
                                                               runif(1,4,6),
                                                               runif(1,2,4),
                                                               runif(1,1,3),
                                                               runif(1,3,5),
                                                               runif(1,4,6),
                                                               runif(1,3,5),
                                                               runif(1,1,3),
                                                               runif(1,1,5),
                                                               runif(1,1,2)),
                                                               status = 0,ini_tim  = NA, fin_tim = NA)

# identificar las actividades que no tienen presedencia e inician desde el principio
df_actividad$ini_tim[!(df_actividad$id %in% df_predec$actividad)] <- 0
# actualizar los tiempo de terminacion de la salida 
df_actividad$fin_tim <- df_actividad$time + df_actividad$ini_tim
# actualizar el estado
df_actividad$status[!(is.na(df_actividad$fin_tim))] <- 1

while(sum(is.na(df_actividad$fin_tim))> 0){
  # se actualiza la informacion de los tiempos de presedencia
  df_predec_temp <- df_predec %>% left_join(df_actividad %>% dplyr::select(id,status,fin_tim), by =c("predecedor" ="id"))
  # se identifican las presentes que todavia faltan por ser ejecutados
  df_faltantes <- df_predec_temp %>% filter( status == 0)
  # identificar las tareas que se pueden iniciar
  vt_habil <- df_actividad$id[df_actividad$status == 0 & !(df_actividad$id %in% df_faltantes$actividad)] 
  # identificar el tiempo de inicio de cada actividad
  df_time_fn <-  df_predec_temp %>% filter(status == 1) %>% group_by(actividad) %>% summarise(max_tim = max(fin_tim))
  # actualizar el tiempo de los que ya pueden iniciar
  df_actividad$status[df_actividad$id %in% vt_habil ] <- 1
  # traer el tiempo de inicio
  df_actividad <- df_actividad %>% left_join(df_time_fn, by =c("id" = "actividad"))
  # actualizar el tiempo de inicio
  df_actividad$ini_tim[df_actividad$id %in% vt_habil ] <- df_actividad$max_tim[df_actividad$id %in% vt_habil]
  # actualizar el tiempo de final
  df_actividad$fin_tim[df_actividad$id %in% vt_habil ] <- df_actividad$ini_tim[df_actividad$id %in% vt_habil] +  df_actividad$time[df_actividad$id %in% vt_habil]
  # elminiar la columna de ayuda
  df_actividad <- df_actividad %>% dplyr::select(-max_tim)
}

tiempo_final <- max(df_actividad$fin_tim)
return(tiempo_final)

}

Aplicación de la función simulacion_gantt

El tiempo medio coincide con lo estimado inicialmente en la planeación de obra.

print(simulacion_gantt())
## [1] 25.09761

Se realizan 1000 simulaciones para identificar los diferentes escenarios posibles

reps <- 1000
df_salidas <- data.frame(id = seq(1,1000), tiempo = NA)
for(k in 1:reps){
  df_salidas$tiempo[k] <- simulacion_gantt()
}

Histograma

library(ggplot2)

# Crear la gráfica con ggplot
D_tiempos <- ggplot(data = df_salidas, aes(x = tiempo)) + 
  geom_histogram(binwidth = 0.5, fill = "#0D0887", color = "#6BD7AF", alpha = 0.7) +  # Ajustar color y transparencia
  labs(title = "Distribución de Tiempos de Simulación", x = "Tiempo", y = "Frecuencia") +  # Agregar título y etiquetas de ejes
  theme_light() + # Seleccionar un tema de fondo claro
  theme(plot.title = element_text(hjust = 0.5)) +  # Centrar el título
  xlim(range(df_salidas$tiempo)) +  # Ajustar los límites del eje x
  scale_x_continuous(breaks = seq(min(df_salidas$tiempo), max(df_salidas$tiempo), by = 5))  # Definir los intervalos de las marcas en el eje x

D_tiempos

df_salidas %>% filter(tiempo <= 15) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo <= 19) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 20) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 24) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 30) %>% summarise(cant = n(), prob = cant/reps)

CONCLUSIONES DEL ESCENARIO 2:

se define como un tiempo factible los 24 días planteados al inicio del proyecto toda vez que se puede asegurar con una probabilidad de 0.845 la ejecución del proyecto.

ESCENARIO 3:

Habitualmente durante la ejecución de una obra eléctrica se presentan dos escenarios que pueden marcar la diferencia en la entrega oportuna y la solucitud de ampliación en tiempo y recurso del proyecto, en este escenario se contempla que la compra de materiales y la entrega en sitio puede variar razones de ello pueden ser la importación de materiales y la puesta en el lugar de ejecución de la obra, así mismo la instalación de los paneles solares dependerá del clima, en este escenario, las demás variables se mantendran fijas y sólo se variarán la compra de materiales y la instalación de los paneles solares, esta variación se llevará a un extremo y posteriormente de evaluará si se puede mantener el tiempo inicialmente proyectado de 24 días.

library(readr)
library(dplyr)

df_predec <- read_delim("datos_gantt_electrico.csv",delim = ";")



simulacion_gantt <- function(){
  
df_actividad <- data.frame(id = seq(1,10),time = c(runif(1,1,1),
                                                               runif(1,5,5),
                                                               runif(1,2,12),
                                                               runif(1,1,1),
                                                               runif(1,3,3),
                                                               runif(1,5,5),
                                                               runif(1,3,10),
                                                               runif(1,2,2),
                                                               runif(1,1,1),
                                                               runif(1,2,2)),
                                                               status = 0,ini_tim  = NA, fin_tim = NA)

# identificar las actividades que no tienen presedencia e inician desde el principio
df_actividad$ini_tim[!(df_actividad$id %in% df_predec$actividad)] <- 0
# actualizar los tiempo de terminacion de la salida 
df_actividad$fin_tim <- df_actividad$time + df_actividad$ini_tim
# actualizar el estado
df_actividad$status[!(is.na(df_actividad$fin_tim))] <- 1

while(sum(is.na(df_actividad$fin_tim))> 0){
  # se actualiza la informacion de los tiempos de presedencia
  df_predec_temp <- df_predec %>% left_join(df_actividad %>% dplyr::select(id,status,fin_tim), by =c("predecedor" ="id"))
  # se identifican las presentes que todavia faltan por ser ejecutados
  df_faltantes <- df_predec_temp %>% filter( status == 0)
  # identificar las tareas que se pueden iniciar
  vt_habil <- df_actividad$id[df_actividad$status == 0 & !(df_actividad$id %in% df_faltantes$actividad)] 
  # identificar el tiempo de inicio de cada actividad
  df_time_fn <-  df_predec_temp %>% filter(status == 1) %>% group_by(actividad) %>% summarise(max_tim = max(fin_tim))
  # actualizar el tiempo de los que ya pueden iniciar
  df_actividad$status[df_actividad$id %in% vt_habil ] <- 1
  # traer el tiempo de inicio
  df_actividad <- df_actividad %>% left_join(df_time_fn, by =c("id" = "actividad"))
  # actualizar el tiempo de inicio
  df_actividad$ini_tim[df_actividad$id %in% vt_habil ] <- df_actividad$max_tim[df_actividad$id %in% vt_habil]
  # actualizar el tiempo de final
  df_actividad$fin_tim[df_actividad$id %in% vt_habil ] <- df_actividad$ini_tim[df_actividad$id %in% vt_habil] +  df_actividad$time[df_actividad$id %in% vt_habil]
  # elminiar la columna de ayuda
  df_actividad <- df_actividad %>% dplyr::select(-max_tim)
}

tiempo_final <- max(df_actividad$fin_tim)
return(tiempo_final)

}

Aplicación de la función simulacion_gantt

El tiempo medio coincide con lo estimado inicialmente en la planeación de obra.

print(simulacion_gantt())
## [1] 32.6295

Se realizan 1000 simulaciones para identificar los diferentes escenarios posibles

reps <- 1000
df_salidas <- data.frame(id = seq(1,1000), tiempo = NA)
for(k in 1:reps){
  df_salidas$tiempo[k] <- simulacion_gantt()
}

Histograma

library(ggplot2)

# Crear la gráfica con ggplot
D_tiempos <- ggplot(data = df_salidas, aes(x = tiempo)) + 
  geom_histogram(binwidth = 0.5, fill = "#0D0887", color = "#6BD7AF", alpha = 0.7) +  # Ajustar color y transparencia
  labs(title = "Distribución de Tiempos de Simulación", x = "Tiempo", y = "Frecuencia") +  # Agregar título y etiquetas de ejes
  theme_light() + # Seleccionar un tema de fondo claro
  theme(plot.title = element_text(hjust = 0.5)) +  # Centrar el título
  xlim(range(df_salidas$tiempo)) +  # Ajustar los límites del eje x
  scale_x_continuous(breaks = seq(min(df_salidas$tiempo), max(df_salidas$tiempo), by = 5))  # Definir los intervalos de las marcas en el eje x

D_tiempos

df_salidas %>% filter(tiempo <= 15) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo <= 19) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 20) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 24) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 30) %>% summarise(cant = n(), prob = cant/reps)
df_salidas %>% filter(tiempo < 45) %>% summarise(cant = n(), prob = cant/reps)

CONCLUSIONES ESCENARIO 3:

La variación en los tiempos asociados a la compra de materiales y la instalación de los paneles solares pueden hacer que el tiempo de entrega supere el tiempo inicialmente proyectadeo, por lo que se sugiere la revisión de estos tiempos antes de la presentación formal de la propuesta ante el grupo directivo.