#!/usr/bin/python3
# -*- coding: utf-8 -*-
########################################################################
#
# This file is part of python module <pyspc>.
# Copyright (C) 2013-2021 R. Marty
# (renaud.marty@developpement-durable.gouv.fr)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see COPYING.txt).
# If not, see <http://www.gnu.org/licenses/>.
#
########################################################################
"""
Données d'observation et de prévision - XML Sandre
"""
from collections import namedtuple
from datetime import datetime as dt
from xml.etree import ElementTree
from pyspc.convention.sandre import DATATYPES, FCST_COLS, OBS_COLS
import pyspc.core.exception as _exception
DATATYPES = sorted([d
for d in DATATYPES
if d.startswith('data')
or d.startswith('level')
or d.startswith('flow')])
ComSimul = namedtuple(
'ComSimul', ['runtime', 'code', 'name'], defaults=[None, None, None])
[docs]
class Sandre():
"""Structure liée aux données XML Sandre."""
[docs]
def __init__(self, filename=None):
"""
Initialisation de l'instance de la classe XML Sandre.
Parameters
----------
filename : str
Fichier local au format XML
"""
self.filename = filename
def __str__(self):
"""Afficher les données de l'instance XML Sandre."""
text = """
*************************************
*********** XML Sandre - Data *******
*************************************
* FICHIER = {filename}
*************************************
"""
return text.format(**vars(self))
[docs]
def read(self):
"""
Lire le fichier XML du Sandre.
Examples
--------
>>> import pyspc.data.sandre as _sandre
Exemple d'observations hydro (Q)
>>> f = 'data/data/sandre/dataobs_hydro_Q.xml'
>>> sandre = _sandre.Sandre(filename=f)
>>> content = sandre.read()
>>> content
Message du 2016-05-13 13:41:49 de version 1.1
Emetteur: Intervenant SANDRE 1537::<sans nom> [0 contact] [None]
Destinataire: Intervenant SIRET 13000930100016::<sans nom> [1 contact]
[Contact 398::<sans civilite> <sans nom> <sans prenom>
[intervenant 13000930100016]]
Contenu:
0 intervenants
0 siteshydro
0 sitesmeteo
0 seuilshydro
0 seuilsmeteo
0 modelesprevision
0 evenements
0 courbestarage
0 jaugeages
0 courbescorrection
3 serieshydro
0 seriesmeteo
0 seriesobselab
0 simulations
>>> for s in content.serieshydro:
... print(s.entite.code, s.grandeur)
... print(s.observations)
res mth qal cnt statut
dte
2016-04-17 01:00:00 45267.567568 8 16 0 4
2016-04-17 02:00:00 47105.405405 8 16 0 4
2016-04-17 03:00:00 48497.333333 8 16 0 4
2016-04-17 04:00:00 50470.666667 8 16 0 4
2016-04-17 05:00:00 50964.000000 8 16 0 4
2016-04-17 06:00:00 51950.666667 8 16 0 4
2016-04-17 07:00:00 52444.000000 8 16 0 4
2016-04-17 08:00:00 52444.000000 8 16 0 4
2016-04-17 09:00:00 52937.333333 8 16 0 4
2016-04-17 10:00:00 53430.666667 8 16 0 4
2016-04-17 11:00:00 53924.000000 8 16 0 4
2016-04-17 12:00:00 54417.333333 8 16 0 4
2016-04-17 13:00:00 54417.333333 8 16 0 4
2016-04-17 14:00:00 55404.000000 8 16 0 4
2016-04-17 15:00:00 56390.666667 8 16 0 4
2016-04-17 16:00:00 57377.333333 8 16 0 4
2016-04-17 17:00:00 58364.000000 8 16 0 4
2016-04-17 18:00:00 59350.666667 8 16 0 4
2016-04-17 19:00:00 60540.000000 8 16 0 4
2016-04-17 20:00:00 60540.000000 8 16 0 4
2016-04-17 21:00:00 60540.000000 8 16 0 4
2016-04-17 22:00:00 60540.000000 8 16 0 4
2016-04-17 23:00:00 60540.000000 8 16 0 4
res mth qal cnt statut
dte
2016-04-18 59350.666667 8 16 0 4
res mth qal cnt statut
dte
2016-04-18 01:00:00 58857.333333 8 16 0 4
2016-04-18 02:00:00 58364.000000 8 16 0 4
2016-04-18 03:00:00 57870.666667 8 16 0 4
2016-04-18 04:00:00 56884.000000 8 16 0 4
2016-04-18 05:00:00 56390.666667 8 16 0 4
2016-04-18 06:00:00 55404.000000 8 16 0 4
2016-04-18 07:00:00 54417.333333 8 16 0 4
2016-04-18 08:00:00 53430.666667 8 16 0 4
2016-04-18 09:00:00 52937.333333 8 16 0 4
2016-04-18 10:00:00 50470.666667 8 16 0 4
2016-04-18 11:00:00 52444.000000 8 16 0 4
2016-04-18 12:00:00 50964.000000 8 16 0 4
2016-04-18 13:00:00 49484.000000 8 16 0 4
2016-04-18 14:00:00 48990.666667 8 16 0 4
2016-04-18 15:00:00 48497.333333 8 16 0 4
2016-04-18 16:00:00 48024.324324 8 16 0 4
2016-04-18 17:00:00 47105.405405 8 16 0 4
2016-04-18 18:00:00 46186.486486 8 16 0 4
2016-04-18 19:00:00 45727.027027 8 16 0 4
2016-04-18 20:00:00 44808.108108 8 16 0 4
2016-04-18 21:00:00 44348.648649 8 16 0 4
2016-04-18 22:00:00 43429.729730 8 16 0 4
2016-04-18 23:00:00 42510.810811 8 16 0 4
Exemple d'observations élaborées hydro (Q)
>>> f = 'data/data/sandre/K0550010_198009060000_198010060000_Q_obs.xml'
>>> sandre = _sandre.Sandre(filename=f)
>>> content = sandre.read()
>>> content
Message du 2021-11-08 16:46:41 de version 1.1
Emetteur: Intervenant SANDRE 1537::<sans nom> [0 contact] [None]
Destinataire: Intervenant SANDRE 1528::<sans nom> [1 contact]
[Contact 398::<sans civilite> <sans nom> <sans prenom>
[intervenant 1528]]
Contenu:
0 intervenants
0 siteshydro
0 sitesmeteo
0 seuilshydro
0 seuilsmeteo
0 modelesprevision
0 evenements
0 courbestarage
0 jaugeages
0 courbescorrection
0 serieshydro
0 seriesmeteo
1 seriesobselab
0 simulations
>>> for s in content.seriesobselab:
... print(s.entite.code, s.typegrd)
... print(s.observations)
K0550010 QmnJ
res mth qal cnt statut
dte
1980-09-06 11100.0 12 20 0 16
1980-09-07 11600.0 12 20 0 16
1980-09-08 9600.0 12 20 0 16
1980-09-09 11600.0 12 20 0 16
1980-09-10 12200.0 12 20 0 16
1980-09-11 12700.0 12 20 0 16
1980-09-12 10600.0 12 20 0 16
1980-09-13 10600.0 12 20 0 16
1980-09-14 9600.0 12 20 0 16
1980-09-15 8650.0 12 20 0 16
1980-09-16 8650.0 12 20 0 16
1980-09-17 7750.0 12 20 0 16
1980-09-18 7750.0 12 20 0 16
1980-09-19 7750.0 12 20 0 16
1980-09-20 5750.0 12 20 0 16
1980-09-21 770000.0 12 20 0 16
1980-09-22 392000.0 12 20 0 16
1980-09-23 120000.0 12 20 0 16
1980-09-24 81000.0 12 20 0 16
1980-09-25 56500.0 12 20 0 16
1980-09-26 47400.0 12 20 0 16
1980-09-27 41500.0 12 20 0 16
1980-09-28 34500.0 12 20 0 16
1980-09-29 30900.0 12 20 0 16
1980-09-30 84500.0 12 20 0 16
1980-10-01 26200.0 12 20 0 16
1980-10-02 24400.0 12 20 0 16
1980-10-03 23800.0 12 20 0 16
1980-10-04 23200.0 12 20 0 16
1980-10-05 23200.0 12 20 0 16
1980-10-06 22600.0 12 20 0 16
Exemple de prévision hydro
>>> f = 'data/data/sandre/datafcst_hydro.xml'
>>> sandre = _sandre.Sandre(filename=f)
>>> content = sandre.read()
>>> content
Message du 2016-05-13 13:42:25 de version 1.1
Emetteur: Intervenant SANDRE 1537::<sans nom> [0 contact] [None]
Destinataire: Intervenant SIRET 13000930100016::<sans nom> [1 contact]
[Contact 398::<sans civilite> <sans nom> <sans prenom>
[intervenant 13000930100016]]
Contenu:
0 intervenants
0 siteshydro
0 sitesmeteo
0 seuilshydro
0 seuilsmeteo
0 modelesprevision
0 evenements
0 courbestarage
0 jaugeages
0 courbescorrection
0 serieshydro
0 seriesmeteo
0 seriesobselab
1 simulations
>>> for s in content.simulations:
... print(s.entite.code, s.grandeur)
... print(s.previsions_tend)
K1930010 Q
dte tend
2016-04-20 06:00:00 moy 657905.029297
min 651244.995117
max 661364.013672
2016-04-20 07:00:00 moy 654122.985840
min 647578.979492
max 657557.983398
2016-04-20 08:00:00 moy 648411.010742
min 637543.029785
max 654010.009766
2016-04-20 09:00:00 moy 644525.024414
min 629979.980469
max 652531.005859
2016-04-20 10:00:00 moy 636773.986816
min 619005.004883
max 646870.971680
2016-04-20 11:00:00 moy 634590.026855
min 614572.021484
max 646533.020020
2016-04-20 12:00:00 moy 621318.969727
min 600044.982910
max 634541.992188
Name: res, dtype: float64
Exemple d'observations météo
>>> f = 'data/data/sandre/dataobs_meteo.xml'
>>> sandre = _sandre.Sandre(filename=f)
>>> content = sandre.read()
>>> content
Message du 2016-05-13 13:41:56 de version 1.1
Emetteur: Intervenant SANDRE 1537::<sans nom> [0 contact] [None]
Destinataire: Intervenant SIRET 13000930100016::<sans nom> [1 contact]
[Contact 398::<sans civilite> <sans nom> <sans prenom>
[intervenant 13000930100016]]
Contenu:
0 intervenants
0 siteshydro
0 sitesmeteo
0 seuilshydro
0 seuilsmeteo
0 modelesprevision
0 evenements
0 courbestarage
0 jaugeages
0 courbescorrection
0 serieshydro
1 seriesmeteo
0 seriesobselab
0 simulations
>>> for s in content.seriesmeteo:
... print(s.grandeur.sitemeteo.code, s.grandeur.typemesure)
... print(s.observations)
023209001 RR # Le code météo est forcé sur 9 caractères par libhydro
res mth qal qua ctxt statut
dte
2016-04-15 12:00:00 0.0 0 16 100.0 0 4
2016-04-15 13:00:00 0.0 0 16 100.0 0 4
2016-04-15 14:00:00 0.0 0 16 100.0 0 4
2016-04-15 15:00:00 4.0 0 16 100.0 0 4
2016-04-15 16:00:00 8.0 0 16 100.0 0 4
2016-04-15 17:00:00 8.0 0 16 100.0 0 4
2016-04-15 18:00:00 2.0 0 16 100.0 0 4
2016-04-15 19:00:00 4.0 0 16 100.0 0 4
2016-04-15 20:00:00 2.0 0 16 100.0 0 4
2016-04-15 21:00:00 2.0 0 16 100.0 0 4
2016-04-15 22:00:00 38.0 0 16 100.0 0 4
2016-04-15 23:00:00 10.0 0 16 100.0 0 4
2016-04-16 00:00:00 24.0 0 16 100.0 0 4
2016-04-16 01:00:00 12.0 0 16 100.0 0 4
2016-04-16 02:00:00 2.0 0 16 100.0 0 4
2016-04-16 03:00:00 2.0 0 16 100.0 0 4
2016-04-16 04:00:00 0.0 0 16 100.0 0 4
2016-04-16 05:00:00 8.0 0 16 100.0 0 4
2016-04-16 06:00:00 14.0 0 16 100.0 0 4
Exemple de Vigicrues
>>> f = 'data/webservice/vigicrues/vigicrues_obs_202101291400.xml'
>>> sandre = _sandre.Sandre(filename=f)
>>> content = sandre.read()
>>> content
Message du 2021-03-03 08:23:01.013681 de version 1.1
Emetteur: Intervenant SANDRE 1537::<sans nom> [0 contact] [None]
Destinataire: Intervenant SANDRE 0::<sans nom> [0 contact] [None]
Contenu:
0 intervenants
0 siteshydro
0 sitesmeteo
0 seuilshydro
0 seuilsmeteo
0 modelesprevision
0 evenements
0 courbestarage
0 jaugeages
0 courbescorrection
1 serieshydro
0 seriesmeteo
0 seriesobselab
0 simulations
>>> for s in content.serieshydro:
... print(s.entite.code, s.grandeur)
... print(s.observations)
K055001010 Q
res mth qal cnt statut
dte
2021-01-27 12:00:00 51000.0 0 16 0 4
2021-01-27 13:00:00 50700.0 0 16 0 4
2021-01-27 14:00:00 50600.0 0 16 0 4
2021-01-27 15:00:00 50600.0 0 16 0 4
2021-01-27 16:00:00 50400.0 0 16 0 4
2021-01-27 17:00:00 50700.0 0 16 0 4
2021-01-27 18:00:00 50300.0 0 16 0 4
2021-01-27 19:00:00 50700.0 0 16 0 4
2021-01-27 20:00:00 49400.0 0 16 0 4
2021-01-27 21:00:00 48300.0 0 16 0 4
2021-01-27 22:00:00 48800.0 0 16 0 4
2021-01-27 23:00:00 52800.0 0 16 0 4
2021-01-28 00:00:00 54100.0 0 16 0 4
2021-01-28 00:05:00 54100.0 0 16 0 4
2021-01-28 00:10:00 54100.0 0 16 0 4
2021-01-28 00:15:00 54100.0 0 16 0 4
2021-01-28 00:20:00 54100.0 0 16 0 4
2021-01-28 00:25:00 54100.0 0 16 0 4
2021-01-28 00:30:00 54100.0 0 16 0 4
2021-01-28 00:35:00 54100.0 0 16 0 4
2021-01-28 00:50:00 54100.0 0 16 0 4
2021-01-28 00:55:00 54100.0 0 16 0 4
2021-01-28 01:00:00 54100.0 0 16 0 4
2021-01-28 01:05:00 54100.0 0 16 0 4
2021-01-28 01:10:00 54100.0 0 16 0 4
2021-01-28 01:15:00 54100.0 0 16 0 4
2021-01-28 01:20:00 54100.0 0 16 0 4
2021-01-28 01:25:00 54100.0 0 16 0 4
2021-01-28 01:30:00 54100.0 0 16 0 4
2021-01-28 01:35:00 54100.0 0 16 0 4
2021-01-28 01:40:00 54100.0 0 16 0 4
2021-01-28 01:45:00 54100.0 0 16 0 4
2021-01-28 01:50:00 54100.0 0 16 0 4
2021-01-28 01:55:00 54100.0 0 16 0 4
2021-01-28 02:00:00 54100.0 0 16 0 4
See Also
--------
Repose sur la libhydro :
https://gitlab.com/vigicrues/hydro3/libhydro
"""
from libhydro.conv import xml as _xml
return _xml.Message.from_file(self.filename)
[docs]
@staticmethod
def check_dtype(dtype):
"""
Contrôler s'il s'agit bien d'une donnée autorisée.
Parameters
----------
dtype : str
Type de donnée à contrôler
"""
try:
DATATYPES.index(dtype)
except ValueError as ve:
raise ValueError(f"Export Sandre '{dtype}' incorrect") from ve
[docs]
@staticmethod
def process_comsim(xml_comsim):
"""Extraire le code simulation."""
try:
xmlstring = xml_comsim.replace('{', '<').replace('}', '>')
except AttributeError:
return ComSimul()
root = ElementTree.fromstring(xmlstring)
try:
runtime = dt.strptime(root.find('DtBaseSimul').text,
'%Y-%m-%dT%H:%M:%S')
except ValueError:
runtime = None
except AttributeError:
runtime = None
try:
scen_code = root.find('CodeScenarioSimul').text
except AttributeError:
scen_code = None
try:
scen_name = root.find('NomScenarioSimul').text
except AttributeError:
scen_name = None
return ComSimul(runtime, scen_code, scen_name)
[docs]
@staticmethod
def concat(filename=None, filenames=None, runtime=None,
sender=None, user=None, target=None):
"""
Fusionner plusieurs fichiers xml Sandre.
Parameters
----------
filename : str
Nom du fichier xml à écrire
filenames : str
Noms des fichiers xml à lire
runtime : datetime
Date de production de la donnée/prévision
sender : str
Identifiant de l'emetteur
user : str
Identifiant du contact
target : str
Identifiant du destinataire
Returns
-------
filename : str
Nom du fichier xml à écrire
"""
from libhydro.conv.xml import Message, Scenario
from libhydro.core.intervenant import Contact, Intervenant
# ---------------------------------------------------------------------
# 0- Contrôles
# ---------------------------------------------------------------------
_exception.check_str(filename)
_exception.check_listlike(filenames)
_exception.check_str(sender)
_exception.check_str(user)
_exception.check_str(target)
# ---------------------------------------------------------------------
# 1- Scénario Sandre
# ---------------------------------------------------------------------
user = Intervenant(code=user)
sender = Contact(code=sender, intervenant=user)
target = Intervenant(code=target)
xml_scen = Scenario(
emetteur=sender, destinataire=target, dtprod=runtime)
# ---------------------------------------------------------------------
# 2- Lecture des fichiers Sandre
# ---------------------------------------------------------------------
content = {}
attrs = ['intervenants',
'siteshydro', 'sitesmeteo',
'seuilshydro', 'seuilsmeteo',
'modelesprevision', 'evenements',
'courbestarage', 'jaugeages', 'courbescorrection',
'serieshydro', 'seriesmeteo', 'seriesobselab', 'simulations']
for f in filenames:
m = Message.from_file(f)
for att in attrs:
if hasattr(m, att):
content.setdefault(att, [])
content[att].extend(getattr(m, att))
# ---------------------------------------------------------------------
# 5- Message Sandre
# ---------------------------------------------------------------------
msg = Message(scenario=xml_scen, **content)
msg.write(filename, force=True, bdhydro=True)
# ---------------------------------------------------------------------
# 6- Retour
# ---------------------------------------------------------------------
return filename
[docs]
def write(self, data=None, datatype=None, runtime=None,
timedelta=None, sender=None, user=None, target=None):
"""
Ecrire un fichier xml Sandre.
Parameters
----------
data : pandas.DataFrame
Tableau de données
datatype : str
Type de donnée.
Seuls les types commençant par 'data' sont autorisés
runtime : datetime
Date de production de la donnée/prévision
timedelta : timedelta
Pas de temps de la donnée
sender : str
Identifiant de l'emetteur
user : str
Identifiant du contact
target : str
Identifiant du destinataire
Returns
-------
filename : str
Nom du fichier xml à écrire
Notes
-----
- si datatype = 'data_obs_hydro', les colonnes du dataframe sont
nommées de la façon suivante pour définir les méta-données
- 'Location' : code du lieu
- 'Varname' : grandeur
- si datatype = 'data_obs_meteo', les colonnes du dataframe sont
nommées de la façon suivante pour définir les méta-données
- 'Location' : code du lieu
- 'Varname' : grandeur
- si datatype = 'data_fcst_hydro', les colonnes du dataframe sont
nommées de la façon suivante pour définir les méta-données
- 'Location' : code du lieu
- 'Varname' : grandeur
- 'Runtime': date de production
- 'Model' : code du modèle
- 'Scenario' : code du scénario
- 'Prob' : nom de la tendance, parmi ['min', 'moy', 'max']
"""
from libhydro.conv.xml import Message, Scenario
from libhydro.core.intervenant import Contact, Intervenant
# ---------------------------------------------------------------------
# 0- Contrôles
# ---------------------------------------------------------------------
_exception.check_dataframe(data)
_exception.check_str(datatype)
_exception.raise_valueerror(
not datatype.startswith('data'),
f"Type de données '{datatype}' incompatible")
_exception.check_str(self.filename)
_exception.check_str(sender)
_exception.check_str(user)
_exception.check_str(target)
if runtime is None:
runtime = dt.utcnow()
_exception.check_dt(runtime)
# ---------------------------------------------------------------------
# 1- Scénario Sandre
# ---------------------------------------------------------------------
user = Intervenant(code=user)
sender = Contact(code=sender, intervenant=user)
target = Intervenant(code=target)
xml_scen = Scenario(
emetteur=sender, destinataire=target, dtprod=runtime)
# ---------------------------------------------------------------------
# 2- DATA OBS HYDRO
# ---------------------------------------------------------------------
obss = _sandre_obss(data, datatype, runtime)
# ---------------------------------------------------------------------
# 3- DATA OBS METEO
# ---------------------------------------------------------------------
mets = _sandre_mets(data, datatype, runtime, timedelta)
# ---------------------------------------------------------------------
# 4- DATA FCST HYDRO
# ---------------------------------------------------------------------
sims = _sandre_sims(data, datatype, xml_scen)
# ---------------------------------------------------------------------
# 5- Message Sandre
# ---------------------------------------------------------------------
msg = Message(scenario=xml_scen, serieshydro=obss, seriesmeteo=mets,
simulations=sims)
msg.write(self.filename, force=True, bdhydro=True)
# ---------------------------------------------------------------------
# 6- Retour
# ---------------------------------------------------------------------
return self.filename
[docs]
@staticmethod
def get_types():
"""
Renvoyer la liste des données du XML Sandre.
Returns
-------
list
Types de données de la XML Sandre
"""
return sorted(DATATYPES)
def _sandre_obss(data, datatype, runtime):
"""Créer une liste de séries d'observation hydrométrique."""
from libhydro.core.sitehydro import Sitehydro, Station
from libhydro.core.obshydro import Serie
obss = []
if datatype == 'data_obs_hydro':
for p in OBS_COLS:
if p not in data.columns.names:
raise ValueError(f"Méta-donné '{p}' manquante")
# Ordre du multi-index
data = data.reorder_levels(OBS_COLS, axis=1)
for c in data.columns:
loc = c[0]
varname = c[1]
if varname == 'Q' and len(loc) < 10:
loc = Sitehydro(code=loc[:8])
mth = 8
else:
loc = Station(code=loc[:10])
mth = 0
df = data[c].to_frame().dropna()
df.columns = ['res']
df.index.name = 'dte'
df['mth'] = mth
df['qal'] = 16
df['cnt'] = 0
df['statut'] = 4
obs = Serie(
entite=loc, grandeur=varname, observations=df,
dtprod=runtime, dtdeb=df.index[0], dtfin=df.index[-1])
obss.append(obs)
return obss
def _sandre_mets(data, datatype, runtime, timedelta):
"""Créer une liste de séries d'observation météorologique."""
from libhydro.core.sitemeteo import Grandeur, Sitemeteo
from libhydro.core.obsmeteo import Serie
mets = []
if datatype == 'data_obs_meteo':
for p in OBS_COLS:
if p not in data.columns.names:
raise ValueError(f"Méta-donné '{p}' manquante")
# Ordre du multi-index
data = data.reorder_levels(OBS_COLS, axis=1)
for c in data.columns:
loc = Sitemeteo(code=c[0])
varname = Grandeur(typemesure=c[1], sitemeteo=loc)
if timedelta is None:
timedelta = 0
df = data[c].to_frame().dropna()
df.columns = ['res']
df.index.name = 'dte'
df['mth'] = 0
df['qal'] = 16
df['qua'] = 100
df['ctxt'] = 0
df['statut'] = 4
met = Serie(grandeur=varname, observations=df,
dtprod=runtime, duree=timedelta)
mets.append(met)
return mets
def _sandre_sims(data, datatype, xml_scen):
"""Créer une liste de simulations (prévisions avec tendances)."""
from libhydro.core.sitehydro import Sitehydro, Station
from libhydro.core.modeleprevision import Modeleprevision
from libhydro.core.simulation import Simulation
sims = []
if datatype == 'data_fcst_hydro':
for p in FCST_COLS:
if p not in data.columns.names:
raise ValueError(f"Méta-donné '{p}' manquante")
# Ordre du multi-index
data = data.reorder_levels(FCST_COLS, axis=1)
# Boucle sur les simulations, éléments communs :
# 'Location', 'Varname', 'Runtime', 'Model', 'Scenario'
metas = sorted({tuple(c[:-1]) for c in data.columns})
for meta in metas:
loc = meta[0]
varname = meta[1]
if varname == 'Q':
loc = Sitehydro(code=loc[:8])
else:
loc = Station(code=loc[:10])
model = Modeleprevision(code=meta[3])
df = data.xs(key=meta, axis=1).stack().to_frame()
df.index.names = ['dte', 'tend']
df.columns = ['res']
df['incertdte'] = 0
comment = "{ContexteSimul}"
comment += "{DtBaseSimul}" + meta[2].strftime(
"%Y-%m-%dT%H:%M:%S") + "{/DtBaseSimul}"
comment += "{CodeScenarioSimul}" + meta[-1] + \
"{/CodeScenarioSimul}"
comment += "{/ContexteSimul}"
sim = Simulation(
entite=loc, grandeur=varname, modeleprevision=model,
# public=True,
statut=16, dtprod=meta[2],
# intervenant=user,
contact=xml_scen.emetteur.contact,
intervenant=xml_scen.emetteur.intervenant,
previsions_tend=df, commentaire=comment
)
sims.append(sim)
return sims