<?php
namespace App\Controller;
use DateTime;
use App\Entity\Site;
use App\Entity\Episode;
use App\Service\PetitsOutils;
use App\Service\ModeleODP\Previs;
use App\Repository\SiteRepository;
use App\Repository\MeteoRepository;
use App\Repository\EpisodeRepository;
use Doctrine\ORM\EntityManagerInterface;
use App\Service\ModeleODP\ModeleODPExcel;
use App\Service\ModeleODP\ModeleODPgraph;
use App\Service\ModeleODP\CreationEpisodes;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class ModeleODPController extends AbstractController
{
private $petitsOutils;
private $meteoRepository;
private $em;
private $episodeRepository;
private $modeleODPExcel;
private $modeleODPgraph;
private $previs;
private $creationEpisodes;
private $siteRepository;
public function __construct(PetitsOutils $petitsOutils, MeteoRepository $meteoRepository, EntityManagerInterface $em, EpisodeRepository $episodeRepository, ModeleODPExcel $modeleODPExcel, Previs $previs, CreationEpisodes $creationEpisodes,ModeleODPgraph $modeleODPgraph, SiteRepository $siteRepository)
{
$this->petitsOutils = $petitsOutils;
$this->meteoRepository = $meteoRepository;
$this->em = $em;
$this->episodeRepository = $episodeRepository;
$this->modeleODPExcel = $modeleODPExcel;
$this->previs = $previs;
$this->creationEpisodes = $creationEpisodes;
$this->modeleODPgraph = $modeleODPgraph;
$this->siteRepository = $siteRepository;
}
/**
* @Route("/user/modele/odp/dates", name="app_modele_odp_dates")
*/
public function choixDates(Request $request): Response
{
$defaultData = [];
$form = $this->createFormBuilder($defaultData)
->add('debut', TextType::class,array(
'label' =>"début",
'attr' => array(
'class' => 'js-datepicker',
)))
->add('fin', TextType::class,array(
'label' =>"fin",
'attr' => array(
'class' => 'js-datepicker',
)
))
->add('site',EntityType::class,array(
'class'=>Site::class,
))
->add('ok', SubmitType::class)
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$data = $form->getData();
$debut = $this->petitsOutils->frenchDateToEnglish($data['debut']);
$fin = $this->petitsOutils->frenchDateToEnglish($data['fin']);
$siteId = $data['site']->getId();
return $this->render('/modele_odp/sortie.html.twig',array(
'siteId'=>$siteId
));
}
return $this->render('modele_odp/dates.html.twig', [
'form' => $form->createView()
]);
}
/**
* @Route("/user/modele/odp/calcul-modele", name="app_modele_odp_calcul-modele")
*/
public function calculModele(Request $request):Response
{
/**
* 1 - Récupération des pluies entre les dates choisies
*/
$debut = $request->query->get('debut');
$fin = $request->query->get('fin');
$siteId = $request->query->get('siteId');
$site = $this->siteRepository->find($siteId);
$pluies = $this->meteoRepository->findPluies($debut,$fin,$site);
/**
* 2 - Récupération des prévisions à 7 jours dans InfoClimat
*/
// $arrayPrevis = [];
// // $arrayPrevis = $this->previs->recupPrevis();
// //dd($arrayPrevis);
/**
* 3 - Pour chaque pluie horaire on crée un épisode pluvieux
* qui démarre à la première pluie et s'arrête à la dernière pluie horaire consécutive
* avec un trou possible d'une heure sans pluie//////-------à faire////////
*/
$episodesP = array();
$episodesP = $this->creationEpisodes->creationEpisodesPluie($pluies);
//on enregistre les épisodes
$this->_recEpisodes($episodesP,$siteId);
// dd($episodesP)
/**
* 4 - Récupération des prévisions à 9 jours dans Weathermesures
*/
$arrayPrevis = [];
//$arrayPrevis = $this->previs->recupPrevisWeatherMeasures($siteId);
//dd($arrayPrevis);
/**
* 5 - Pour chaque pluie horaire prévision on crée un épisode pluvieux
* qui démarre à la première pluie et s'arrête à la dernière pluie horaire consécutive
* avec un trou possible d'une heure sans pluie//////-------à faire////////
*/
$episodesP = array();
$pluiesP = array();
foreach($arrayPrevis as $k => $e){
//dd($e);
if($e['pluie'] > 0){
$pluiesP[$k] = $e;
//dump($pluiesP);
}
}
//dd($pluiesP);
$episodesP = $this->creationEpisodes->creationEpisodesPluiePrevis($pluiesP);
/**
* 4 - Pour chaque épisode pluvieux on étudie l'hygrométrie dans les heures suivantes
*/
//on récupère les épisodes
$episodes = $this->episodeRepository->findDebSite($debut,$site);
foreach ($episodes as $ep) {
$hum = $this->_calculHumide($ep);
//dd($hum);
$humide = array();
foreach ($hum as $h) {
$humide = $h;
}
//on met à jour la table épisodes avec les infos de humide
//et de S1 S2
//pour avoir un objet épisode pluvieux complet
if (!empty($humide)) {
$ep->setDateDebHygroSup85($humide['debut']);
$ep->setDateFinHygroSup85($humide['fin']);
$ep->setNbreHeuresHygroSup85($humide['nbre']);
$ep->setTempMoyHygroSup85($humide['temp']);
}
$temp = $ep->getTempMoyPluie();
//calcul S1
$S1 = round(exp(-16.492684 + (72.865517 / $temp) + 4.8386114 * log($temp)), 1);
//dd($S1);
if (strlen($S1) > 5) { // plus de 9999 heures (il fait trop froid ou trop chaud)
//dump($S1);
//dump($ep);exit;
$S1 = 1000;
}
$ep->setS1($S1);
//calcul S2
$S2 = round(exp(-16.417647 + (74.073111 / $temp) + 4.8611597 * log($temp)), 1);
if (strlen($S2) > 5) {
$S2 = 1000;
}
$ep->setS2($S2);
if (empty($humide)) {
$humide['nbre'] = 0;
}
//dd($ep);
$totalHeures = $ep->getNbreHeuresPluie() + $ep->getNbreHeuresHygroSup85();
if ($totalHeures >= $S1) {
$ep->setConta(true);
}
$this->em->persist($ep);
}//fin de chaque épisode pluvieux
// Flushing and clear data on queue
$this->em->flush();
// Detaches all objects from Doctrine for memory save
$this->em->clear();
//on travaille sur les épisodes prévis
// foreach ($episodesP as $ep) {
// $hum = $this->_calculHumideP($ep,$arrayPrevis);
// dd($hum);
// $humide = array();
// foreach ($hum as $h) {
// $humide = $h;
// }
// //on met à jour la table épisodes avec les infos de humide
// //et de S1 S2
// //pour avoir un objet épisode pluvieux complet
// if (!empty($humide)) {
// $ep->setDateDebHygroSup85($humide['debut']);
// $ep->setDateFinHygroSup85($humide['fin']);
// $ep->setNbreHeuresHygroSup85($humide['nbre']);
// $ep->setTempMoyHygroSup85($humide['temp']);
// }
// $temp = $ep->getTempMoyPluie();
// //calcul S1
// $S1 = round(exp(-16.492684 + (72.865517 / $temp) + 4.8386114 * log($temp)), 1);
// //dd($S1);
// if (strlen($S1) > 5) { // plus de 9999 heures (il fait trop froid ou trop chaud)
// //dump($S1);
// //dump($ep);exit;
// $S1 = 1000;
// }
// $ep->setS1($S1);
// //calcul S2
// $S2 = round(exp(-16.417647 + (74.073111 / $temp) + 4.8611597 * log($temp)), 1);
// if (strlen($S2) > 5) {
// $S2 = 1000;
// }
// $ep->setS2($S2);
// if (empty($humide)) {
// $humide['nbre'] = 0;
// }
// //dd($ep);
// $totalHeures = $ep->getNbreHeuresPluie() + $ep->getNbreHeuresHygroSup85();
// if ($totalHeures >= $S1) {
// $ep->setConta(true);
// }
// $this->em->persist($ep);
// }
//Maintenant pour chaque épisode pluvieux contaminant on calcule la durée d'incubation :
//on avance dans les mesures suivantes en calculant
//la T° moyenne par jour.
//À la fin de chaque jour D, on enregistre le nombre de jours J depuis la fin
//de l'épisode pluvieux, et on calcule la durée d'incubation Di qui est en jours.
//Dés que J >= Di on a l'apparition de taches et donc l'émission de spores (?????)
//On enregistre la date D et la durée D1 dans l'objet épisode
//on arrête soit parce qu'on a Di, soit parce qu'on a atteint la fin des mesures connues (et prévisionnelles)
//on récupère les épisodes contaminants
$episodesC = $this->episodeRepository
->findBy([
'conta' => true,
'site'=> $site
]);
//dd($episodesC);
//Pour chaque épisode pluvieux contaminant :
foreach ($episodesC as $ep) {
//on avance jour par jour dans les mesures
//en partant du début de la pluie ////////////////// A voir avec Regis
$epi = $this->_calculLatence($ep, $arrayPrevis = array());
// dd($epi);
$this->em->persist($epi);
$this->em->flush($epi);
} //fin de chaque $episodeC
return $this->render('/modele_odp/sortie.html.twig',array(
'site'=>$site
));
}
/**
* @Route("/modele/ODP/excel",name="app_modele_odp_excel")
*
* @return void
*/
public function excel(Request $request)
{
$siteId = $request->query->get('siteId');
//sortie Excel
return $this->modeleODPExcel->generateExcel($siteId);
}
/**
* @Route("/modele/ODP/graph",name="app_modele_odp_graph")
*
* @return void
*/
public function graph(Request $request)
{
$siteId = $request->query->get('siteId');
//sortie graphique
return $this->modeleODPgraph->generateGraph($siteId);
}
private function _recEpisodes($episodes,$siteId)
{
//dump($stationId);exit;
foreach ($episodes as $ep) {
// $d = substr($deb, 0, 10);
// $h = substr($deb, 11, 2);
$deb = new \DateTime($ep['debut']);
$fin = new \DateTime($ep['fin']);
//dump($deb);
//test existence
$existe = $this->episodeRepository->findDebFinSite($deb,$siteId);
//dump($existe);
if(!empty($existe)){
continue;
}else{
$epi = new Episode();
$epi->setSite($siteId);
$epi->setDateDebPluie($deb);
$epi->setDateFinPluie($fin);
// if ($ep['pluv'] > 500) {
// // dump($ep['pluv']);
// // dump($deb);
// // dump($fin);exit;
// continue;
// }
$epi->setPluvioTotale($ep['pluv']);
$epi->setNbreHeuresPluie($ep['nbre']);
$epi->setTempMoyPluie($ep['temp']);
//dd($epi);
$this->em->persist($epi);
$this->em->flush($epi);
}
}
}
private function _calculHumide($ep)
{
//dump($ep);
$fin = $ep->getDateFinPluie();
$site = $ep->getSite();
//dump($fin);exit;
$humide = array();
// 1 - on récupère la première hygro > 85%
//qui suit la fin de la pluie
//dump($station);exit;
$firstHygro = $this->_recupHygro85suivantes($fin, $limite = 1, $site);
if (!isset($firstHygro[0])) {
return $humide;
}
// dump($fin);
// dump($firstHygro);exit;
$firstDateMesureHygro = $firstHygro[0]->getDate();
//si l'intervalle entre la fin de la pluie ($fin)
//et la première mesure avec une hygro >= 85 %
//est de plus de 1 heure, alors on passe à l'épisode pluvieux suivant
$interval = $fin->diff($firstDateMesureHygro);
//s'il y a plus d'une heure (et pas un jour et une heure) de différence avec l'heure précédente
//dump($fin->fotmat('H'));
if ($interval->format("%d") > 0 || $interval->format("%h") > 1) {
return $humide;
}
//on récupère les 24 * 4 * 10 = 9600 mesures suivantes (10 jours)
//avec une hygro >= 85%
$hygros85 = $this->_recupHygro85suivantes($fin, $limite = 9600,$site);
//dd($hygros85);
//on ne garde que les premières hygros >= 85%
//consécutives dans le tableau tabHygros85
//avec un trou maxi de 1 hygro
$prec = new \DateTime();//valeur bidon pour démarrer la boucle
$origin = "";
$i = 1;
$tabHygros85 = array();
foreach ($hygros85 as $h) {
if ($i == 1) {
//on sait déjà qu'il n'y a pas plus d'une heure d'écart
//avec la fin de la pluie
$tabHygros85[$h->getDate()->format('Y-m-d H:i:s')] = $h;
$prec = $h->getDate();
} else {
$heureActuelle = $h->getDate();
$interval = $prec->diff($heureActuelle);
//s'il y a plus d'une heure (ou plus d'un jour)
//de différence avec l'heure précédente
//on s'arrête
if ($interval->format("%d") > 0 || $interval->format("%h") > 1) {
break;
} else {
$prec = $h->getDate();
$tabHygros85[$h->getDate()->format('Y-m-d H:i:s')] = $h;
}
}
$i++;
}
//Pour chaque hygro horaire on crée un éventuel épisode humide
//qui démarre à la première heure >= 85% et s'arrête à la dernière
//heure consécutive > 85% (avec un trou possible d'une heure <85%////////////////)
$i = 1;
foreach ($tabHygros85 as $h) {
$heure = $h->getDate();
if ($i == 1) {
$k= $h->getDate()->format('Y-m-d H:i:s');
$humide[$k]['nbre'] = 1;
$humide[$k]['hygro'] = $h->getU();
$humide[$k]['temp'] = $h->getT();
$humide[$k]['debut'] = $heure;
$humide[$k]['fin'] = $heure;
//origin est la date de début de l'épisode humide
$origin = $k;
//dump($humide);exit;
} else {
$humide[$origin]['nbre'] += 1;
$humide[$origin]['hygro'] += $h->getU();
$humide[$origin]['temp'] += $h->getT();
$humide[$origin]['fin'] = $heure;
}
$i++;
}
//dump($i);exit;
//on fait les calculs de moyennes
$humide[$origin]['hygro'] = round($humide[$origin]['hygro'] / $humide[$origin]['nbre'], 1);
$humide[$origin]['temp'] = round($humide[$origin]['temp'] / $humide[$origin]['nbre'], 1);
//on enregistre l'id de l'épisode pluvieux
$humide[$origin]['idEp'] = $h->getId();
//dump($humide);exit;
return $humide;
}
private function _calculHumideP($ep,$arrayPrevis)
{
$fin = new DateTime($ep['fin']);
//dump($fin);
$humide = array();
// 1 - on récupère la première hygro > 85%
//qui suit la fin de la pluie
$firstHygro = array();
foreach($arrayPrevis as $d => $a){
//dd($a);
$date = new DateTime($d);
if($date > $fin){
if($a['hum'] >= 0.85){
$firstHygro[0] = $arrayPrevis[$d];
}
break;
}
}
if (!isset($firstHygro[0])) {
return $humide;
}
$firstDateMesureHygro = $date;
//dump($fin);
//dd($firstDateMesureHygro);
//si l'intervalle entre la fin de la pluie ($fin)
//et la première mesure avec une hygro >= 85 %
//est de plus de 1 heure, alors on passe à l'épisode pluvieux suivant
$finOb = new DateTime($fin);
$firstDateMesureHygroOb = new DateTime($firstDateMesureHygro);
$interval = $finOb->diff($firstDateMesureHygroOb);
//s'il y a plus d'une heure (et pas un jour et une heure) de différence avec l'heure précédente
//dump($fin->fotmat('H'));
if ($interval->format("%d") > 0 || $interval->format("%h") > 1) {
return $humide;
}
//on ne garde que les premières hygros >= 85%
//consécutives dans le tableau tabHygros85
//avec un trou maxi de 1 hygro
$prec = new \DateTime();//valeur bidon pour démarrer la boucle
$origin = "";
$i = 1;
$tabHygros85 = array();
foreach ($arrayPrevis as $h) {
if ($i == 1) {
//on sait déjà qu'il n'y a pas plus d'une heure d'écart
//avec la fin de la pluie
$tabHygros85[$h->getDate()->format('Y-m-d H:i:s')] = $h;
$prec = $h->getDate();
} else {
$heureActuelle = $h->getDate();
$interval = $prec->diff($heureActuelle);
//s'il y a plus d'une heure (ou plus d'un jour)
//de différence avec l'heure précédente
//on s'arrête
if ($interval->format("%d") > 0 || $interval->format("%h") > 1) {
break;
} else {
$prec = $h->getDate();
$tabHygros85[$h->getDate()->format('Y-m-d H:i:s')] = $h;
}
}
$i++;
}
//Pour chaque hygro horaire on crée un éventuel épisode humide
//qui démarre à la première heure >= 85% et s'arrête à la dernière
//heure consécutive > 85% (avec un trou possible d'une heure <85%////////////////)
$i = 1;
foreach ($tabHygros85 as $h) {
$heure = $h->getDate();
if ($i == 1) {
$k= $h->getDate()->format('Y-m-d H:i:s');
$humide[$k]['nbre'] = 1;
$humide[$k]['hygro'] = $h->getU();
$humide[$k]['temp'] = $h->getT();
$humide[$k]['debut'] = $heure;
$humide[$k]['fin'] = $heure;
//origin est la date de début de l'épisode humide
$origin = $k;
//dump($humide);exit;
} else {
$humide[$origin]['nbre'] += 1;
$humide[$origin]['hygro'] += $h->getU();
$humide[$origin]['temp'] += $h->getT();
$humide[$origin]['fin'] = $heure;
}
$i++;
}
//dump($i);exit;
//on fait les calculs de moyennes
$humide[$origin]['hygro'] = round($humide[$origin]['hygro'] / $humide[$origin]['nbre'], 1);
$humide[$origin]['temp'] = round($humide[$origin]['temp'] / $humide[$origin]['nbre'], 1);
//on enregistre l'id de l'épisode pluvieux
$humide[$origin]['idEp'] = $h->getId();
//dump($humide);exit;
return $humide;
}
private function _recupHygro85suivantes($fin, $limite,$siteId)
{
$site = $this->siteRepository->find($siteId);
$hygros = $this->meteoRepository
->findHyg($fin, $limite,$site);
return $hygros;
}
private function _calculLatence($ep, $arrayPrevis)
{
$J = 1;
$dat = $ep->getDateDebPluie();
$date = clone $dat;
$siteId = $ep->getSite();
$site = $this->siteRepository->find($siteId);
//dump($date);
//moyenne des températures de la journée $date
$moyenneJour = $this->meteoRepository->recupTempMoyJour($date,$site);
//dd($moyenneJour);
if ($moyenneJour == "vide") { //pas de mesures pour cette date
//dump('vide et premier new = 1');
$ep->setLatence(' >' . $J); //l'espace avant le > est important pour strpos dans la feuille excel
$ep->setTempMoyLatence(null);
$ep->setDateTache($date);
//dump($ep);exit;
return $ep;
} else {
$moyJ = $moyenneJour / $J;
$moy = $moyenneJour;
//jours suivants
//dump($ep);
for ($i = 1; $i <= 300; $i++) {
$date->add(new \DateInterval('P1D'));
//dump($ep);
$J++;
//dump($J);
//dump($date);
$moyenneJour = $this->meteoRepository->recupTempMoyJour($date,$site);
//dump($moyenneJour);
if ($moyenneJour == "vide") { //pas de mesures pour cette date
//dump('vide et second new = 1');
//dd($ep);
if (array_key_exists($date->format('Y-m-d'), $arrayPrevis)) {
$moyenneJour = $arrayPrevis[$date->format('Y-m-d')];
// dd($moyenneJour);
} else {
$ep->setLatence(' >' . $J); //l'espace avant le > est important pour strpos dans la feuille excel
$ep->setTempMoyLatence(null);
$ep->setDateTache(null);
//dd($ep);
return $ep;
}
} else {
if (is_numeric($moyenneJour)) {
$moy += $moyenneJour;
} else {
//dump($moyenneJour);
exit;
}
// dump($moy);
//dump($J);
$moyJ = $moy / $J;
//dump($moyJ);
//calcul Di
$Di = 365.76 - 89.57 * $moyJ + 9.12 * pow($moyJ, 2) - 0.43 * pow($moyJ, 3) + 0.0078 * pow($moyJ, 4);
//dump('Di = '.$Di);
if ($J >= $Di) {
//on arrête pour cette épisode
//dump($J);
//dump($ep);
// dump($Di);
//dump($moyJ);
$ep->setLatence($J);
$ep->setTempMoyLatence(round($moyJ, 1));
$ep->setDateTache($date);
//dump($ep);exit;
return $ep;
}
//dump($ep);
}
} //fin de $i
}
}
}