ar_redadeg/scripts_v2/phase_3_compute.py
MaelREBOUX c05d9ba256 phase 3 : ajustements
ça marche mieux…
2021-11-07 11:43:26 +01:00

406 lines
12 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Libraries
#
import os
import sys
import datetime
import time
import configparser
import psycopg2
#from logguer import log_verif
# ==============================================================================
# répertoire courant
script_dir = os.path.dirname(os.path.abspath(__file__))
# jour courant
date = datetime.datetime.now()
# lecture du fichier de configuration qui contient les infos de connection
config = configparser.ConfigParser()
config.read( script_dir + '/config.ini')
#fichier_log = str(date.year)+str(date.month)+str(date.day)+"_"+str(date.hour)+str(date.minute)
fichier_log = str(date.year)+str(date.month)+str(date.day)
# ==============================================================================
def initConnRedadegDB():
# connexion à la base postgresql
try:
global db_redadeg_pg_conn
db_redadeg_pg_conn = psycopg2.connect(db_redadeg_conn_str)
db_redadeg_pg_conn.set_session(autocommit=True)
print(" Connexion à la base "+db_redadeg_db+" sur "+db_redadeg_host+" réussie ")
except Exception as err:
print(" Connexion à la base "+db_redadeg_db+" sur "+db_redadeg_host+ " impossible ")
try:
err.pgcode
print(" PostgreSQL error code : " + err.pgcode)
sys.exit()
except:
print(" " + str(err),0)
sys.exit()
# ==============================================================================
def closeConnRedadegDB():
try:
db_redadeg_pg_conn.close()
print(" Fermeture de la connexion à la base "+db_redadeg_db+" sur "+db_redadeg_host)
except:
pass
# ==============================================================================
def getPKfromRouting(start, distance):
sql_routage = """
WITH t AS (
SELECT *
FROM pgr_drivingDistance('SELECT id, source, target, cost, reverse_cost FROM phase_3_troncons_pgr
WHERE SOURCE IS NOT NULL AND id > 0',
"""+str(start)+""", """+str(distance)+""")
)
SELECT node, edge, round(agg_cost) FROM t ORDER BY seq DESC LIMIT 1;"""
#print(sql_routage)
cursor = db_redadeg_pg_conn.cursor()
cursor.execute(sql_routage)
# on récupère l'id du nœud de fin
data = cursor.fetchone()
node_end = data[0]
edge = data[1]
distance = data[2]
cursor.close()
return([node_end, edge, distance])
# ==============================================================================
def getPgrNodeInfos(node_id):
# cette fonction va chercher les infos où il faut pour le PK
cursor = db_redadeg_pg_conn.cursor()
# géométrie…
sql_get_from_pgr_node = """
SELECT
the_geom,
TRUNC(ST_X(the_geom)::numeric,1) AS x,
TRUNC(ST_Y(the_geom)::numeric,1) AS y,
TRUNC(ST_X(ST_Transform(the_geom,4326)::geometry(Point, 4326))::numeric,8) AS long,
TRUNC(ST_Y(ST_Transform(the_geom,4326)::geometry(Point, 4326))::numeric,8) AS lat
FROM phase_3_troncons_pgr_vertices_pgr v WHERE id = """+ str(node_id) +""";"""
#print(sql_get_from_pgr_node)
cursor.execute(sql_get_from_pgr_node)
data = cursor.fetchone()
the_geom = data[0]
x = data[1]
y = data[2]
long = data[3]
lat = data[4]
cursor.close()
return([the_geom,x,y,long,lat])
# ==============================================================================
def getLongueurParcourue(node_start, node_end):
# cette fonction sert à retourner la longueur parcourue entre 2 nœuds
sql_get_longueur = "SELECT round(max(agg_cost))::integer "
sql_get_longueur += "FROM pgr_dijkstra('SELECT id, source, target, cost, reverse_cost FROM phase_3_troncons_pgr "
sql_get_longueur += " WHERE SOURCE IS NOT NULL', " + str(node_start) + ", " + str(node_end) + ")"
cursor = db_redadeg_pg_conn.cursor()
cursor.execute(sql_get_longueur)
data = cursor.fetchone()[0]
return (data)
# ==============================================================================
# ==============================================================================
# ==============================================================================
# Start processing
#
startTime = time.perf_counter()
# on récupère les arguments passés
list_of_args = sys.argv
millesime=""
secteur=""
typemaj=""
# et on fait des tests
try:
if len(list_of_args[1]) != 4:
print("Pas de millésime en argument")
sys.exit()
else:
millesime = list_of_args[1]
# millesime ok : on passe au secteur
if len(list_of_args[2]) != 3:
print("Pas d'id secteur en argument")
sys.exit()
else:
secteur = list_of_args[2]
# ok : tout est bon on peut commencer
# sortie des tests
except SystemExit:
print("Erreur dans les arguments --> stop")
sys.exit()
except:
print("oups : vérifiez vos arguments passés au script !")
print("stop")
sys.exit()
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
print("")
print(" Calcul des PK pour le secteur "+str(secteur)+" pour le millésime "+str(millesime))
print("")
print(" Lecture du fichier de configuration ")
print("")
# BD Ar Redadeg
global db_redadeg_host
global db_redadeg_db
db_redadeg_host = config.get('redadeg_database', 'host')
db_redadeg_port = config.get('redadeg_database', 'port')
db_redadeg_db = config.get('redadeg_database', 'db')+"_"+str(millesime)
db_redadeg_user = config.get('redadeg_database', 'user')
db_redadeg_passwd = config.get('redadeg_database', 'passwd')
# chaîne de connection
global db_redadeg_conn_str
db_redadeg_conn_str = "host="+db_redadeg_host+" port="+db_redadeg_port+" dbname="+db_redadeg_db+" user="+db_redadeg_user+" password="+db_redadeg_passwd
initConnRedadegDB()
# le cursor
db_redadeg_cursor = db_redadeg_pg_conn.cursor()
print("")
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
try:
# ------------------------------------------------------
print(" Récupération des infos du secteur")
# PK de départ de la Redadeg (à cause de l'avant course)
pk_start_redadeg = config.get('redadeg', 'pk_start')
sql_get_infos_secteur = "SELECT pk_start, node_start, node_stop, longueur, longueur_km_redadeg "
sql_get_infos_secteur += "FROM secteur "
sql_get_infos_secteur += "WHERE id = "+secteur+" ;"
db_redadeg_cursor.execute(sql_get_infos_secteur)
infos_secteur = db_redadeg_cursor.fetchone()
secteur_pk_start = infos_secteur[0]
secteur_node_start = infos_secteur[1]
secteur_node_stop = infos_secteur[2]
secteur_longueur = infos_secteur[3]
secteur_longueur_km_redadeg = infos_secteur[4]
# pour test
#secteur_longueur = 10000
# longueur de découpage des tronçons de la phase 2
longueur_densification = config.get('redadeg', 'longueur_densification')
print(" fait")
print("")
# on détermine le nb théorique de PK pour ce secteur
secteur_nb_pk = int(secteur_longueur / secteur_longueur_km_redadeg)
# et la longueur réelle demandée au calculateur
longueur_decoupage = int(secteur_longueur_km_redadeg)
print(" " + str(secteur_nb_pk) + " KM redadeg de " + str(secteur_longueur_km_redadeg) + " m vont être créés")
print(" pour une longeur réelle de " + str(secteur_longueur) + " m")
print("")
# cette variable pour stocker la requête SQL de création des PK
# et la première requête sera de supprimer les données du secteur
sql_insert_pks = "DELETE FROM phase_3_pk WHERE secteur_id = "+secteur+" ;\n"
# ------------------------------------------------------
print(" Calcul du 1er PK du secteur")
# on a les infos -> on calcule la route qui va du 1er nœud de départ et qui fait la distance demandée
# pour récupérer l'id du noeud de fin qui va devenir notre PK
node_zero = secteur_node_start
node_zero_data = getPgrNodeInfos(node_zero)
sql_insert_pks += "INSERT INTO phase_3_pk (secteur_id, pk_id, the_geom, pk_x, pk_y, pk_long, pk_lat, length_theorical, length_real) VALUES ("
sql_insert_pks += secteur + ", " + str(secteur_pk_start)
sql_insert_pks += ",'" + node_zero_data[0] + "'"
sql_insert_pks += "," + str(node_zero_data[1]) + "," + str(node_zero_data[2])
sql_insert_pks += "," + str(node_zero_data[3]) + "," + str(node_zero_data[4])
sql_insert_pks += f",{longueur_decoupage},0"
sql_insert_pks += ");\n"
print(" nœud du PK " + str(secteur_pk_start) + " : " + str(node_zero))
print("")
# ------------------------------------------------------
print(" Calcul des autres PK")
print("")
# maintenant on peut itérer jusqu'à la fin du secteur
node_x = node_zero
# en sa basant sur la longueur des PK posés et la longueur totale du secteur
longueur_parcourue = getLongueurParcourue(node_zero, node_x)
if longueur_parcourue is None: longueur_parcourue = 0
longueur_restante = secteur_longueur - longueur_parcourue
# un compteur pour la boucle
i = 1
# début de l'id des PK qui commence avec le PK de début du secteur
pk_id = secteur_pk_start
# tant que la distance restante est supérieure à la distance de découpage
# on boucle
while longueur_restante >= longueur_decoupage:
# incrément du compteur de la boucle
i += 1
# incrément du compteur de PK
pk_id += 1
# on va trouver le prochain PK
pk_data = getPKfromRouting(node_x , longueur_decoupage)
node_x = pk_data[0]
previous_pk_edge = pk_data[1]
longueur_km_redadeg = pk_data[2]
longueur_parcourue = getLongueurParcourue(node_zero,node_x)
longueur_restante = secteur_longueur - longueur_parcourue
#print(" nouveau nœud : " + str(node_x))
#print(" previous_pk_edge : "+ str(previous_pk_edge))
# on sort une infos pour suivre si le traitement bosse
if (i <= 5) or (i % 10 == 0) or (i >= secteur_nb_pk - 5):
print(" PK " + str(pk_id))
print(" id du nœud : " + str(node_x))
print(" " + str(longueur_parcourue) + " m jusqu'à maintenant")
print(" " + str(longueur_restante) + " m restant jusqu'à la fin du secteur")
# ici on construit la requête avec les données du PK
node_x_data = getPgrNodeInfos(node_x)
# on fait une requête SQL d'insert de ce PK
sql_insert_pks += "INSERT INTO phase_3_pk (secteur_id, pk_id, the_geom, pk_x, pk_y, pk_long, pk_lat, length_theorical, length_real) VALUES ("
sql_insert_pks += secteur + "," + str(pk_id)
sql_insert_pks += ",'" + node_x_data[0] + "'"
sql_insert_pks += "," + str(node_x_data[1]) + "," + str(node_x_data[2])
sql_insert_pks += "," + str(node_x_data[3]) + "," + str(node_x_data[4])
sql_insert_pks += f",{longueur_decoupage},{longueur_km_redadeg}"
sql_insert_pks += ");\n"
# on met en négatif l'info de routage du précédent tronçon afin de l'écarter du prochain calcul de routage
sql_neutralisation = "UPDATE phase_3_troncons_pgr SET id = -ABS("+str(previous_pk_edge)+") WHERE id = "+str(previous_pk_edge)+" ;"
#print(sql_neutralisation)
db_redadeg_cursor.execute(sql_neutralisation)
print("")
print(" Fin de la boucle")
print("")
print(" RAZ de la neutralisation des infos de routage pour la boucle")
sql_reset_neutralisation = "UPDATE phase_3_troncons_pgr SET id = -1*id WHERE id < 0 ;"
db_redadeg_cursor.execute(sql_reset_neutralisation)
print(" fait")
print("")
print(" Écriture des PK dans la couche phase_3_pk")
db_redadeg_cursor.execute(sql_insert_pks)
print(" fait")
print("")
print(" sauvegarde du dernier PK calculé pour ce secteur")
# on est sorti de la boucle alors on va écrire en base l'id du dernier PK calculé
sql_update_pk_end = "UPDATE secteur SET pk_stop = " + str(pk_id)
sql_update_pk_end += "WHERE id = " + secteur + " ;"
db_redadeg_cursor.execute(sql_update_pk_end)
print(" fait")
print("")
db_redadeg_cursor.close()
print("")
print("")
except Exception as err:
print(" ERREUR : " + str(err))
closeConnRedadegDB()
sys.exit()
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
db_redadeg_cursor.close()
closeConnRedadegDB()
# pour connaître le temps d'exécution
print("")
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
print("F I N")
print("")
stopTime = time.perf_counter()
# version simple en secondes
#print(f"Exécuté en {stopTime - startTime:0.4f} secondes")
# version en h min s
hours, rem = divmod(stopTime - startTime, 3600)
minutes, seconds = divmod(rem, 60)
print("Exécuté en {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))