diff --git a/doc/dev/scenario.org b/doc/dev/scenario.org
new file mode 100644
index 00000000..5200c45f
--- /dev/null
+++ b/doc/dev/scenario.org
@@ -0,0 +1,661 @@
+# senario.org -- Pamhyr developers documentation
+# Copyright (C) 2023-2024 INRAE
+#
+# 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. If not, see .
+
+# -*- coding: utf-8 -*-
+
+#+STARTUP: indent show2levels
+
+#+INCLUDE: ../tools/macro.org
+#+INCLUDE: ../tools/latex.org
+
+#+TITLE: Scenario implementation in Pamhyr2: \textbf{Preparatory work}
+#+SUBTITLE: Version: {{{version}}}
+#+AUTHOR: {{{INRAE}}}
+
+#+OPTIONS: toc:t
+#+LANGUAGE: UKenglish
+
+#+latex: \newpage
+
+* COMMENT tools
+
+#+begin_src emacs-lisp :export none
+ (add-to-list 'org-structure-template-alist
+ '("p" "#+begin_src python :python python3 :results output\n\n#+end_src"))
+#+end_src
+
+#+RESULTS:
+#+begin_example
+((p #+begin_src python :python python3 :results output
+
+,#+end_src) (d . #+name: graph-XXX
+,#+header: :results drawer
+,#+header: :exports results
+,#+header: :post attr_wrap(width="12cm", data=*this*, name="graph-XXX", caption="Graph XXX", float="t")
+,#+begin_src dot :file "images/graph-XXX.png" :cache no
+digraph {
+ bgcolor="transparent";
+ node[colorscheme=set19,shape=box,style="filled",fillcolor=9];
+}
+,#+end_src) (p . src python :python python3 :results output :noweb yes
+
+src) (t . EXPORT latex
+\begin{table}
+\centering
+\resizebox{0.6\linewidth}{!}{
+
+}
+%\vspace{0.5pt}
+%\caption{Number of tests by errors types}
+\end{table}
+,#+E) (B . src shell :session *shell* :results output :exports both) (a . export ascii) (c . center) (C . comment) (e . example) (E . export) (h . export html) (l . export latex) (q . quote) (s . src) (v . verse))
+#+end_example
+
+#+name: dbg-execute
+#+begin_src python :python python3 :results output :noweb yes
+ def execute(db, query):
+ print(query)
+ return db.execute(query)
+#+end_src
+
+#+RESULTS: dbg-execute
+
+#+name: execute
+#+begin_src python :python python3 :results output :noweb yes
+ def execute(db, query):
+ return db.execute(query)
+#+end_src
+
+#+RESULTS: execute
+
+* Principe
+
+** Scenario
+
+A scenario is defined by a name, a description and a parent
+scenario. If a scenario as no parent, parent value is =None=. So, in
+Pamhyr2 the list of scenario must by a tree with a root defined by a
+default scenarios with no parent.
+
+#+begin_src sql
+ CREATE TABLE scenario(
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL, -- Name of the scenario
+ description TEXT NOT NULL, -- Rich text description
+ parent_id INTEGER REFERENCES scenario(id) -- Recursive references
+ -- for parent scenario
+ )
+#+end_src
+
+** Data
+
+Each data is associated with one and only one scenario. This senario
+is defined by the =id=. So, each data structure who can saved in DB
+must add the following lines in table définition:
+
+#+begin_src sql
+ scenario_id INTEGER NOT NULL,
+ FOREIGN KEY(scenario_id) REFERENCES scenario(id)
+#+end_src
+
+To avoid, at least, memory usage exploitation, by default, a scenario
+must saved only the modified data from its parent. This contrains
+require to wrap any data modification to update the data scenario id
+to current scenario id in source code. In addition, we need to modify
+the data loading méthode to take in considération this recursive
+dependencies.
+
+#+CAPTION: Recursive loading method
+#+begin_src python :python python3 :results output :noweb yes
+ def rec_load(cls, db, current_scenario):
+ # Default case, end of recursion
+ if current_scenario is None:
+ return [] # Default value
+
+ table = db.execute(f" WHERE scenario_id = {current_scenario}")
+
+ # If no data for this scenario, recursion
+ if len(table) == 0:
+ parent_id = db.get_parent_id(current_scenario)
+ return cls.rec_load(db, parent_id)
+
+ # Otherelse, parse data and return...
+#+end_src
+
+With this method, modify a data in parent scenario, modify this data
+in child scenario too. Unless is value has been previously modified in
+the child scenario. Deny tree node modification, except for leaf.
+
+This method work, but it dont allow to delete data un child scenarios,
+because if we dont found data for this scenario we search for parent
+scenario. So, we need a condition to stop recursion in case of data
+deletion in child scenario. To stop the recurtion, we can use a dummy
+data flag. By default, this flags is =false=, but if this flags is
+=true= the data is ignored at loading.
+
+So, we can use this flags for each data structure who can saved in DB:
+
+#+begin_src sql
+ is_dummy BOOLEAN, -- True if this data as been deleted
+#+end_src
+
+Modify the loading method:
+
+#+CAPTION: Recursive loading method with possible dummy data
+#+begin_src python :python python3 :results output :noweb yes
+ def rec_load_2(cls, db, current_scenario):
+ # Default case, end of recursion
+ if current_scenario is None:
+ return [] # Default value
+
+ table = db.execute(f" WHERE scenario_id = {current_scenario}")
+
+ # If no data for this scenario, recursion
+ if len(table) == 0:
+ parent_id = db.get_parent_id(current_scenario)
+ return cls.rec_load(db, parent_id)
+
+ for data in table:
+ if is_dummy(data):
+ continue
+
+ # Otherelse, parse data ...
+
+ # return ...
+#+end_src
+
+#+RESULTS:
+
+And add a data reduction method:
+
+#+caption: Data reduction method for data subtree
+#+begin_src python :python python3 :results output :noweb yes
+ def reduce_change(self):
+ # Get the greater scenario
+ scenar = reduce(
+ lambda acc, x: max(acc, x._scenario),
+ self._values,
+ self._scenario
+ )
+
+ # Apply change on this subtree
+ self._scenario = scenar
+
+ if is_dummy(self): # There are no more subtree
+ self.values = []
+ else: # Update data subtree scenario id
+ for value in self._values:
+ value.set_scenario(self._scenario)
+ # Dummy data is no more necessary in this subtree
+ self._values = list(
+ filter(
+ lambda v: not is_dummy(v),
+ self._values
+ )
+ )
+
+ # Keep data id unique for all subtree
+ self.get_new_db_id()
+#+end_src
+
+#+RESULTS:
+
+#+latex: \newpage
+
+* Prototype
+
+** Scenario
+
+#+name: scenario
+#+begin_src python :python python3 :results output :noweb yes
+ class Scenario():
+ def __init__(self, id, name, parent):
+ self._id = id
+ self._name = name
+ self._parent = parent
+
+ @classmethod
+ def create_db(cls, db):
+ execute(
+ db, """
+ CREATE TABLE scenario(
+ id INTEGER PRIMARY KEY,
+ name TEXT NOT NULL,
+ parent_id INTEGER REFERENCES scenario(id)
+ )
+ """
+ )
+
+ @classmethod
+ def load_db(cls, db):
+ cur = execute(
+ db, f"SELECT * FROM scenario"
+ )
+ table = cur.fetchall()
+
+ new = []
+ for values in table:
+ new.append(
+ cls(
+ values[0], values[1], values[2],
+ )
+ )
+
+ return new
+
+ def save(self, db):
+ sid = 'NULL' if self._parent is None else self._parent
+
+ execute(
+ db,
+ "INSERT INTO scenario (id, name, parent_id) " +
+ f"VALUES ({self._id}, '{self._name}', {sid})"
+ )
+
+ def __repr__(self):
+ return f"Scenario {{ {self._id}, {self._name}, parent {self._parent} }}"
+
+ def __str__(self):
+ return f"{self._name}({self._id})"
+#+end_src
+
+#+RESULTS: scenario
+
+** Data
+
+#+name: data-b
+#+begin_src python :python python3 :results output :noweb yes
+ class B():
+ def __init__(self, value, scenario):
+ self._value = value
+ self._scenario = scenario
+ self._dummy = False
+
+ @classmethod
+ def create_db(cls, db):
+ execute(db, """
+ CREATE TABLE b(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ dummy_data BOOLEAN,
+ x INTEGER,
+ a_id INTEGER NOT NULL,
+ scenario_id INTEGER NOT NULL,
+ FOREIGN KEY(a_id) REFERENCES a(id),
+ FOREIGN KEY(scenario_id) REFERENCES scenario(id)
+ )
+ """)
+
+ def save(self, db, a_id):
+ execute(
+ db,
+ "INSERT INTO b (x, dummy_data, a_id, scenario_id) " +
+ f"VALUES ({self._value}, {self._dummy}, {a_id}, {self._scenario})"
+ )
+
+ @classmethod
+ def load_db(cls, db, a_id, senar):
+ if senar is None:
+ return []
+
+ cur = execute(
+ db,
+ "SELECT x, scenario_id, dummy_data FROM b " +
+ f"WHERE scenario_id = {senar} AND a_id = {a_id}"
+ )
+ table = cur.fetchall()
+
+ if len(table) == 0:
+ parent = execute(
+ db,
+ f"SELECT parent_id FROM scenario WHERE id = {senar}"
+ ).fetchone()
+
+ return cls.load_db(db, parent[0])
+
+ new = []
+ for values in table:
+ if values[2]: # Is dummy
+ continue
+
+ new.append(cls(values[0], values[1]))
+
+ return new
+
+ def set_value(self, value, scenario):
+ self._value = value
+ self._scenario = scenario
+
+ def set_dummy(self, scenario):
+ self._scenario = scenario
+ self._dummy = True
+
+ def __repr__(self):
+ if self._dummy:
+ return ""
+ return f"{self._value}"
+
+ def __str__(self):
+ if self._dummy:
+ return ""
+ return f"{self._value}"
+#+end_src
+
+#+RESULTS: data-b
+
+#+name: data-a
+#+begin_src python :python python3 :results output :noweb yes
+ class A():
+ def __init__(self, id, values, scenario):
+ self._id = id
+ self._values = values
+ self._scenario = scenario
+ self._dummy = False
+
+ @classmethod
+ def create_db(cls, db):
+ execute(db, """
+ CREATE TABLE a(
+ id INTEGER PRIMARY KEY,
+ dummy_data BOOLEAN,
+ scenario_id INTEGER,
+ FOREIGN KEY(scenario_id) REFERENCES scenario(id)
+ )
+ """)
+
+ def save(self, db):
+ self.reduce_change()
+
+ execute(db, f"DELETE FROM a WHERE scenario_id = {self._scenario}")
+ execute(
+ db,
+ "INSERT INTO a (id, dummy_data, scenario_id) " +
+ f"VALUES ({self._id}, {self._dummy}, {self._scenario})"
+ )
+
+ execute(
+ db,
+ "DELETE FROM b " +
+ f"WHERE scenario_id = {self._scenario} " +
+ f"AND a_id = {self._id}"
+ )
+
+ for value in self._values:
+ value.save(db, self._id)
+
+ def reduce_change(self):
+ diff_scenar = reduce(
+ lambda acc, x: max(acc, x._scenario),
+ self._values,
+ self._scenario
+ )
+ print(f" ~> Reduce: {self._scenario} to {diff_scenar}")
+ self._scenario = diff_scenar
+
+ # Reduce new scenario value on each value
+ for value in self._values:
+ value._scenario = self._scenario
+
+ # Delete useless dummy data
+ self._values = list(
+ filter(
+ lambda v: not v._dummy,
+ self._values
+ )
+ )
+
+ # HACK: keep id unique
+ self._id = self._id * 100 + diff_scenar
+
+ @classmethod
+ def load_db(cls, db, senar):
+ if senar is None:
+ return []
+
+ cur = execute(
+ db,
+ f"SELECT id, scenario_id, dummy_data FROM a WHERE scenario_id = {senar}"
+ )
+ table = cur.fetchall()
+
+ if len(table) == 0:
+ parent = execute(
+ db,
+ f"SELECT parent_id FROM scenario WHERE id = {senar}"
+ ).fetchone()
+
+ return cls.load_db(db, parent[0])
+
+ new = []
+ for values in table:
+ if values[2]:
+ continue
+
+ bb = B.load_db(db, values[0], senar)
+ new.append(cls(values[0], bb, values[1]))
+
+ return new
+
+ def set_dummy(self, scenario):
+ self._scenario = scenario
+ self._dummy = True
+
+ def add(self, b):
+ self._values.append(b)
+
+ def delete(self, index, scenario):
+ self._values[index].set_dummy(scenario)
+ self._scenario = scenario
+
+ def __repr__(self):
+ if self._dummy:
+ return "{ }"
+ return f"{{ {self._values}, ({self._scenario}) }}"
+
+ def __str__(self):
+ if self._dummy:
+ return "{ }"
+ return f"{{ {list(map(str, self._values))}, ({self._scenario}) }}"
+#+end_src
+
+#+RESULTS: data-a
+
+** Full prototype
+
+#+begin_src python :python python3 :results output :exports both :noweb yes :cache yes
+ from functools import reduce
+
+ def execute(db, query):
+ # print(query)
+ return db.execute(query)
+
+ def get_tree(db):
+ from treelib import Node, Tree
+
+ tree = Tree()
+
+ for senar in db.execute("SELECT * FROM scenario").fetchall():
+ if senar[1] is None:
+ tree.create_node(
+ str(Scenario(senar[0], senar[1], senar[2])) +
+ " : " + str(A.load_db(db, senar[0])[0]),
+ senar[0]
+ )
+ else:
+ tree.create_node(
+ str(Scenario(senar[0], senar[1], senar[2])) +
+ " : " + str(A.load_db(db, senar[0])[0]),
+ senar[0],
+ parent=senar[2]
+ )
+
+ return tree
+
+ ### --- Scenario ---
+ <>
+
+ ### --- class B ---
+ <>
+
+ ### --- class A ---
+ <>
+
+ ### --- Script ---
+ import sqlite3
+ import pprint
+
+ pp = pprint.PrettyPrinter(width=79, compact=True, depth=6)
+
+ with sqlite3.connect(":memory:") as db:
+ cur = db.cursor()
+
+ Scenario.create_db(cur)
+ A.create_db(cur)
+ B.create_db(cur)
+
+ print("--- Default scenario (s0) ---")
+
+ # One scenario
+
+ s0 = Scenario(0, "s0", None)
+ a0 = A(
+ 1,
+ [
+ B(0, s0._id),
+ B(1, s0._id),
+ B(2, s0._id),
+ ],
+ s0._id
+ )
+
+ s0.save(cur)
+ a0.save(cur)
+
+ print("--- New scenario (s1) -- copy without modification ---")
+
+ # New scenario
+
+ s1 = Scenario(1, "s1", s0._id)
+ s1.save(cur)
+
+ print("--- New scenario (s2) -- data modification ---")
+
+ # New scenario 2 with data
+
+ s2 = Scenario(2, "s2", s0._id)
+ s2.save(cur)
+
+ a2 = a0
+ bb = list(map(
+ lambda b: b.set_value(b._value + 1, s2._id),
+ a2._values
+ ))
+
+ a2.save(cur)
+
+ print("--- New scenario (s3) -- delete data ---")
+
+ # New scenario 3 with data
+
+ s3 = Scenario(3, "s3", s0._id)
+ s3.save(cur)
+
+ a3 = A.load_db(cur, s3._id)[0]
+ a3._values[0].set_dummy(s3._id)
+ a3.save(cur)
+
+ print("--- New scenario (s4) -- new data ---")
+
+ s4 = Scenario(4, "s4", s3._id)
+ s4.save(cur)
+
+ a4 = A.load_db(cur, s3._id)[0]
+ a4.add(B(666, s4._id))
+ a4.save(cur)
+
+ print("--- Scenario tree ---")
+
+ tree = get_tree(db)
+ print(tree)
+
+ print("--- Modify s0 data ---")
+
+ aa = A.load_db(db, s0._id)[0]
+ bb = list(map(
+ lambda b: b.set_value(b._value * 100 - 1, s0._id),
+ aa._values
+ ))
+ aa.save(db)
+
+ print("--- Scenario tree ---")
+
+ tree = get_tree(db)
+ print(tree)
+
+ print("--- DB ---")
+
+ ss = db.execute("SELECT * FROM scenario").fetchall()
+ print(f"+ scenario ({len(ss)}):")
+ pp.pprint(ss)
+
+ aa = db.execute("SELECT * FROM a").fetchall()
+ print(f"+ a ({len(aa)}):")
+ pp.pprint(aa)
+
+ bb = db.execute("SELECT * FROM b").fetchall()
+ print(f"+ b ({len(bb)}):")
+ pp.pprint(bb)
+
+#+end_src
+
+#+RESULTS[96c84f23be557425ae2822ef7f174175ef69f9b9]:
+#+begin_example
+--- Default scenario (s0) ---
+ ~> Reduce: 0 to 0
+--- New scenario (s1) -- copy without modification ---
+--- New scenario (s2) -- data modification ---
+ ~> Reduce: 0 to 2
+--- New scenario (s3) -- delete data ---
+ ~> Reduce: 0 to 3
+--- New scenario (s4) -- new data ---
+ ~> Reduce: 3 to 4
+--- Scenario tree ---
+s0(0) : { ['0', '1', '2'], (0) }
+├── s1(1) : { ['0', '1', '2'], (0) }
+├── s2(2) : { ['1', '2', '3'], (2) }
+└── s3(3) : { ['1', '2'], (3) }
+ └── s4(4) : { ['1', '2', '666'], (4) }
+
+--- Modify s0 data ---
+ ~> Reduce: 0 to 0
+--- Scenario tree ---
+s0(0) : { ['-1', '99', '199'], (0) }
+├── s1(1) : { ['-1', '99', '199'], (0) }
+├── s2(2) : { ['1', '2', '3'], (2) }
+└── s3(3) : { ['1', '2'], (3) }
+ └── s4(4) : { ['1', '2', '666'], (4) }
+
+--- DB ---
++ scenario (5):
+[(0, 's0', None), (1, 's1', 0), (2, 's2', 0), (3, 's3', 0), (4, 's4', 3)]
++ a (4):
+[(10000, 0, 0), (10002, 0, 2), (10003, 0, 3), (1000304, 0, 4)]
++ b (14):
+[(1, 0, 0, 100, 0), (2, 0, 1, 100, 0), (3, 0, 2, 100, 0), (4, 0, 1, 10002, 2),
+ (5, 0, 2, 10002, 2), (6, 0, 3, 10002, 2), (7, 0, 1, 10003, 3),
+ (8, 0, 2, 10003, 3), (9, 0, 1, 1000304, 4), (10, 0, 2, 1000304, 4),
+ (11, 0, 666, 1000304, 4), (12, 0, -1, 10000, 0), (13, 0, 99, 10000, 0),
+ (14, 0, 199, 10000, 0)]
+#+end_example
diff --git a/doc/dev/scenarios/presentation.org b/doc/dev/scenarios/presentation.org
new file mode 100644
index 00000000..5ecaf7b1
--- /dev/null
+++ b/doc/dev/scenarios/presentation.org
@@ -0,0 +1,525 @@
+# presentation.org -- Pamhyr
+# Copyright (C) 2023 INRAE
+#
+# 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. If not, see .
+
+# -*- coding: utf-8 -*-
+
+#+STARTUP: indent hideblocks content beamer
+
+#+TITLE: \textbf{Pamhyr2}
+#+SUBTITLE: Scenarios managements
+
+# #+AUTHOR: Pierre-Antoine Rouby
+#+LATEX_HEADER: \author[Pierre-Antoine Rouby]{\textbf{Pierre-Antoine Rouby}}
+#+EMAIL: pierre-antoine.rouby@inrae.fr
+#+INSTITUTE: INRAE Lyon-Villerbanne, teams River Hydraulics
+#+LATEX_HEADER: \institute{INRAE Lyon-Villerbanne, River Hydraulics team}
+#+DATE: 9th November
+
+#+KEYWORDS: g ui, hydraulics, sedimentary, hydro-sedimentary, 1D modelling, freesoftware, foss
+
+#+OPTIONS: H:2 toc:t num:t author:nil
+#+LATEX_CLASS: beamer
+#+LATEX_CLASS_OPTIONS: [slideopt,A4,showboxes,svgnames,aspectratio=169]
+# #+LATEX_CLASS_OPTIONS: [presentation]
+#+BEAMER_THEME: default
+#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col)
+
+#+LANGUAGE: fr
+#+LATEX_HEADER: \usepackage[frenchb]{babel}
+
+#+BEGIN_SRC emacs-lisp :results silent :exports none
+ (setq org-latex-pdf-process (list
+ "latexmk -pdflatex='lualatex -shell-escape -interaction nonstopmode' -pdf -f %f"))
+
+ (add-to-list 'org-latex-packages-alist '("" "minted"))
+ (setq org-latex-listings 'minted)
+ (setq org-src-fontify-natively t)
+
+ (org-add-link-type
+ "cite" 'ebib
+ (lambda (path desc format)
+ (cond
+ ((eq format 'html)
+ (format "(%s)" path))
+ ((eq format 'text)
+ (format "[%s]" path))
+ ((eq format 'latex)
+ (if (or (not desc) (equal 0 (search "cite:" desc)))
+ (format "\\cite{%s}" path)
+ (format "\\cite[%s][%s]{%s}"
+ (cadr (split-string desc ";"))
+ (car (split-string desc ";")) path))))))
+#+END_SRC
+
+# Wrapper
+#+NAME: attr_wrap
+#+HEADER: :var width="\\textwidth"
+#+HEADER: :var caption=""
+#+HEADER: :var smallcaption=""
+#+HEADER: :var name=""
+#+HEADER: :var data=""
+#+HEADER: :var float="nil"
+#+BEGIN_SRC sh :results output :exports none
+ echo "#+CAPTION[$smallcaption]: $caption"
+ echo "#+NAME: $name"
+ echo "#+ATTR_LATEX: :width $width :float $float"
+ echo "$data"
+#+END_SRC
+
+#+LATEX_HEADER: \setbeamertemplate{footline}[frame number]
+#+LATEX_HEADER: \setbeamertemplate{headline}{}
+#+LATEX_HEADER: \usepackage{multirow}
+#+LATEX_HEADER: \usepackage{fontawesome5}
+#+LATEX_HEADER: \usepackage{tcolorbox}
+#+LATEX_HEADER: \usepackage{tikz}
+
+#+LATEX_HEADER: \logo{\includegraphics[width=.1\textwidth]{../../../src/View/ui/ressources/Logo-INRAE.png}}
+
+#+LATEX_HEADER: \newcommand{\R}[1]{\rotatebox[origin=c]{90}{#1}}
+
+# Beamer colors
+#+LATEX_HEADER: \setbeamersize{text margin left=0.5cm,text margin right=0.5cm}
+#+LATEX_HEADER: \setbeamerfont{alerted text}{series=\bfseries}
+#+LATEX_HEADER: \setbeamerfont{example text}{series=\bfseries}
+
+#+LATEX_HEADER: \definecolor{inrae_1}{RGB}{102,193,191}
+#+LATEX_HEADER: \definecolor{inrae_2}{RGB}{0,150,152}
+#+LATEX_HEADER: \definecolor{inrae_3}{RGB}{39,86,98}
+
+#+LATEX_HEADER: \setbeamercolor{alerted text}{fg=inrae_1}
+#+LATEX_HEADER: \setbeamercolor{structure}{fg=inrae_2}
+#+LATEX_HEADER: \setbeamercolor{normal text}{fg=inrae_3}
+#+LATEX_HEADER: \setbeamercolor*{author}{fg=inrae_3}
+
+#+LATEX_HEADER: \usepackage[absolute,showboxes,overlay]{textpos}
+
+#+LATEX_HEADER: \TPshowboxesfalse
+#+LATEX_HEADER: \textblockorigin{5mm}{0mm}
+
+# Biblio
+#+LATEX_HEADER: \usepackage{natbib}
+# #+LATEX_HEADER: \bibliographystyle{apalike}
+#+LATEX_HEADER: \setbeamertemplate{bibliography item}{}
+#+LATEX_HEADER: \renewcommand\bibfont{\scriptsize}
+#+LATEX_HEADER: \setbeamertemplate{frametitle continuation}[from second]
+#+LATEX_HEADER: \setbeamercolor*{bibliography entry title}{fg=inrae_3}
+#+LATEX_HEADER: \setbeamercolor*{bibliography entry author}{fg=inrae_3}
+#+LATEX_HEADER: \setbeamercolor*{bibliography entry location}{fg=inrae_3}
+
+#+LATEX_HEADER: \usepackage{bbding}
+#+LATEX_HEADER: \usepackage{pdfpages}
+
+# Renew title page
+#+LATEX_HEADER: \defbeamertemplate*{title page}{customized}[1][]
+#+LATEX_HEADER: {
+# #+LATEX_HEADER: {
+# #+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}
+# #+LATEX_HEADER: \tikz[overlay,remember picture]
+# #+LATEX_HEADER: \node[xshift=-1cm,yshift=-1cm,text width=10cm] at (current page.north east) {
+# #+LATEX_HEADER: 7$^{th}$ International Conference\\
+# #+LATEX_HEADER: 8TH-10TH November\\
+# #+LATEX_HEADER: EDF Lab - CHATOU, FRANCE
+# #+LATEX_HEADER: }
+# #+LATEX_HEADER: }
+#+LATEX_HEADER: {
+#+LATEX_HEADER: \usebeamerfont{title}\inserttitle\par
+#+LATEX_HEADER: \usebeamerfont{title}\usebeamercolor[fg]{title}
+#+LATEX_HEADER: }
+#+LATEX_HEADER: \bigskip
+#+LATEX_HEADER: \begin{center}
+#+LATEX_HEADER: \usebeamerfont{subtitle}\usebeamercolor[fg]{subtitle}
+#+LATEX_HEADER: {
+#+LATEX_HEADER: \LARGE\insertsubtitle\par
+#+LATEX_HEADER: }
+#+LATEX_HEADER: \bigskip
+#+LATEX_HEADER: \usebeamerfont{author}\usebeamercolor[fg]{author}\insertauthor\par
+#+LATEX_HEADER: \bigskip
+#+LATEX_HEADER: \usebeamerfont{institute}\usebeamercolor[fg]{institute}\insertinstitute\par
+#+LATEX_HEADER: \bigskip
+#+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}\insertdate\par
+#+LATEX_HEADER: \usebeamercolor[fg]{titlegraphic}\inserttitlegraphic
+#+LATEX_HEADER: \end{center}
+#+LATEX_HEADER: }
+
+# #+LATEX_HEADER: \newcommand{\tred}[1]{\textcolor{rouge_inrae}{#1}}
+
+#+TODO: TODO WIP TOREVIEW | DONE
+
+#+MACRO: pamhyr \textsc{PAMHyR}
+#+MACRO: pamhyr2 \textsc{Pamhyr2}
+
+#+MACRO: pause \pause
+#+MACRO: framebreak \framebreak
+#+MACRO: no
+# #+MACRO: OK \checkmark
+#+MACRO: OK \faIcon{check}
+#+MACRO: bf \textbf{$1}
+
+# #+latex: \frame{\tocpage}
+
+* Problématique
+
+** Problématique
+
+*** Utilisateur
+
+- Définire une version modifier de l'étude (changement dans les
+ données)
+- Comparé des résultats entre une variante et l'étude
+
+{{{pause}}}
+
+**** COMMENT Développeur
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+- Un unique fichier
+- Limité la duplication de donnée à sauvegarder
+- Garder une bonne cohérence entre données et résultats
+
+{{{pause}}}
+
+*** Scénarios
+:PROPERTIES:
+:BEAMER_COL: 1
+:BEAMER_ENV: definition
+:END:
+
+Un scénario est une variate d'une étude.
+
+** Problématique -- Avancer
+
+*** Utilisateur
+
+- Définire une version modifier d'un senarios
+- Comparé des résultats entre plusieurs senarios
+
+{{{pause}}}
+
+**** COMMENT Développeur
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+- Un unique fichier
+- Limité la duplication de donnée à sauvegarder
+- Garder une bonne cohérence entre données et résultats
+
+{{{pause}}}
+
+*** Scénarios
+:PROPERTIES:
+:BEAMER_COL: 1
+:BEAMER_ENV: definition
+:END:
+
+Un scénario peut être l'étude ou une variate d'un autre scénario.
+
+** Problématique -- Encore plus avancer
+
+*** Utilisateur
+
+- Définire un ensemble fini de variante correspondant a un ensemble de
+ valeur pour un(des) paramètre(s) et executer un solveur sur
+ l'ensemble des variantes
+- Pouvoir comparé des metrics sur un ensemble de résultats trop grand
+ pour une comparaisont à la mains
+
+{{{pause}}}
+
+**** COMMENT Développeur
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+- Un unique fichier
+- Limité la duplication de donnée à sauvegarder
+- Garder une bonne cohérence entre données et résultats
+
+{{{pause}}}
+
+*** Scénarios
+:PROPERTIES:
+:BEAMER_COL: 1
+:BEAMER_ENV: definition
+:END:
+
+Un scénario peut être l'étude, une variate d'un scénarios ou un
+ensemble fini de variantes d'un scénarios.
+
+** Problématique -- Encore plus plus avancer
+
+*** Utilisateur
+
+- Définire un ensemble fini de variante correspondant a un ensemble de
+ valeur pour un(des) paramètre(s) et faire un nombre fini de tirage
+ aléatoire dans ces paramètre pour executer un solveur ces paramètres
+- Pouvoir comparé des metrics sur un ensemble de résultats trop grand
+ pour une comparaisont à la mains
+
+{{{pause}}}
+
+*** Scénarios
+:PROPERTIES:
+:BEAMER_COL: 1
+:BEAMER_ENV: definition
+:END:
+
+Un scénario peut être l'étude, une variate d'un scénarios ou un
+ensemble fini ou un tirage aléatoire dans un ensemble de variantes
+d'un scénarios.
+
+** Problématique -- Développeur
+
+*** Développeur
+
+- Permetre a l'utilisateur de *garder une bonne cohérence entre
+ données et résultats* de façon claire
+- Permetre a l'utilisateur de *géré les scénarios* de façon claire
+ (représentation graphique)
+- Garder *un unique fichier* (=.pamhyr=)
+- *Limité la duplication* de donnée à sauvegarder
+- Permetre à l'utilisateur de garder les *résultats pertinant* sans
+ exploser la mémoire de l'ordinateur
+
+* Proposition
+
+** Proposition -- Concept
+
+*** {{{no}}}
+\vspace{-1.2cm}
+**** Deux type de scénarios
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+- Scénarios simple
+- Scénarios d'éxecution d'ensemble
+
+{{{pause}}}
+
+**** Scénarios simple
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+Est composer:
+- d'un identifiant unique
+- d'un nom (définie par l'utilisateur)
+- d'une description (définie par l'utilisateur)
+- d'un parent (définie par l'utilisateur)
+
+{{{pause}}}
+
+\vspace{-0.5cm}
+
+*** Scénarios d'ensembles
+
+**** {{{no}}}
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+\vspace{-1cm}
+Est composer:
+- d'un identifiant unique
+- d'un nom (définie par l'utilisateur)
+- d'une description (définie par l'utilisateur)
+- d'un parent (définie par l'utilisateur)
+- d'un ou plusieurs ensemble de valeur
+
+**** {{{no}}}
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+\vspace{-0.5cm}
+Un ensemble de valeurs est definie par:
+- une valeurs de départ
+- une valeurs de fin
+- un pas de valeur
+- un élément d'origine (élément définie dans l'étude)
+- une fonctions (modification de l'élément à l'aide d'une valeur de
+ l'ensemble)
+
+** Proposition -- Limitation
+
+*** Scénarios simple
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+Si le scénarios est le *parent d'un autre scénarios*, il ne *peut plus
+être modifier* sans risquer des comportement difficilement
+comprehensible pour l'utilisateur.
+
+{{{pause}}}
+
+*** Scénarios d'ensembles
+:PROPERTIES:
+:BEAMER_COL: 0.5
+:BEAMER_ENV: block
+:END:
+
+- Un scénarios d'ensemble *ne peut pas être parent* d'un autre
+ scénarios
+- Le nombre d'exécution peut très rapidement grossir
+
+** Proposition -- Affichage
+
+#+name: graph-scenarios
+#+header: :results drawer
+#+header: :exports results
+#+header: :post attr_wrap(width="7cm", data=*this*, name="graph-scenarios", caption="Exemple of scenarios graph", float="t")
+#+begin_src dot :file "images/graph-scenarios.png" :cache no
+ digraph {
+ bgcolor="transparent";
+ node[colorscheme=pastel19,shape=ellipse,style="filled",fillcolor=9];
+
+ b[fillcolor=2];
+
+ aa[shape=box,fillcolor=2];
+ aa2[label="aa'", shape=box, fillcolor=2];
+ ad[shape=box, fillcolor=2];
+ re[shape=box, fillcolor=2];
+ rf[shape=box, fillcolor=2];
+
+ default -> a;
+ default -> b;
+ default -> c;
+
+ a -> aa;
+ a -> aa2;
+ a -> f -> rf;
+ c -> d -> ad;
+ c -> e -> re;
+ }
+#+end_src
+
+#+RESULTS[80ed2484b9cc71143f800ff23c10846fd04697c3]: graph-scenarios
+:results:
+#+CAPTION[]: Exemple of scenarios graph
+#+NAME: graph-scenarios
+#+ATTR_LATEX: :width 7cm :float t
+[[file:images/graph-scenarios.png]]
+:end:
+
+* Solution technique
+
+** Technique -- scénarios
+
+#+begin_src sql
+ CREATE TABLE scenario(
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL, -- Name of the scenario
+ description TEXT NOT NULL, -- Rich text description
+ parent_id INTEGER REFERENCES scenario(id) -- Recursive references
+ -- for parent scenario
+ )
+#+end_src
+
+** Technique -- Données -- Enregistrement
+
+#+begin_src sql
+ -- Unique ID (Must be unused, to delete)
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ -- New ID (not unique)
+ pamhyr_id INTEGER NOT NULL,
+ -- (Optional) Flag for set there is no data in this scenario and
+ -- ignore parent scenario
+ dummy BOOLEAN NOT NULL,
+ -- Corresponding scenario
+ scenario_id INTEGER NOT NULL,
+ PRIMARY KEY(pamhyr_id, scenario_id),
+ FOREIGN KEY(scenario_id) REFERENCES scenario(id),
+#+end_src
+
+** Technique -- Données -- Chargement
+
+#+begin_src python :python python3 :results output :noweb yes
+ def load(cls, db, current_scenario):
+ # Default case, end of recursion
+ if current_scenario is None:
+ return [] # Default value
+
+ table = db.execute(f" WHERE scenario_id = {current_scenario}")
+
+ # If no data for this scenario, recursion
+ if len(table) == 0:
+ parent_id = db.get_parent_id(current_scenario)
+ return cls.load(db, parent_id)
+
+ # Otherelse, parse data and return...
+#+end_src
+
+** Technique -- Données -- Modification
+
+#+begin_src python :python python3 :results output :noweb yes
+ def set_modified(self, current_scenario):
+ self.scenario = current_scenario
+#+end_src
+
+#+begin_src python :python python3 :results output :noweb yes
+ def delete(self, current_scenario):
+ self.deleted = True
+ self.set_modified(current_scenario)
+#+end_src
+
+** Technique -- Exécution d'ensemble
+
+#+begin_src sql
+ CREATE TABLE range_set(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ start REAL NOT NULL, -- Range start
+ end REAL NOT NULL, -- Range end
+ step REAL NOT NULL, -- Range step
+ generator_name TEXT NOT NULL, -- Generator function name (ex:
+ -- 'minor_strickler')
+ original_data_id INTEGER, -- (optional) Ref to data who apply
+ -- this range (ex: a strickler id)
+ scenario_id INTEGER NOT NULL,
+ FOREIGN KEY(scenario_id) REFERENCES scenario(id)
+ )
+#+end_src
+
+* Sauvegarde des résultats
+
+** Sauvegarde des résultats
+
+*** Scénarios simple
+
+Sauvegarde d'un seul résultats complet par scénarios (et par solver).
+
+*** Scénarios d'ensemble
+
+Sauvegarde de metrics récupéré sur un ensemble de résultats (pas de
+sauvegarde de tous les résultats) ou certain résultats particuliers.
+
+* Question & remarque
+
+** Question & remarque
+
+- Solution satisfaisante ?
+- Cas d'usage intéressent non couvert ?
+- Contre exemple ?
+- Meilleur solution ?