Erwan Jahier

RDBG: a Reactive Programs Extensible Debugger

Keywords: Programmable Debuggers, Dynamic Analysis, Monitor, Reactive systems, Synchronous languages, Interpreter, Compiler, Code Instrumentation, Continuations

Debugging reactive programs requires to provide a lot of inputsat each reaction step. Moreover, because a reactive system reacts to an environment it tries to control, providing realistic inputs can be hard. The same considerations apply for automatic testing. This work take advantage on previous work on automated testing of reactive programs that close this feedback loop.

This article demonstrates how to implement opportunistically such a debugging commands interpreter by taking advantage of an existing (ocaml) toplevel Read-Eval-Print Loop (REPL). Then it shows how a small kernel is enough to build a full-featured debugger with little effort. The given examples provide a tutorial for end-users that wish to write their own debugging primitives, fitting to their needs, or to tune existing ones.

An orthogonal contribution of this article is to present an efficient way to implement the debugger coroutining using continuations.

The Reactive programs DeBuGger (RDBG) prototype aims at being versatile and general enough to be able to deal with any reactive languages. We have experimented it on 2 synchronous programming: Lustre and Lutin.

INTRODUCTION

Reactive systems and synchronous languages. A reactive system is an assembly of hardware and software that continuously interacts with its environment, typically via sensors and actuators. Because reactive systems are often critical, dedicated languages that offer strong guaranties on the software behavior were designed. Synchronous languages [START_REF] Amagbégnon | Implementation of the data-flow synchronous language Signal[END_REF][START_REF] Berry | The Esterel synchronous programming language: Design, semantics, implementation[END_REF][START_REF] Halbwachs | The synchronous dataflow programming language Lustre[END_REF], for instance, ensure that the generated code uses a bounded amount of memory and execution time. A lot of efforts has also been put on formal verification and automated testing, but almost no work on debugging. Of course, for programs which by construction, contain no loop, no memory leak, and no To appear in 19th International Workshop on Software and Compilers for Embedded Systems (SCOPES '16), May 23th to 25th, 2016, Sankt Goar, Germany segmentation fault, a debugger seems less necessary. Nonetheless, the remaining errors, revealed by testing or formal verification, can still be difficult to spot. Debugging reactive programs : closing the feedback loop. One difficulty when debugging reactive programs is that they often require a lot of inputs -at each activation step. Moreover, those inputs are not always easy to provide, as they can depend on past values of the program inputs and outputs. Actually, we face exactly the same problem when performing automated testing: to provide realistic input sequences, we need to take into account the following feedback loop: the program influences its environment, which it turn influences (reacts to) the program. The testing tool of reactive programs LURETTE tackles this problem by providing a language dedicated to the modeling/simulation of program environments [START_REF] Jahier | Environment-model based testing of control systems: Case studies[END_REF]. This language, named Lutin [START_REF] Raymond | Lutin: a language for specifying and executing reactive scenarios[END_REF], is an extension of Lustre [START_REF] Halbwachs | The synchronous dataflow programming language Lustre[END_REF] designed to model non-deterministic reactive systems. To test automatically a program, this idea is therefore to write in Lutin the program environment model, and then to execute the program under test inside this simulated environment.

Since we have the same problem for debugging than for testing, the idea is to re-use the LURETTE infrastructure to close feedback loop. This is all the more natural to use the same framework that it is precisely the objective of a testing tool to detect bugs that a debugger would then help to track. In order words, to debug a reactive program, one can reuse the simulated environment used for the tests, which revealed the error that require the use of a debugger. Note that in this framework, the environment model is also a reactive program (written in Lutin), which therefore can also contain bugs, and also necessitates a debugger. Our debugger is actually able to debug Lutin programs too.

RDBG, an extensible debugger for reactive programs. In this article, we present RDBG, a debugger for reactive programs that re-use the LURETTE plumbing and its ability to plug various kinds of reactive programs together in closed loop. RDBG has a plugin mechanism to connect to reactive program runtime systems. Two language plugins are currently implemented: one for Lustre V6, and one for Lutin. RDBG is extensible in a second manner: it provides a language which allows programmers to write their own debugging and monitoring commands. This language is based on a kernel made of 2 primitives that allow one to inspect the debuggee entrails, and to navigate through its runtime events list (observation points). The sequence of events comes from a pre-defined instrumentation of the target language runtime system that is provided via the language plugin. The RDBG command interpreter. A debugger is a program that runs in coroutine with a program to be debugged, and that observes and controls its execution. It interacts with the debuggee by interpreting in loop commands, possibly coming from a Graphical User Interface. For a debugger to be extensible, we need this commands interpreter to be able to interpret programs. An opportunistic way of obtaining such a commands and programs interpreter is to rely on an existing host language equipped with a good set of libraries, and an interactive Read-Eval-Print Loop (REPL); in this work, we use OCAML as the host language, which has both a REPL and a rich set of libraries. One drawback to rely on OCAML is of course that it requires to know OCAML to program debugging extensions. However, if one just wants to use RDBG, or maybe just wants to tune existing commands, knowing OCAML is not necessary. Likewise, the examples in this article are given in OCAML, but no deep knowledge of ml should be needed to understand them. A continuation-based kernel. Finally, we propose an original and efficient way of implementing coroutine using continuations. Indeed, continuations allow to execute arbitrarily complex user code in debuggee process, which avoid costly context switches and communications between the 2 processes. Debuggers and academic languages. Debuggers are fastidious to implement. From an academic perspective, working on debuggers is time-consuming and difficult to bring out. Nevertheless, debuggers are useful. This is the reason why:

• we have chosen to rely on existing REPL and libraries;

• we have paid a particular attention to re-usability by defining a language agnostic interface and by providing to compiler developers a simple plugin API;

• we have focused on separation of concerns by providing debugger users an API that allows them to implement their own debugging and monitoring programs with no need to look under the hood of the runtime system.

Another claim we try to argue in this article is that, once you have a carefully crafted programmable kernel, extending it with new debugging commands is easy and entertaining. Plan. While RDBG aims at being versatile enough to debug any kind of reactive programs, it currently works with 2 synchronous languages. We therefore first briefly review them in Section 2albeit a deep understanding of synchronous languages is not necessary to grasp the debugging commands we show. Section 3 presents the RDBG user interface, and demonstrate how to build a full-featured debugger on top of a small kernel. Section 4 presents the RDBG plugin mechanism, that is the API for language developers that would wish to use it. Section 5 describes the design choices and the prototype implementation. Section 6 briefly discusses the 2 current language plugins. Section 7 presents related work.

SYNCHRONOUS LANGUAGES

RDBG is (currently) plugged onto 2 synchronous languages, Lustre and Lutin [START_REF] Jahier | The Lutin Reference Manual[END_REF]. The examples we give in the forthcoming sections refer to Lutin, and even though a deep understanding of it is not necessary, we recap its main characteristics now. We first recap the Lustre main characteristics, as Lutin is based on Lustre concepts. Lustre. A reactive system interacts continuously with its environment, at a speed imposed by the environment. Typically, it first acquires inputs via sensors, performs a computation step, and then sets its outputs through actuators. This cyclic behavior can be periodic (time-triggered) or sporadic (event-triggered).

Because reactive systems are often critical, dedicated languages that offer strong guaranties on the software behavior were designed. Synchronous languages [START_REF] Amagbégnon | Implementation of the data-flow synchronous language Signal[END_REF][START_REF] Berry | The Esterel synchronous programming language: Design, semantics, implementation[END_REF][START_REF] Halbwachs | The synchronous dataflow programming language Lustre[END_REF] such as Lustre were successful in this respect as they make reasoning about time easier, thanks to the notions of logical time and deterministic concurrency. Synchronous languages generate code with known bounds on their memory usage and execution time.

The Lustre compiler (as well as Scade, its industrial version) generates a C step function, that is meant to be embedded in systems with no operating system. In Lustre, one defines reactive programs via sets of data-flow equations that are executed in parallel. Equations are structured into nodes. Nodes transform input sequences (or streams) into output sequences.

Lutin. In order to be able to test Lustre programs (or programs written in other reactive languages) automatically, we need to simulate the System Under Test (SUT) environment. To generate realistic input sequences, such simulated environment needs to take into account the SUT outputs. This simulated environment is therefore itself a reactive program which environment is the SUT. The Lutin language [START_REF] Raymond | Lutin: a language for specifying and executing reactive scenarios[END_REF] was designed to program stochastic reactive programs, that can model reactive system environments [START_REF] Jahier | Environment-model based testing of control systems: Case studies[END_REF][START_REF] Jahier | Engineering functional requirements of reactive systems using synchronous languages[END_REF].

Lutin is a probabilistic extension of Lustre with an explicit control structure based on regular operators: sequence (fby, for "followed by"), Kleene star (loop), and choice (|). At each step, the Lutin interpreter (1) computes the set of reachable constraints, which depends on the current control state; (2) removes from it unsatisfiable constraints, which depends on the current data-state (input and memories); (3) draws a constraint among the satisfiable ones (control-level non-determinism); (4) draws a point in the solution set of the constraint (data-level non-determinism). This chosen point defines the output for the current reaction. The solver of the current Lutin interpreter uses Binary Decision Diagrams (BDD) and convex polyhedron libraries. It is thus able to deal with any combination of logical operators and linear constraints. Unlike Lustre, Lutin programs are not meant to be embedded, and only an interpreter is available.

A debugger-based Lutin tutorial

One benefit of a debugger is to allow programming language learners to discover its operational semantics. Maybe because language programming environments don't always come with a debugger, language introductory tutorials are seldom based on them. Here, we propose to describe the semantics of Lutin on a trace produced the Lutin debugger we present later. The objective is actually less to present the semantics of Lutin (which is not the topic of the article) than to motivate the use of debuggers and to introduce some of our debugger concepts step by step. We propose now to base the explanation of the operational behavior of those two nodes by describing this trace representing 5 RDBG steps, i.e., 5 reaction steps of the program plus 5 reaction steps of the environment. This trace is made of 6 columns. The first two columns contain the event and the step numbers. The third column contains the event kind: call events are generated when a node is called, and exit events when a node is exited; a try event is generated when the Lutin solver tries to solve a constraint. If the constraint is satisfiable (resp. unsatisfiable), a sat event (resp. usat) is emitted. top events are generated at the end of a global step. The fourth column contains the node name. The fifth column contains the node variables instantiation. The last column contains the source code corresponding to the event. Each row in this trace corresponds to a particular observation point in the execution. The first event indicates that the env node is called first (which was specified to RDBG at some point). Events 2 to 4 inform that the constraint "T=4", is tried; obviously, this constraint is satisfiable and bounds the variable T to 4. Then comes the turn of sut; events 4 to 8 inform that the elected constraint it "true", which is actually is the only one in this node. The Lutin semantics says that when there is no constraint, the output are generated at (pseudo-)random. Here the value f (false) is chosen.

1 1 call env [ ] 2 1 try env [ ] " T = 4 " 3 1 sat env [ ] " T = 4 " 4 1 exit env [ T =4 ] " T = 4 " 5 1 call sut [ T =4 ] 6 1 try sut [ T =4 ] " true " 7 1 sat sut [ T =4 ] " true " 8 1 exit sut [ T =4 , b = f ] " true " 9 1 top - [ T =4 , b = f ] 10 2 call env [ b = f ]
At event 10 starts the second step. This time the elected constraint in env is "b and T=pre T" (the pre operator gives access to the value of a variable at the previous step). The Lutin semantics states that when a constraint is elected, inputs and memories are replaced by their values (constant propagation). Hence, this expression is evaluated to "false and T=4", which is equivalent to "false", which is unsatisfiable. This appears in the usat event 12. Since this branch of the alternative failed to produce a solution, the other branch is tried (event 13); "not b and between(T,5,10)" evaluates to "true and between(T,5,10)", and then after expansion of the between macro to "5<T and T<10". This constraint has 4 solutions, and event 15 shows that the random generator has chosen the value 6. For the sut node, it has chosen t (true) at event 19.

For the third step, the only satisfiable alternative for env is the first one ("b and T=pre T"). By chance it is the one that is tried first (at event 22); after input and memory values propagation, it evaluates to "T=6", which has a unique solution. At step 4, there is no alternative, and the elected constraint is "T = 1 + pre T", which also has a unique solution (T=7) (cf event 33). The trace events for step 5 are similar to the ones of step 2, except that the only satisfiable constraint is chosen in the first place this time. This execution is represented graphically in Figure 3 by chronograms representing the values taken by T and b at each step during the execution.

A REACTIVE PROGRAMS DEBUGGER

RDBG targets reactive languages. New languages can be added via a plugin mechanism described in Section 4. RDBG REPL relies on the OCAML one. RDBG is based on a small kernel, that can be extended by standard OCAML programs. In this section, we present this kernel (3.1), and how it can be adapted to various target languages (3.2). Then we demonstrate how it can be extended (3.3).

In order to ease the work of eventual plugins contributors, and to encourage programmers to contribute to the RDBG libraries of debugging commands, the code has been licensed under GPL. Everything related to this free software project can be found at http://rdbg.forge.imag.fr/.

The RDBG User Interface

The RDBG User Interface is made of one data type (Event.t) and one function run, that starts the debugging session and returns the first event:

val run : params -> Event . t
where params holds the set of the debug session parameters (file names, number of steps to perform, interpreter options, etc.), and where Event.t is a structure defined as follows (in ml syntax): The field name holds the name of the node instance associated to the current event; lang holds its programming language name, and depth its depth in the call tree; nb and step respectively hold a counter that is incremented at each event, and at each step; inputs and outputs hold the node interface variable names and types; data holds the node variable values (interface and local variables). Data.v is a data type provided by RDBG that holds debuggee variable values (Boolean, integer, real, structure, array, enum); next holds a frozen function that, when called with the unit value, returns the next event; terminate holds a function that allows to terminate the execution cleanly; kind and sinfo hold the src_info and the kind data types, that are defined below. The src_info data type holds source-level information. Its expr field holds an expression that represents the current control point; it explains how the outputs are computed from the inputs at the current step. The Expr.t data type is standard expression type that is supposed to be versatile enough to be able to represent all supported languages constructions. The atoms field holds a finer-grained representation of this expression; this information is split into a list of atoms, because the parallelism is a constitutive characteristic of synchronous languages, and thus the current control-point is often distributed in all over the source code. The src_info_atom is a structure made of a file name (file), the beginning/ending character and line numbers of the atom in the source code (char and line fields). The stack field holds the call stack.

type kind = Top | Call | Exit | MicroStep of string
The kind data type is used to classify the various kinds of events. Top events are generated at the top-level of the cyclic process, and before a new round of reactive program steps is started (it is therefore where the step counter is incremented). Call events are generated when a node is called, and Exit events when it is exited.

MicroStep events are generated during the execution of the node.

The various kinds of MicroStep depend on the node language. We give examples of possible MicroStep kind sets for the Lutin language below (3.2).

This interface aims at being general and versatile enough to represent runtime information of any reactive languages. At least it is able to represent the information of Lustre and Lutin. Now we present a few Lutin specificities.

The Lutin Micro-steps

The MicroStep variant of the event kind data type of Section 3.1 is meant to hold language specific event kinds. Choosing a good set of event kinds is a delicate task: it defines the granularity of the instrumentation, and is the result of a trade-off between precision and efficiency. Too many events would slow-down the execution, but missing events could prevent to understand what's going on with a buggy program. Discussing the current instrumentation granularity we made for Lutin is out of the scope of this article, which aims at presenting the debugger language. However, we have chosen to briefly present it because we use them in some examples we give in Section 3.3. Moreover, it illustrates the RDBG API versatility.

In order to report faithfully what happens during a Lutin program execution, stopping at call or exit time is not enough. We need a finer-grained observation of the execution, that indicates which expressions contribute to the computation of the outputs of the current step. Lutin expressions are made of constraints that may or may not be satisfiable, depending on the inputs, and on the past (memory values). Hence we have defined, specifically for the Lutin plugin, 3 new kinds of events: try events, when a constraint is elected; sat events, when the selected constraint is satisfiable and (hence) is used to compute the outputs; usat events, when the selected constraint is not satisfiable.

What can be done with this small kernel

We now demonstrate by examples how such a minimalist kernel can be used to implement classic and advanced debugging features. Some of them might not be the more efficient solution, but the longest is about 20 lines long. Indeed, the emphasis here is put on readability and conciseness, rather that on efficiency. For example, each time we use linear-time lists, logarithmic-time association tables (a.k.a. maps) would have been more efficient but less readable.

All programs described below are part of the standard RDBG library module RdbgStdLib, available in the RDBG git repository.

Forward Moves

Moving to the next event (next) just requires to unfreeze the next field function of the current event. Moving several events forward (nexti) can be done using a counter (i) that is decremented until it becomes equal to 0: Similarly, we can implement commands that go to a specific event number (goto_i), or step number (goto_si): let rec ( goto_i : e -> int -> e ) = fun e i -> if e . nb < i then goto_i ( next e ) i else e let rec ( goto_si : e -> int -> e ) = fun e i -> if e . step < i then goto_si ( next e ) i else e

Note that here and in the following, we present purely functional commands. Equivalent commands using side-effects are easy to define (and sometimes easier to use) like this: e is now a reference to an event. ni only takes as argument the number of forward steps to perform, and modifies the event reference through a side-effect.

Conditional Breakpoints

The next_cond command below takes as argument a predicate (cond) over events which states when to stop moving forward. The criterion to decide when to stop going forward can of course be arbitrarily complex. The only limitation on what can be done comes from the information contained in the event itself. For example, suppose you notice that your program violates some invariant (or test oracle); one can then move forward up to the first event where the invariant is violated to inspect the state of your program. More specifically, suppose that this invariant consists of an alarm that should be set to true when a numeric variable "T" overcomes a threshold. One could write the following interactive query at the RDBG prompt: The invariant, encoded into the stop_here predicate, is then provided to the next_cond command. vi and vb (which code is straightforward and part of RdbgStdLib) respectively extract from the data field of an event the value of an integer and a Boolean variable .

Forward Moves (cont)

As we have mentioned before, several events can have the same step number. When navigating into the trace history of cyclic nodes, it is sometimes interesting to go to the next step of the current node. To implement such a command, we can again take advantage of the next_cond command: We can define a stepi command using step in exactly the same manner we have defined nexti using next. By using this step command instead of next in the definition of goto_si (Section 3.3.1), we obtain a new behavior that some users might prefer over the initial one. It is the whole purpose of a programmable debugger to provide a tool that makes it is easy to fit one's specific needs or preferences.

Hooks

Hooks are another very useful mechanism to let users tune their environment. They can be implemented, for example using hash tables, as follows: Hook functions are stored into a table that maps a string identifier to functions over events. This string can be used to remove or update the associated function. Here, we initialize the hooks association table with a single hook that contains an event printer. The idea then is to modify the next function of Section 3.3.1 and apply hook functions at each event. The trace of Figure 2 in Section 2.1 has been produced calling in loop this next function.

Custom Traces

Depending of the debugging context, customizing the trace that is printed by the debugger is useful. For instance, not all events are of interest, and for events that are printed, different information might give more insights. Suppose for example that one wants to modify the trace of Figure 2 in two manners. Firstly, by focusing on events that occur in the env node (indeed the sut ones are boring). Secondly, by printing constraints expressions where input and memory values are propagated. To do that, one can get the expression (Expr.t) contained in the expr field of the sinfo field, as well as the variable values in the data field, and program an expression pretty-printer that instantiates bound variables. In addition to the expression printer, this event printer uses 4 straightforward functions that we don't show the code of either: to_lut_evt, that translates MicroStep event kinds into Lutin event (lut_evt) for type safety; sinfo2str, kind2str, and data2str, are used by the default event printer, translate sinfo, kind, and Data.v to strings. Once the new printer is defined, one just needs to update the print_event hook, as illustrated in the RDBG interactive session below:

( rdbg ) del_hook " print_event " ;; ( rdbg ) add_hook " print_event " my_pp_event ;; ( rdbg ) let e = stepi ( run ()) 4;;

The last line which calls the stepi command of Section 3.3.3 produces the following trace: This is trace of exactly the same execution as the one that generated the trace of Figure 2. To obtain the same execution, one needs to provide the same seed the Lutin pseudo-random generator. Such expression printers or evaluators are good examples of code that can be written once for all, leveraging the work of plugins writers.

gdb-like Breakpoints

Another classic feature of debuggers consists in moving forward in the event history by setting breakpoints. We show a possible implementation of breakpoints that uses a syntax reminiscent to the gdb one. Basically, one can set a breakpoint on a node (break "a_node_id") or on a particular line of a particular file (break "[[file::line][file::line]]"). We store each breakpoint in a table indexed by a global counter bc. This index can then be used to remove a specific breakpoint: Now, the only non-trivial part consists in digging into the event data structure for the file name and line number. This work is done by the brk_matches event predicate below, that returns true if and only if the event argument matches the breakpoint string. This time the code is a bit laborious. Nevertheless, we report it here to justify the fact it fits into a few lines of code. Readers that want to check that code, and that are non-familiar with the Str module of the OCAML standard library, just need to know that a call to "Str.split (Str.regexp "::")" on the string ""fn::42"" returns the list of strings "["fn";"42"]". Notice here the advantage of having a rich existing library to ease the engineering a set of debugging commands on top of this small kernel. Now, implementing the (classic) continue command that moves forward until a breakpoint is reached is a simple as: We could refine this command and take into account the character numbers. We could also have a better handling of errors in breakpoint syntax.

Profilers

Now we illustrate how to implement a simple counting profiler. For purely data-flow languages like Lustre, such a profiler is completely useless, as every equation is used at each step. Therefore we present now a command that work for Lutin. It is specific to Lutin as it uses the micro-events presented in Section 3.2. The idea is simply to stop at try events and to associate in a table constraints and counters. Each counter is initialized to 1 when a constraint is elected for the first time, and incremented the following times. This profiler could be enhanced (using sat and usat events) by computing 2 counters per constraint, to count the number of times an elected constraint is satisfiable.

Then we can rely again on the hook mechanism of Section 3.3.4 to implement a command that sets on and off the profiler mode: let ( profiler : bool -> unit ) = fun on -> if on then add_hook " profile " prof_add else del_hook " profile "

At this stage, the only remaining work is to write a prof_tbl pretty-printer. One could also implement a coarse-grained timeprofiler using the Unix.time() function at call and exit events for instance.

Backward Moves (Time-travel)

Efficient reversible debuggers [START_REF] Engblom | A review of reverse debugging[END_REF][START_REF] Tolmach | A Debugger for Standard ML[END_REF] store periodically (at ckpt_rate rate) events in a table. Then, in order to move backward, it suffices to move to the lastly stored event, and then to move forward until an event that satisfies the event predicate is found, as illustrated by the arrows labeled by 1 in the drawing below. When no satisfying event is found, we start again with the previously stored event (cf the arrows 2, 3, and 4). When a satisfying event is found, we still need to go forward up to the last backward jump source, to make sure that no more recent event satisfies the event predicate (cf the 2 bullets representing satisfiable events, and the arrow 5). Of course this only works with programs with no side-effect.

Dynamic code modifications

A simple thing we could do to allow dynamic code modification from RDBG would be to change slightly the type of the next field of Event.t, and replace the unit type by an event. Although it might looks a bit dangerous, such kinds of features can, in some circumstances, be useful, for instance test quickly (without modifying the source code) an hypothesis over the debuggee behavior.

THE PLUGIN API

We now present the plugin Application Programming Interface, that is the API for developers that would wish to plug their runtime system (compiler or interpreter) to RDBG. In order to do so, one needs to provide an OCAML library that implements the following interface: The sl alias type (substitution list) is used to hold variables instantiation. The plugin data type holds the list of interface variable names and types in its inputs and outputs fields. It also contains two fields, init_inputs, and init_outputs, to provide initial values to interface variables (i.e., the value of their memories before the first step). Then there are 2 step functions. One simple step function computes an output substitution out of an input one; this function is used to run program as LURETTE would. RDBG can then be used as testing tool 1 . The step_dbg function is more complex, and holds the instrumented version of the runtime system; step_dbg exposes its depths to RDBG via events. Its first parameter is an input variable substitution (the same one as step). The second parameter is the event of the current step (the initial event is built by RDBG). The third parameter is the continuation function. It holds the code that has to be executed after; it is used to fill the next field of Event.t. Notice that the output substitution is not returned by step_dbg, but it should be used in the continuation function instead.

In order to be used with the RDBG interactive command interpreter, plugin modules implementing this interface must be provided under the form of a byte-code library (.cma). RDBG commands can also be executed in batch using ocaml native compiler. In that case one also has to provide a dynamic native code library (.cmxs) version of the plugin.

We have currently implemented 4 such plugins. We have already mentioned the 2 language plugins for Lutin (LutinRun) and for Lustre (Lus2licRun). We also have an OCAML plugin (OCamlRun) that allows to plug programs that are executed via a compiler that uses ocaml as a back-end (cf the examples/ocaml/ directory of the RDBG git repository). We also have a plugin based on standard input and standard output reading and writing (StdioRun). This one is useful to enter inputs manually, via the keyboard or a GUI. It can also be used to plug any kind of systems via TCP/IP sockets. Of course this plugin provides no step_dbg function.

A few additional details about the Lustre and the Lutin plugins are given in Section 6.

COROUTINE VIA CONTINUATIONS

The debugger works in coroutine with the debuggee, and navigates through the event sequence generated by the program execution. Alternative manners of implementing coroutine are discussed in Section 5.4. In RDBG, as the plugin interface suggests, the coroutine relies on continuations. The idea is the following. Transforming a function into Continuation Passing Style (CPS) leads to a function that never returns. It never returns because each function is supposed to call, at its last breath, another function (its continuation), that itself never returns. Once all functions are in CPS, instead of calling the continuation, we can return a data structure (Event.t) that contains a frozen function, which allows to return the control back to the calling function (next field). This calling function (the debugger) hence runs in coroutine with the continuation function (the debuggee). Using this technique, it is easy to execute user code in the debuggee process, which avoids costly context switches and inter-process communications.

In the following, we illustrate this idea by describing how we have transformed the LURETTE top-level command interpreter to implement RDBG.

From LURETTE to RDBG via CPS

We illustrate the old idea of transforming a function into CPS on a vanilla LURETTE top-level function. Once all the administrative work has been done (parsing the various test parameters such as the test length, the name of the SUT, the name of its environment, the name of the file where to save generated data, etc.), LURETTE basically performs: (1) a step of the environment; (2) a step of the SUT to which LURETTE provides the environment outputs of the previous step; (3) a step of the environment to which LURETTE provides the SUT outputs of the previous step; (4) a step of the test oracle, that checks if some property is violated; (5) a test to check if the required number of steps is reached, and if it is not the case, loop back to item 2.

Here is a Vanilla implementation of the LURETTE process, with a SUT that increments its input by one, and an environment that increments its input by 2, and this during 42 steps (we skip the oracle step). The initial version is at the left, and the CPS version at the right.

Instrument the runtime system with events

For the sake of simplicity, we consider here a simplified event type. Doing the same on the event type defined in Section 3.1 is not more difficult.

type event = { msg : string ; next : unit -> event }

Once the LURETTE interpreter is in CPS, instrumenting it with event is straightforward. Here is our CPS Vanilla LURETTE toplevel instrumented with events: Readers of the pdf version of this article are encouraged to try to copy/paste this code out into an OCAML top-level. Then, for example, to launch a 42-steps test session, one just need to do this: let e = ref ( loop 42 0) in while ( true ) do print_string (! e . msg ^" \ n " ); e :=! e . next () done ;;

Handling lists of steps

Most of the modifications in the LURETTE code to transform it into CPS were as straightforward as what is described in Section 5.1. The only convoluted one is the following.

The real implementation of LURETTE is able to run concurrently several programs under test, using several environments (and several oracles to assess the test result). LURETTE therefore iterates over a list of step functions, to compute a list of outputs from a list of inputs. More precisely, we need a function that take as input 2 parameters : a list of variable substitution (holding the global step input values), a list of step functions, that generate some output values. And this function computes from this the substitution holding the global step output values. Here is a possible ml implementation of such a function. let ( step_sl : 's list -> ( ' s list -> 's list ) list -> 's list ) = fun sl sut_step_sl_l -> List . flatten ( List . map ( fun f -> f sl ) sut_step_sl_l )

Now we need a CPS version of it. Here is a possible solution that works (and that is used by RDBG):

Other debugger technologies

One contribution of this article is to base the coroutine between the debugger and the debuggee on the use of continuations. Hence we review here what other debuggers do in this respect. Code Instrumentation. In order to implement debuggers, some code instrumentation is required for the coroutine with the debuggee. Typically, a test is added before each event site to decide whether the control should remain in the debuggee, or should go the debugger. This test can be added via a source to source transformation [START_REF] Ducassé | Tracing Prolog programs by source instrumentation is efficient enough[END_REF][START_REF] Tolmach | A Debugger for Standard ML[END_REF], or at compile time via a compiler option that will add those tests in the generated code. The granularity of this instrumentation influences the performance.

Another option is to modify the executable program at run time (e.g., using ptrace) and to add instructions to jump into the debugger [START_REF] Stallman | Debugging with GDB[END_REF]. The advantage is of course at the performance side, as one doesn't need to perform additional tests at all. But of course such debuggers depend on the target platform. This (mainstream) family of debuggers even often exploits dedicated processor instructions to deal with memory modifications, which is particularly important for low-level languages with no automatic memory management. Some debuggers (e.g., Caml and java) adopt a intermediate solution, which consists in modifying the byte-code on the fly. The resulting debuggers remain platform independent, and save tests. But going though a byte-code interpreter has a performance impact. Another (minor) disadvantage is that the native and the byte-code backends might sometimes behaves differently.

Another very popular way of designing debuggers is to instrument a source code interpreter (as we do here). In that case the tests are embedded in the interpretation algorithm. Is is certainly the easiest method to implement debuggers when an interpreter exists. But developing interpreters on purpose duplicates the development and the maintenance effort when a compiler exists. Moreover, such interpreters generally run slower than the compiler equivalent, and may behave differently.

In the Lustre RDBG plugin (Lutin has no compiler), we minimize that problem as the instrumented interpreter operates over a data structure obtained at the very last pass of the compiler: the one that is pretty-printed to perform the code generation. Errors in this pretty-printing would lead to bugs that would be hided in the debugger indeed. An alternative would have been to instrument an OCAML Lustre code generator.

Coroutine. Most debuggers live in a separate process, and communicate with debuggees through sockets, pipes, or signals. The advantages of having two distinct processes are: (1) to be more robust to memory leaks, and program crashes; (2) to have a better separation of concerns; (3) to allow remote debugging; (4) to allow to debug several programs at the same time.

On the other hand, having the 2 routines in the same process (1) permits a direct access to the runtime system depths; (2) avoids costly context switches (which are less costly than using threads);

(3) avoids costly messages writing/parsing (for sockets and pipes).

ABOUT THE CURRENT PLUGINS

Describing in detail how we have implemented the Lustre and the Lutin RDBG Plugins is out of the scope of this article. A few remarks still. Plugins Design. The step_sut and the step_env functions of Section 5.2 typically (but not necessarily) comes from a Lustre and a Lutin program respectively. In the corresponding plugins, step functions have been transformed into CPS and instrumented in a similar manner. The fact that OCAML is the language used to program LURETTE/RDBG as well as the Lutin and the Lustre interpreters makes the work easier, when it comes to provide an OCAML library that implement the RDBG plugin interface.

The important and difficult work is actually to define a good set of event kinds, so that the operational semantics of the underlying language is usefully depicted by the generated events. Some information can be reconstructed inside the RDBG process, but not all. Nevertheless, it is always possible to control the granularity of the instrumentation when compiling the plugin, and use different granularity for different runtime analysis.

For Lutin, the choices we made with respect to event granularity are described in Section 3.2. For Lustre, our current RDBG-plugin prototype has no micro-step event; each equation generates at most 2 events. It generates a call and an exit event if the equation is a node call, and it generates no event if for variable assignments (wires). This choice only makes sense because the Lustre V6 compiler [START_REF] Jahier | The Lustre V6 Reference Manual[END_REF] does not inline all the nodes (unlike the previous versions of Lustre compilers). Plugins Performance. We have performed a few timing measurements on a simple Lutin program that performs 4 node calls made of trivial constraints (equalities). Then we have compared the execution time of that node executed with the step function, and with the step_dbg function executed via the RDBG command below: let rec loop e = loop ( e . next ()) in loop ( run ());;

and have observed a penalty smaller than 1%. When executed with the profiler of Section 3.3.7, the slowdown is of 30%. A Lutin node with more complex constraints would exhibit a negligible slowdown, as the constraint resolution would dominate the whole execution time. To give an order of idea, the number of events that are generated per second is around 4000 (on a PC running at 3.6GHz, with 8Mo of RAM) and of 8000 on a Lustre equivalent one. Even though the Lustre plugin has no internal events, it generates more events per second, because equations are easier to compute than constraints. More systematic benchmarks should definitely be done on the language plugins.

Note that actually, one source of inefficiency is due to the use of the ocaml top-level, which implies the use of the byte-code compiler. Indeed, the Lutin interpreter is compiled with the ocaml native code compiler (ocamlopt). The performance ratio between the byte-code and the native code compilers is reputed to be of 5 in average (it was 2 on our small program). Nevertheless, this drawback only concerns interactive sessions. It is still possible to run RDBG scripts in batch mode, and to benefit from the native code compiler performances. For efficient interactive sessions, a solution would be to use a native code top-level [START_REF] Fischbach | Towards a native toplevel for the Ocaml language[END_REF].

RELATED WORK

Debugging reactive programs. Ludic is a debugger of Lustre programs [START_REF] Maraninchi | Step-wise+ algorithmic debugging for reactive programs: Ludic, a debugger for Lustre[END_REF]. It features standard step-by-step backward and forward execution and conditional breakpoints using a dedicated Lustre interpreter. It also provides an algorithmic debugging engine. Algorithmic debugging consists in exploring a tree (here, a dataflow network) by asking yes/no questions to the user until the bug is found [START_REF] Shapiro | Algorithmic program debugging[END_REF]. Implementing on top of RDBG the Ludic exploration algorithm, that fits into one page, should be straightforward. The advantage would be to take advantage of the modular compilation capabilities of the Lustre V6 compiler. Indeed, the embedded Ludic Lustre interpreter inlines the whole Lustre program, and only the toplevel node is observable. The Lustre V6 compiler generates "synchronous objects" that are either interpreted (by the RDBG plugin or the Lustre V6 interpreter) or pretty-printed into a C function. The questions asked by the exploration engine might thus be much more precise and easier to answer than it is on inlined code.

Sabry and Sparud performs dataflow reactive programming on top of Haskell using streams and lazy computations. They designed a debugger [START_REF] Sabry | Debugging reactive systems in Haskell[END_REF] that gives insights on the behavior of such programs at the level of recursive equations and abstract away from the underlying Haskell semantics, in order to provide better error messages in case of instantaneous dependency -which are statically detected by all synchronous language compilers.

Elm is a functional language that targets non-critical reactive systems such as web services and GUIs [START_REF] Czaplicki | Asynchronous functional reactive programming for GUIs[END_REF]. The Elm's debugger [START_REF] Pandy | Elm's Time Traveling Debugger[END_REF] thus focuses on interactions with the GUIs. Such a neat GUI integration is complementary to the program-based stochastic stimuli generation we propose.

Programmable debuggers. Several debuggers offer the possibility of defining debugging commands, taking advantage of existing programming environments and relying on an execution trace view as a sequence of runtime events. The Prolog's debugger Opium [START_REF] Ducassé | Opium: An extendable trace analyzer for Prolog[END_REF] and its derivatives (Coca [START_REF] Ducassé | Coca: An automated debugger for c[END_REF] for C, Morphine [START_REF] Jahier | Generic program monitoring by trace analysis[END_REF] for Mercury) are based on a Prolog REPL. The debugger and the debuggee communicates via sockets, but some primitives perform as much event filtering as possible in the debuggee process to avoid context switches and inter-process communications. In Morphine, non-interactive commands (monitors) can be compiled and executed entirely in the debuggee process using dynamic linking.

MzTake [START_REF] Marceau | The design and implementation of a dataflow language for scriptable debugging[END_REF] is programmable debugger for Java based on the Fr-Time [START_REF] Cooper | Embedding dynamic dataflow in a call-by-value language[END_REF], a functional reactive programming language based on Scheme. It communicates with the JVM via sockets (Java Debug Wire Protocol) and pays the price of 2 context switches per event.

Expositor [START_REF] Phang | Expositor: scriptable time-travel debugging with first-class traces[END_REF] is a programmable debugger for C, based on GDB and UndoDB, a commercial replay debugger. The tool provides a Python API to program debugging commands. Typical Expositor program performs an initial query that computes a sub-trace of a complete execution trace. Then other queries can perform further filtering, merge several traces, or fold them. For efficiency, they use a mixture of lazy computations and replay debugging.

The moldable debugger [START_REF] Chiş | The moldable debugger: A framework for developing domain-specific debuggers[END_REF] is a framework for smalltalk, that eases the development of domain-specific debuggers, and orchestrate their use. Such domain-specific debuggers are not really meant to be developed by end-users though.

CONCLUSION

We have presented RDBG, the first debugger for reactive programs that takes into account the feedback loop. We have demonstrated how to implement a full-featured debugger on top of a small kernel plugged onto 2 existing execution systems. This debugger is based on 4 simple and orthogonal ideas: (1) take advantage of existing languages (for the read-eval-print loop and the libraries);

(2) provide users a pre-defined instrumentation and a simple API that allow them to implement their own debugging or monitoring commands; (3) provide compiler designers a plugin API; (4) use continuations to implement coroutine efficiently.

The advantages are multiple: a lightweight implementation (although, there remains technical work in the plugin implementation), which allow to program (or tune) efficient commands (no context switches nor inter process communications). This architecture offers a good separation of concerns, as debugging commands are implemented separately, and can serve for several language plugins. Besides, having the same infrastructure for testing and debugging is very handy; when the test exhibits a bug, everything is ready to launch a debug session.

RDBG has been designed for debugging reactive programs, that interact continuously with their environments. But RDBG can be used with non-reactive programs, which can be seen as degenerated kind of reactive programs that perform only step and that don't interact with their environment (no input/output). More generally, part of the proposed infrastructure does not depend on the target language characteristics (Lustre or Lutin). It depends on the other hand on the host interpreter language (ocaml). However, any language equipped with a REPL and good libraries could be used as host language. In our implementation however, the fact that the host language, is also the language used to compile and interpret the targeted languages (Lustre and Lutin) facilitates the task.

The use of continuations to implement coroutine is not specific to any host or target language either. It might be easier with language where functions are first class citizens though.

RDBG can be used by any execution system that can be interfaced with ocaml. RDBG could therefore be a good starting point to provide to synchronous programs that do not have a debugger yet, in particular for languages which runtime system is already based on OCAML such as Lucid synchrone [START_REF] Pouzet | Lucid synchrone, version 3. Tutorial and reference manual[END_REF], ReactiveML [START_REF] Mandel | ReactiveML: A Reactive Extension to ML[END_REF], or Stimulus [START_REF] Jeannet | Debugging embedded systems requirements with stimulus: an automotive case-study[END_REF] -Stimulus is an industrial version of Lutin that is developed by the Argosim company.

Figure 1 :

 1 Figure 1: A Lutin program made of one macro, and two nodes Figure 1 contains a Lutin program made of two nodes, sut and env. The sut node produces a Boolean output b out of a integer input T, while env produces T out of b. As the names of those 2 nodes suggest, sut plays the of the system under test (or program under debug), and env plays the role of its environment. Therefore

  11 2 try env [ b = f ] " b and T = pre T " 12 2 usat env [ b = f ] " b and T = pre T " 13 2 try env [ b = f ] " not b and between (T ,5 ,10) " 14 2 sat env [ b = f ] " not b and between (T ,5 ,10) " 15 2 exit env [ b =f , T =6 ] " not b and between (T ,5 env [ b = t ] 22 3 try env [ b = t ] " b and T = pre T " 23 3 sat env [ b = t ] " b and T = pre T " 24 3 exit env [ b =t , T =6 ] " b and T = pre T " 25 3 call sut [ T =6 ] 26 3 try sut [ T =6 ] " true " 26 3 sat sut [ T =6 ] " true " 28 3 exit sut [ T =6 , b = t ] " true " 29 3 top -[ T =6 , b = t ] 30 4 call env [ b = t ] 31 4 try env [ b = t ] " T = 1 + pre T " 32 4 sat env [ b = t ] " T = 1 + pre T " 33 4 exit env [ b =t , T =7 ] " T = 1 + pre T " 34 4 call sut [ T =7 ] 35 4 try sut [ T =7 ] " true " 36 4 sat sut [ T =7 ] " true " 37 4 exit sut [ T =7 , b = f ] " true " 38 4 top -[ T =7 , b = f ] 39 5 call env [ b = f ] 40 5 try env [ b = f ] " not b and between (T ,5 ,10) " 41 5 sat env [ b = f ] " not b and between (T ,5 ,10) " 42 5 exit env [ b =f , T =9 ] " not b and between (T ,5

Figure 2 :

 2 Figure 2: An execution trace of the Lutin program of Figure 1

Figure 3 :

 3 Figure 3: The chronograms of the trace of Figure 2

  type src_info = { expr : Expr . t ; (* current ctrl point *) atoms : src_info_atom list ; (* atoms expr is made of *) }

  type src_info_atom = { file : string ; line : int * int ; (* line nb begin / end in file *) char : int * int ; (* char nb begin / end in file *) stack : src_info_atom list ; (* call stack *) }

  type lut_evt = | Top | Call | Exit | Try (* Try a c o n s t r a i n t to compute the step *) | Sat (* The tried c o n s t r a i n t is s a t i s f i a b l e *) | Usat (* The tried c o n s t r a i n t is Not s a t i s f i a b l e *) val to_lut_evt : Event . kind -> lut_evt val from_lut_evt : lut_evt -> Event . kind

  type e = Event . t (* a type alias for brevity *) let rec ( next : e -> e ) = fun e -> e . next () let rec ( nexti : e -> int -> e ) = fun e i -> if i > 0 then nexti ( next e ) (i -1) else e

(

  rdbg ) let e = ref ( run params );; ( rdbg ) let ni i = ( e := nexti ! e i );; ( rdbg ) ni 42;; (* moves 42 events forward *)

  let rec ( next_cond : e -> ( e -> bool ) -> e ) = fun e cond -> let ne = next e in if cond ne then ne else next_cond ne cond

(

  rdbg ) let stop_here e = let val_T = vi " T " e and val_alarm = vb " alarm " e in not (( val_T > 42.0) = > val_alarm );; ( rdbg ) let e = next_cond stop_here e ;;

  let rec ( step : e -> e ) = fun e -> next_cond e ( fun ne -> e . name = ne . name && e . depth = ne . depth && e . kind = ne . kind && e . step = ne . step -1)

  let ( hooks : ( string , ( Event . t -> unit )) Hashtbl . t ) = let ht = Hashtbl . create 1 in Hashtbl . add ht " print_event " print_event ; ht let add_hook = Hashtbl . replace hooks let del_hook = Hashtbl . remove hooks

  let rec ( next : e -> e ) = fun e -> let ne = e . next () in Hashtbl . iter ( fun _ f -> f ne ) hooks ; ne

(

  rdbg ) let ( my_pp_event : e -> unit ) = fun e -> if e . name = " sut " then () elsesinfo2str let cstr = match LutinRdbg . to_lut_evt e . kind with | Top | Call | Exit -> " " | Try -> ( " \" " ^( sinfo2str e )^" \" " ) | Sat | Usat ->( match e . sinfo with None -> " " | Some si -> " \" " ^( Expr . pp si . expr e . data )^" \" " ) in Printf . printf " %2 i %2 i % s % s [% s ] % s \ n " e . nb e . step ( kind2str e . kind ) e . name ( data2str e . data ) cstr ; flush stdout ;;

  env [ b = f ] 11 2 try env [ b = f ] " b and T = pre T " 12 2 usat env [ b = f ] " false and T =4 " 13 2 try env [ b = f ] " not b and between (T ,5 ,10) " 14 2 sat env [ b = f ] " true and between (T ,5 ,10) " 15 2 exit env [ b =f , env [ b = f ] 40 5 try env [ b = f ] " not b and between (T ,5 ,10) " 41 5 sat env [ b = f ] " true and between (T ,5 ,10) " 42 5 exit env [ b =f , T =9 ] 47 5 top -[ T =9 , b = t ]

  let bc = ref 0 let ( brkpts : ( int * string ) list ref ) = ref [] let ( break : string -> unit )= fun str -> brkpts := (! bc , str )::! brkpts ; incr bc let ( del : int -> unit ) = fun i -> brkpts := List . remove_assoc i let ( del_all : unit -> unit ) = fun () -> brkpts :=[]; bc :=0

  let ( brk_matches : e -> string -> bool ) = fun e b -> match e . sinfo , Str . split ( Str . regexp " :: " ) b with | _ , [] -> false (* no more breakpoint *) | None , _ -> false (* no src info at current evt *) | Some _ , [ node ] -> e . name = node | Some src , [ file ; line ] -> let i , atoms = int_of_string line ,( src ()). atoms in List . exists ( fun { line =( debut , fin ) ; file = f } -> f = file && debut <= i && i <= fin ) atoms | _ , _ :: _ :: _ -> failwith " syntax error in brkpts "

  let ( continue : e -> e ) = fun e -> let stop e = List . exists ( brk_matches e ) ! brkpts in next_cond e stop

  let prof_tbl = Hashtbl . create 50 let ( incr_prof : Event . src_info_atom -> unit )= fun si -> try let cpt = Hashtbl . find prof_tbl si in Hashtbl . replace prof_tbl si ( cpt +1) with Not_found -> Hashtbl . add prof_tbl si 1 let ( prof_add : e -> unit ) = fun e -> match to_lut_evt e . kind , e . sinfo with | Try , Some si -> List . iter incr_prof ( si ()). atoms | _ -> ()

  type sl = ( string * Data . v ) list (* substitutions *) type e = Event . t (* a useful alias *) type plugin = { inputs : ( string * string ) list ; (* name and type *) outputs : ( string * string ) list ; (* name and type *) init_inputs : sl ; init_outputs : sl ; step : sl -> sl ; step_dbg : sl -> e -> ( sl -> e -> e ) -> e ; } val make : string array -> plugin

-

  -The lurette toplevel --A CPS version of it let p a b = a + b let p a b ct = ct ( a + b ) let step_env a = p a 1 let step_env a ct = ct ( p a 1) let step_sut a = p a 2 let step_sut a ct = ct ( p a 2) let rec loop i a = let rec loop i a = if i > 42 then if i > 42 then raise ( End a ) else raise ( End a ) else let b = step_env a in step_env a ( loop2 i ) let c = step_sut b in and loop2 i b = step_sut b loop ( i +1) c ( loop ( i +1))

  let plus a b cont = { msg = Printf.sprintf "%i+%i" a b;next=fun() -> cont ( a + b ) } let step_env a cont = { msg = "step_env" ; next = fun () -> plus a 1 cont } let step_sut a cont = { msg = "step_sut" ; next = fun () -> plus a 2 cont } let rec loop2 i b = step_sut b ( loop ( i +1)) and loop i a = if a > 42 then failwith " the end " else { msg = "top"; next = fun () -> step_env a ( loop2 i )}

  let ( step_dbg_sl : ( ' s list -> 'e -> ( ' s list -> 'e -> 'e ) -> 'e ) list -> 's list -> 'e -> ( ' e -> 's list -> 'e ) -> 'e ) = fun step_dbg_sl_l sl e cont = let rec iter_step stepl ( ctx , res_stepl ) sl = match stepl with | [] -> cont ctx ( List . flatten ( res_stepl )) | step :: stepl -> step sl ctx ( fun res_sl ctx -> iter_step stepl ( ctx ,( res_sl :: res_stepl )) sl ) in iter_step step_dbg_sl_l ( ctx ,[]) sl

The LURETTE tool is now an alias for rdbg -lurette


H Nouasse
email: houda.nouasse@enit.fr

P Chiron

B Archimède

SUPERVISORY CONTROL OF RIVER FLOOD: NETWORK MODELING WITH VARYING TIME DELAY

Keywords: Water systems management, Supervisory control, Transportation networks, Time delay, Flood control

Food phenomena become an usual phenomenon occurring in the world and causing serious human and material damage. One way to protect urban zones from river floods is to equipped river with flood control area used as reservoirs in order to reduce the velocity of water and to attenuate the flood wave. The work presented in this paper concerns the supervisory control of such an equipped river. The supervisory scheme consists in four blocks connected to the river process: a Supervisory Control and Data Acquisition block, a Dynamic Parameterization block, a Diagnosis-Decision-Correction block and a Management Objectives and Constraints Generation block. The proposed method is based on a dynamic method combining a reduced transportation network and a temporized matrix from which the water volumes to be stored or released in time are calculated. It makes possible the water storage and release adapted to each river flood scenario, and preservation of agriculture in these floodplains. It takes into account the variation of the time delay with the flow without any modification in the structure of the network.

INTRODUCTION

Flood is an usual phenomenon all over the world. Extreme rainfall events become more frequent and the induced damages more severe. Recently, at the end of April 2014, rainstorm caused floods in the North of Florida, as well as in the east of the United States, rains reached up to 550 millimeters of water. Roads were cut, a street collapsed in Baltimore, flights were delayed, hundred of people have been evacuated, power failure affected more than 28000 homes. This disaster caused the loss of 35 lives (source AFP). Flooding due to excessive rains can cause significant human and material damages around the world.

One way to prevent these flood problems is to equipped river with flood control area used as reservoirs. The reservoirs are emptying with water in order to reduce the water velocity in the river and to attenuate the flood wave. Various research works have been proposed in order to reduce flood peaks and volumes involving linear programming [START_REF] Needham | Linear Programming For Flood Control In The Iowa And Des Moines Rivers[END_REF], folded dynamic programming (Nagesh [START_REF] Kumar | Optimal Reservoir Operation for Flood Control Using Folded Dynamic Programming[END_REF], hybrid analytic/rule-based approach [START_REF] Karbowski | A hybrid analytic/rulebased approach to reservoir system management during flood[END_REF] for example. Most of these methods do not allow controlling the duration of water storage in the reservoir, the storage and release dates ... In order to improve the managers' decisions during these abrupt climatic phenomena, optimization techniques were proposed such as linear programming [START_REF] Karamouz | Water Resources Systems Analysis[END_REF], fuzzy optimization [START_REF] Fu | A fuzzy optimization method for multicriteria decision making: An application to reservoir flood control operation[END_REF][START_REF] Cheng | Fuzzy iteration methodology for reservoir flood control operation[END_REF], stochastic optimization [START_REF] Ratnayake | Deterministic and Stochastic Optimization of a Reservoir System[END_REF] and multi-objective optimization [START_REF] Chuntian | Three-person multi-objective conflict decision in reservoir flood control[END_REF]. Rivers are equipped with sensors and actuators and Supervisory Control and Data Acquisition systems (SCADA) are developed in order to improve their control. Such SCADA systems are used to collect data from sensors, communicate with operators through a Human Machine Interface, and send control values to actuators in many kind of systems such as irrigation canals [START_REF] Figueiredo | SCADA system with predictive controller applied to irrigation canals[END_REF][START_REF] Puerto | Remote management of deficit irrigation in almond trees based on maximum daily trunk shrinkage. Water relations and yield[END_REF][START_REF] Pfitscher | Automatic control of irrigation systems aiming at high energy efficiency in rice crops[END_REF], inland navigation networks [START_REF] Duviella | Adaptive and predictive control architecture of inland navigation networks in a global change context: application to the Cuinchy-Fontinettes reach[END_REF], or energy management [START_REF] Mora | Service-Oriented Architecture approach for Industrial "System of Systems[END_REF] ; network vulnerabilities of such systems are studied in (Amin et al., 2013a,b).

In order to manage the water volumes in case of flood in river area, a supervisory control scheme is proposed in this paper. The structure of the paper is as follows. Section 2 describes the proposed scheme which includes water storage and release in the reservoirs and the variation of time delay with discharge. The effectiveness of the proposed supervisory scheme !"#$%&&' ()&*+,$-)./' 0%+&1"%2%.,&' 312+.' 0+$-).%' 4.,%"5+$%'' (+,+' 6+&%'

()&*+,$-)./' 0%+&1"%2%.,& 312+.' 0+$-).%' 4.,%"5+$%'' (+,+' 6+&%'

789(9' (:.+2)$' *+"+2%; ,%")<+=#.' 0+.+/%2%.,'#>?%$=@%&'+.A'$#.&,"+).,&'/%.%"+=#.' 9A+*,+=#.' 9A+*,+=#.

()+/.#&)&;(%$)&)#.;8#""%$=#.'

S P =#.' B)@%"' C8B D' C8B E' C8B "' C8B .F' F D' F E' F .F' F "' τ D' τ ";D' τ .F;D' Figure 1 -Supervisory Control Scheme.
is shown for different flood situations on a simulated river system in section 3. Finally, conclusion is given and some future works are suggested.

SUPERVISORY CONTROL SCHEME

General Scheme

In order to manage the water volumes in case of flood arising in river area, a supervisory control scheme depicted in Figure 1 is proposed. The process is a river system along which n G reservoirs are distributed.

Theses reservoirs, denoted F CR r (flood control reservoir) are floodplains provided with a controlled gate G r , r = 1, • • • , n G , and are used to absorb the flood. The time delay, τ r , from the gate G r to the following gate G r+1 depends on the flow discharge. The gate opening should be computed in order to maintain the river discharge under a predefined flow value called the attenuation flow. Thus the control of discharges leads to limit the level of the river.

The SCADA system is connected to the river process. It transmits the sensors' values to the Diagnostic-Decision-Correction and the Dynamic Parameterization blocks, and receives the gate opening values in order to send them to the process. The measurements considered herein are levels and discharges.

The Diagnostic-Decision-Correction block (DDC) permits the determination of the gate opening setpoints. It is composed of a transportation network which diagnose the process state, depending on the flow in the river, decide if a correction must be carried out and execute it. The transportation network includes time delays, moreover, if the time delays vary, it is not necessary to change the network structure (no need to add node or arc, only network parame-ters are modified); as described in the next section (section 2.2). Setpoints values are adapted in order to be understood by the SCADA system.

The Dynamic Parameterization (DP) block provides the DDC block with all the necessary dynamic characteristics such as time delays.

The Management Objectives and Constraints Generation block supplies the DDC and DP blocks with management constraints and rules such as the thresholds, the attenuation flow value, the priority parameters.

Network With Time Delay

The river with FCR is modeled with a transportation network including time delay. In previous work [START_REF] Nouasse | Flood lamination strategy based on a threeflood-diversion-area system management[END_REF], we firstly proposed the use of a static transportation network, where time delay where neglected. Because of the importance of the flow delay in the river, the method was improved to include time delay (Nouasse et al., 2013a) and storage and release operations for reservoirs (Nouasse et al., 2013b). The method is composed of a transportation network G and a Temporization Matrix (T M ), as described in Figure 2. In these works, time delays were constant during the simulation; in the present paper, the method is proved to be efficient with delay varying during the simulation.

The objective of the method is to maintain the flow under a predefined attenuation flow denoted Q lam . The attenuation flow is a flow threshold under which the river flow should remain as, expected by the river system manager. Moreover, in order to protect agriculture and to be able to control a new flood episode, when the reservoirs are not empty, and when the discharge level in the river is lower than the attenuation threshold, the stored water can be released. For this purpose a threshold, Q do , is defined as the discharge level under which the water is released from the reservoir. In the case of release, gates are opened in a way that the discharge level in the river remains under the attenuation threshold Q lam .

In order to determine the optimal attenuation flow that satisfies the management objectives and the flood occurring case, we formulated the problem as a Min-Cost-Max-Flow problem. The cost function to minimize is subject to the constraints of flow conservation and minimal and maximal capacities in the network. The network G enables water storage and release from reservoirs. In order to include variable transfer time in the network without oversizing it, the values of delayed flow are stored in the n × 2n G T M matrix. Each column represents the evolution of a gate or a FCR, and each line represents an instant of the evolution of the state of the system,

Actualize_Network Actualize_Temporization_Matrix G 1 G 2 … G r … G nG RES 1 RES 2 … RES r … RES nG 1 2 … k … n
rk rk rk rk rk rk rk rk at each kT c , k = 0, • • • , n, in the horizon H f , with

S 0 G 1 RES 1 RES 2 P 0 G 2 G nG RES nG Q ( k ) RD 1 RD nG RD 2 Stock_RES 1 Max_RES 1 1 0 Q peak 1 0 λ 1 1 0 Stock_RES 1 1000 0 v 1 1 0 Q peak 100 Stock_RES 1 Max_RES 1 1 Stock_RES 2 Max_RES 2 1 0 α 2 1 0 λ 2 1 0 Stock_RES 2 1000 0 v 2 1 Stock_RES 2 Max_RES 2 1 0 Q peak 100
H f = n × T c , n ∈ N + .
The network G = {N , A} where N is a set of 3n G + 2 nodes defined as follows, with r = 1, • • • , n G :

• The node G r represents the gate G r ;

• The node RD r is a release decision node;

• The node RES r is a reservoir node;

• The node S 0 is a source node corresponding to the fictive entry point of the system;

• The node P 0 is a sink node corresponding to the fictive exit point of the system.

The arcs belonging to the set A between the nodes of N are valued, each value is between a maximum capacity and a minimum capacity written respectively in blue and red in Figure 2. The arc value at kT c is computed using an optimization algorithm as detailed in the following. The arcs describe the following connections:

• The arc between the node S 0 and the node RD r , r = 1, . . . , n G , represents the water volume already stored in the reservoir linked to it. Its maximum capacity is M ax RES r , the maximum storage capacity of the reservoir, which depends on the maximum value of the peak flowrate of the flood (Q peak ). Its minimum capacity is Stock RES r , and it corresponds to the amount of water already present in the reservoir.

• The arc between the node RD r and the node G r , r = 1, . . . , n G , represents the draw-off flow leaving the reservoir. Its maximum capacity is denoted λ r .

• The arc between the node RD r and RES r , r = 1, . . . , n G , represents the water volume not released and remaining in the reservoir at the end of the concerned period. Its maximum capacity is Stock RES r , the amount of water already present in the reservoir.

• The arc between the node S 0 and the node G r , r = 2, • • • , n G , takes into account the discharge upstream from the gate G r in the system. Its maximum capacity is Q peak .

• The arc between the node G r and the node RES r , connects the gate with its reservoir. It represents the flow leaving the river through the gate G r towards the reservoir, i. e. the stored water. Its maximum capacity is denoted ν r .

• The arc between the node G r and the node • The arc between the node G n G and the node P 0 , corresponds to the flow-rate downstream from the exit point of the system. Its maximum capacity is Q peak .

P 0 , r = 1, • • • , n G -1,
• The arc between the node RES r and the node P 0 , r = 1, • • • , n G , represents the total volume of water remaining in the reservoir. It respects transportation network conservation flow rules. Its maximum capacity is M ax RES r , its minimum capacity is Stock RES r .

In Figure 2, the cost of each arc is written in black.

In order to limit overflow downstream, the cost of the G n G P 0 arc is set to a high value, here 100. Similarly, the cost of the G r P 0 arcs (r = 1, . . . , n G -1) are set to a value lower or equal to the G n G P 0 arc cost, here 100. In order to release water only in the case where there is no overflow risk, the costs of the RD r RES r arcs (r = 1, . . . , n G ) were set to a value higher than the cost value of the G n G P 0 arc, here 1000. Finally, the three reservoirs are considered to have a similar role, thus, all other costs were set equal to 1.

The Flood-Attenuation algorithm, described in algorithm 1, permits to determine the gate opening setpoint values. The computation of the setpoints is based on the arc values. Firstly, the temporization matrix is initialized. Thereafter, at each k, the network and the temporization matrix are actualized (see algorithm 2 and algorithm 3), the optimal flow is

Algorithm 1: Flood Attenuation input : G the network n = ⌊ H f
Tc ⌋ + 1 the number of samples n G the number of gates and FCR in the system

k r = ⌊ τr Tc ⌋, r = 1, • • • , n G -1 Q input (k) the flow of flood at kT c , k = 1 • • • n Q lam the attenuation flow output:
G the network T M the n × 2n G temporization matrix ϕ * the optimal flow for each arc in G begin % Initialization phase one

for k = 1 to n do T M (k, 1) ← Q input (0) for r = 2 to 2n G do T M (k, r) ← 0 end end % Initialization phase two for r = 1 to n G -1 do for k = 1 to k r -1 do T M (k, r + 1) ← min(Q input (0), Q lam ) end end k ← 1 while (k ≤ n) do Actualize Network(G, k, T M ) ϕ * (k) ← Compute Optimal Flow(G, k) Actualize Matrix(ϕ * (k), k, T M ) k ← k + 1 end end computed.
In order to compute the optimal flow, the Min cost Max flow problem resolution for this network is done, using a Linear Programming formulation (as described in [START_REF] Nouasse | Flood lamination strategy based on a threeflood-diversion-area system management[END_REF]), according to our management objectives. ϕ * xy (k) is the obtained optimal flow from node x to node y in the network G at kT c ; thus, at kT c , we can derive the gate G r opening setpoint value which is equal to ϕ * GrRESr (k) in the storage case and to ϕ * RDrGr (k) in the release case. During the phase one of the initialization of the Flood-Attenuation algorithm, the first column of T M matrix is set to the value of the upriver flow at each kT c (k = 1, • • • , n), which is the flow upstream from the first gate G 1 . The initialization phase two allows us to introduce the flow values for all the gates

G r (r = 2, • • • , n G ) during the non-stationary phase i. e. before k = k nG-1 , with k nG-1 = ⌊ τn G -1
Tc ⌋. We chose in this case to set these upstream discharges to the upriver flow except when it is higher than the attenuation flow. In the algorithm 2, Q(k) is the flowrate entering the network at kT c . It is equal to the sum of flows entering the gates added to the sum of Algorithm 2: Actualization Network input : T M the n × 2n G temporization matrix G the network n G the number of gates and RES in the system k the iteration number Q lam the attenuation flow Q do the draw-off discharge threshold M ax RES r the maximum storage capacity of RES r output:

G the network begin for r = 1 to n G do if T M (k, r) >= Q lam then γ r ← 1 ; µ r ← 0 else if (T M (k, r) < Q do ) then µ r ← 1 ; γ r ← 0 else µ r ← 0 ; γ r ← 0 end end end Q(k) ← 0 for r = 1 to 2n G do Q(k) ← Q(k) + T M (k, r) end for r = 2 to n G do α r ← T M (k, r) end for r = 1 to n G do ν r ← min[max(0, T M (k, r) - Q lam ), max(0, M ax RES r -T M (k, n G + r))] × γ r Stock RES r ← T M (k, n G + r) λ r ← min[Stock RES r , max(0, Q lam - T M (k, r)] × µ r end end
the discharge corresponding to the water volumes already stocked in all the reservoirs. In order to choose which strategy to implement, we introduced management parameters µ r and γ r . The storage phase and release phase cannot occur at the same time for each gate, thus parameters values are set according to the following equation:

         γ r = 1, µ r = 0 if water storage γ r = 0, µ r = 1 if water release γ r = 0 if no water storage µ r = 0 if no water release (1)
The network G is updated at each

kT c (k = 1, • • • , n).
The network parameters values at k-1 such as the adjacency matrix, the costs and the constraints vector

G -1 do T M (k + k r , r + 1) ← T M (k + k r -1, r + 1) + ϕ * GrP0 (k) end for r = 1 to n G do T M (k + 1, n G + r) ← T M (k, n G + r) + ϕ * RESrP0 (k) end end
(arc minimum and maximum values) are input parameters. The strategy parameters, γ r and µ r are set depending on the discharge values in the matrix T M compared to the thresholds Q lam and Q do . The flow entering the network is updated with the sum of the line k of the T M matrix. In order to take into account the transfer time between gates, the maximum flow, α r , upstream from each gate G r (r = 2, • • • , n G ), is set to the T M matrix previous stored value. The maximum capacity, ν r , of the arc G r RES r , is set to the amount of flow overtaking Q lam and lower than the remaining RES r capacity (only if the RES r can be used i. e. γ r = 1). The value of Stock RES r (r = 1, • • • , n G ) is set to its previous value stored in the T M matrix. Finally, the maximum capacity, λ r , of the arc RD r G r is set to the amount of flow to be released from RES r , provided that it remains under Q lam , and that it is lower than the amount of water in the RES r (only if the RES r can be released i. e. γ r = 1).

The matrix T M is updated at each kT c (k = 1, • • • , n) in the Actualization Temporization Matrix algorithm described in algorithm 3. In this matrix, the temporized flow values are stored and actualized such that transfer times can be introduced in the network. In order to take into account the transfer time between gates, the optimal flow from each gate G r (r = 1, • • • , n G -1) to the sink P 0 , ϕ * (Gr,P0) (k), is stored in the T M matrix as the future flow upstream from the next gate G r+1 at k + k r . The flow feeding each RES r (r = 1, • • • , n G ) at k, ϕ * RESr,P0) (k), is added to the flow already stored in order to obtain the new stored value. This value is written in the T M matrix as the future RES r stored value i. e. at k + 1.

Implementation

In order to evaluate the efficiency of the proposed model, a simulation for several cases of flood was done. A test case river was used and the implementation of this river was performed by using a 1D-2D coupled numerical model according to the description given in [START_REF] Garcia-Navarro | The shallow water equations: An example of hyperbolic system[END_REF][START_REF] Morales-Hernandez | A large time step 1D upwind explicit scheme (CF L > 1): Application to shallow water equations[END_REF][START_REF] Morales-Hernández | A conservative strategy to couple 1D and 2D models for shallow water flow simulation[END_REF]. 1D and 2D models are formulated using a conservative upwind cell-centred finite volume scheme. The discretization was based on cross-sections for the 1D model and with triangular unstructured grid for the 2D model. Coupling techniques were based on mass and momentum conservation. The cross section geometry and topography was derived from the Ebro river, however, the shape of the river was simplified. As summarized in Figure 3, the process and SCADA systems were replaced by a 1D-2D coupled simulator (developed by [START_REF] Garcia-Navarro | The shallow water equations: An example of hyperbolic system[END_REF]). In the 1D-2D coupled simulator, each gate is modeled considering that the flow discharge that crosses the gate is governed by the difference between the water level in both side of the gate. The 1D-2D coupled simulator entries are the values of the gate opening thus, the Adaptation Block consisted in the computation of the gate opening values from the optimal flow, by means of a static inversion of the free flow open channel equations [START_REF] Litrico | Conversion from discharge to gate opening for the control of irrigation canals[END_REF]. The Dynamic Parameterization block was used in order to compute the time delays at each kT c (k = 1, • • • , n). The transfer time, τ r , from the gate G r to the gate G r+1 , r = 1, • • • , n G was approximated by the following equation, (see [START_REF] Karamouz | Water Resources Systems Analysis[END_REF] for exam-Algorithm 4: Actualization TM and Simulator input : n G the number of gates and FCR in the system T M the n × 2n G temporization matrix k the iteration number

k r = ⌊ τr Tc ⌋, r = 1, • • • , n G -1 V mes
RESr (k) the measured amount of water stored in the RES r at kT c Q mes (Gr,RESr) (k) the measured discharge from gate G r to RES r at kT c G the network output:

T M the n × 2n G temporization matrix begin for r = 1 to n G -1 do T M (k + k r , r + 1) ← T M (k + k r -1, r + 1) + ϕ * GrP0 (k) + max(0, ϕ * GrRESr (k) -Q mes (Gr,RESr) (k)) end for r = 1 to n G -1 do T M (k + 1, n G + r) ← T M (k, n G + r) + V mes RESr (k) end end ple): τ r = Q Gr S.d Gr,Gr+1 (2)
where Q Gr is the discharge measured at gate G r , S is the wetted cross section, and d Gr,Gr+1 is the distance traveled from G r to G r+1 . In order to evaluate time delays, methods such as the ones developed in [START_REF] Romera | Flooding management using hybrid model predictive control: application to the Spanish Ebro River[END_REF] or in (Bautista and Clemmens, 2015) can also be used. The values measured with the simulator were introduced in the algorithm for actualization of temporized matrix, as described in algorithm 4.

Performance criteria

The flood wave attenuation can be defined as the decrease in the downstream peak flow, due to the attenuation of the flood [START_REF] Bedient | Hydrology and floodplain analysis, 5th Edition[END_REF]. In order to evaluate the performances of the proposed flood attenuation method, three indicators were defined : the attenuation rate (AR), the rate of filling (RF) and the attenuation wave rate (AWR). These measures allow us to evaluate how we prevent downstream flood risk by using the proposed method. All these measures are computed over the time horizon H f , i. e. for k = 0, • • • , n; and we denote Q out the downstream flow. The AR permits to measure the difference between the attenuation threshold objective and the obtained attenuation threshold. It is defined as the ratio between the mean effective at-tenuation flow, Q mea , and the predefined attenuation flow Q lam , as given in equation ( 3) and equation ( 4).

AR = Q mea Q lam (3)    if ∃k|Q out (k) > Q lam Q mea = mean Qout(k)>Q lam Q out (k) else Q mea = max k=1•••n Q out (k) (4)
Another estimator of the attenuation capacity is the AWR which compares the case where the gates are always closed to the case in which a strategy is involved and is expressed by equation ( 5).

AW R = Qcg(k)>Q lam Q cg (k) - Qout(k)>Q lam Q out (k) Qcg(k)>Q lam Q cg (k) (5)
The downstream flow when the gates are closed is denoted Q cg . Finally, RF indicates the water volume storage efficiency. It is computed as the ratio between the water volume stored in all the reservoirs, V s , and the estimated water volume to be stored, V lam , as indicated in equation ( 6), and assuming that V RESr is the maximum volume stored in the reservoir RES r (r = 1, • • • , n G ), during the time horizon H f . V lam is approximated by the trapezoidal numerical integration of the input flow, Q input , above Q lam .

RF = V s V lam , V s = n G r=1
V RESr (6)

Results

Simulation were done within the horizon H f = 86400s corresponding to 24 hours, T c = 100s thus n = 864. The simulated river was equipped with n G = 3 flood control reservoirs, each one controlled by a gravitational gate.

The first case studied is a flood episode with one peak flow of 790.31m 3 /s occurring at k = 330 i. e. around 9 hours after the beginning of the simulation. The values of attenuation and draw-off flows were set to

Q lam = 675m 3 /s and Q do = 600m 3 /s ≈ 90%Q lam .
For this one peak flood, the measured time delays varied between 11T c and 16T c as illustrated in Figure 4. Thus in order to compare the results obtained when the strategy involved constant time delay or varying time delay, we realized simulation for constant time delays underestimated or overvalued:

τ 1 = τ 2 = 10T c , τ 1 = τ 2 = 11T c , τ 1 = τ 2 = 14T c , τ 1 = τ 2 = 16T c , τ 1 = τ 2 = 18T c .
In Figure 5, the Q input value is given in red and results obtained for the four following cases When time delays are computed, the Q out curve is between the Q out curves obtained for the time delays set to their variation interval bounds. In all these cases, the Q out maximum value is given, and denoted Q max in the second column of the Table 1. Without the use of flood control reservoirs the peak flow reaches 777.08m 3 /s, when the gates are always open, the peak flow reaches 690.39m 3 /s. When the proposed strategy is applied, the peak flow decreases and it is lower than the Q lam value when the time delays are computed. When time delays are set to constant values, performance decreases, and we can conclude that it is preferred to overestimate the time delays. The values of the performance criteria obtained in the studied cases are given in Table 1. Whatever the method used for the time delays computation, the ability to absorb the flood is increased when using the transportation network. Indeed AW R = 65.09% when the time delays are underestimated, and AW R = 90.45% when the time delays are overvalued.

Case

When the time delays are set to the minimum value of their variation interval AW R = 91.12%. When the time delays are computed or set to values high enough, AW R = 100%, the peak flow is under the Q lam value. Finally, AW R = 36.83% when the gates are not regulated. AR value is better if it is as close as possible to 100% which is the case for computed time delays. Finally, in all cases the water stored in the reservoir is upper than the estimated needed volume.

The gates' opening height computed by the algorithm with varying time delays is given in blue in Figure 6(a) for the gate G 1 , in Figure 6(b) for the gate G 2 and in Figure 6(c) for the gate G 3 . The water level inside the reservoir is represented in black and the water level in the river in front of the gates in red. The water levels are measured with regard to the river bed. In each Figure, the gate is first opened in order to store water, thereafter, during the phase when the discharge is between Q lam and Q do the gate is closed and finally, the gate is opened in order to empty the reservoir.

In the fourth illustrated cases, the water level inside the reservoirs is superimposed in Figure 7(a) for the gate G 1 , in Figure 7(b) for the gate G 2 and in Figure 7(c) for the gate G 3 . The always open gates case is given in green. The proposed strategy applied with constant time delays: τ 1 = τ 2 = 11T c is given in blue, with τ 1 = τ 2 = 16T c in magenta and with varying time delays in black. For each one of the three gates, the green curve is always above the other ones, which indicates that the needed reservoirs' capacity is lower when using the regulation scheme. Moreover, the reservoirs are filled later in that case and the water remains less time in the reservoirs, thus the agri- cultural zone are better preserved. The water level curve in the case of computed time delays is between the curves obtained for the time delays set to their variation interval bounds.

The second case studied is a flood episode with two peak flows, the first one is of 838.79m 3 /s occurring at k = 324 i. e. around 9 hours after the beginning of the simulation, the second is of 753.79m 3 /s and occurs at k = 570 i. e. around 16 hours after the beginning of the simulation. The values of attenuation and draw-off flows were set to Q lam = 710m 3 /s and Q do = 680m 3 /s ≈ 95%Q lam . This case was proposed in order to evaluate the ability of the method to attenuate a second flood episode. Moreover, Q do is set high enough to allow for a water draw-off from the reservoir after the first peak and before the second one and so that the ability to absorb the second flood exists. Because results obtained in the one peak flood episode shown that results were better in the computed time delay case, we compared for the two peaks flood episode only this case and the case when gates are always open. For this two peak flood, the In Figure 9, the Q input value is given in red, the always open gates case in green. The proposed strategy applied with varying time delays is given in black.

When the gate are always open, the peak flood is reduced however, the discharge exceeds the Q lam value. When time delays are computed, the Q out curve is between the Q out curves obtained for the time delays set to their variation interval bounds. Without the use of flood control reservoirs the peak flow reaches 823.01m 3 /s for the first wave and 746.19m 3 /s for the second one. When applying the strategy, the peak flow reaches 703.65m 3 /s for the first wave and computed for each case are given in Table 2. As in the first test, the ability to absorb the both flood waves is increased when using the proposed method. Indeed, for the first wave, AW R = 100% when gates are regulated whereas AW R = 64.34% when gates are not regulated. For the second wave AW R = 91.90% when the strategy is used whereas AW R = 77.34% when the gates remain open. Before the arrival of the second flood, we take advantage of the decrease of the water level in the river to release a certain amount of water from FCRs in the river. This enables us to better accommodate the second wave of flooding.

CONCLUSION

In this paper, we propose a supervisory control scheme for the management of a river section in a flood situation. The Diagnosis-Detection-Correction block is based on a transportation network model-ing including time delay. It permits to account for the variation of time delays without any modification in the network structure. The results of the connection between the method and the 1D-2D-coupled river simulator were displayed, highlighting the benefits of the strategy. The proposed simulated case permitted to attest the feasibility of including varying time delays in the network. Results are expected to be most obvious when considering a more extended network with longer delays. The strategy consists of two phases: water storage and water release. The storage phase keeps the flow below the attenuation discharge threshold imposed: the flood is attenuated, and the draw-off phase, enables us to preserve the floodplain.

The strategy can be used in order to estimate the capability of river systems equipped with flood control reservoirs to control floods. One of the most important problem to be studied, beyond quantitative flood management, is the quality of water in the river and in the reservoirs. Future research will focus on the integration of pollution problems into the strategy.

Figure 2 -

 2 Figure 2 -Network for Diagnosis-Decision-Correction Block.

  represents the flow transferred from the gate G r to the next gate G r+1 . This discharge is stored in the column of T M associated to the gate G r+1 at line k + k r , with k r = ⌊ τr Tc ⌋. Its maximum capacity is Q peak .

Algorithm 3 :

 3 Actualization TM Matrix input : T M the n × 2n G temporization matrix n G the number of gates and FCR in the system k the iteration number k r = ⌊ τr Tc ⌋, r = 1, • • • , n G -1 ϕ * (k) the optimal flow in G at kT c output: T M the n × 2n G temporization matrix begin for r = 1 to n

Figure 3 -

 3 Figure 3 -Simulator and supervisory control scheme

Figure 4 -

 4 Figure 4 -τ 1 and τ 2 evolution for a 1-peak simulation with Q lam = 675m 3 /s and Q do = 600m 3 /s. are compared. Case one, the gates always open (unregulated reservoirs) is given in green. Case two, the proposed strategy applied with constant time delays: τ 1 = τ 2 = 11T c is given in blue. Case three, the proposed strategy applied with constant time delays: τ 1 = τ 2 = 16T c is given in magenta. Case four, the proposed strategy applied with varying time delays, expressed as function of flow and computed thanks to the Dynamic Parameterization block is given in black. When the gate are always open, the peak flood is reduced however, the discharge exceeds the Q lam value.When time delays are computed, the Q out curve is between the Q out curves obtained for the time delays set to their variation interval bounds. In all these cases, the Q out maximum value is given, and denoted Q max in the second column of the Table1. Without the use of flood control reservoirs the peak flow reaches 777.08m 3 /s, when the gates are always open, the peak flow reaches 690.39m 3 /s. When the proposed strategy is applied, the peak flow decreases and it is lower than the Q lam value when the time delays are computed. When time delays are set to constant values, performance decreases, and we can conclude that it is preferred to overestimate the time delays.

Figure 5 -

 5 Figure5-Q input and Q out for a 1-peak simulation with Q lam = 675m 3 /s and Q do = 600m 3 /s.

Figure 6 -

 6 Figure6-Gate opening and water levels for a 1peak simulation with Q lam = 675m 3 /s and Q do = 600m 3 /s. The water levels inside (outside) the reservoirs are denoted bd (fd) respectively.

Figure 7 -Figure 8 -

 78 Figure 7 -Comparison of water levels inside the reservoirs for a 1-peak simulation with Q lam = 675m 3 /s and Q do = 600m 3 /s.

Figure 9 -

 9 Figure 9 -Q input and Q out for a 2-peak simulation with Q lam = 710m 3 /s and Q do = 680m 3 /s.

Table 1 -

 1 AR, AWR and RF values for the 1 peak scenario.

		Q max	AR% AWR% RF%
	Open Gates 690.39 101.65	36.83	123.42
	τ r = 10T c	679.26 100.39	65.09	115.80
	τ r = 11T c	675.46 100.05	91.12	112.99
	τ r = 14T c	673.83 99.83	100	112.21
	τ r = 16T c	672.64 99.65	100	111.65
	τ r = 18T c	675.47 100.04	90.45	113.94
	Varying τ	674.92 99.99	100	112.59

Table 2 -

 2 712.56m 3 /s for the second one. Applying the strategy allows the discharge to remain under the Q lam value for the first wave and very close to it for the second wave. The values of the performance criteria AR, AWR and RF values for the 2 peaks scenario in the two different cases.

	Case	AR%	AWR% 1st pic 2nd pic	RF%
	Open Gates 100.76	64.34	77.34	103.17
	Varying τ	100.16	100	91.90	99.07

ACKNOWLEDGMENTS

The authors want to thank Confederación Hidrográfica del Ebro for providing the case study used in this paper as well as for sharing their hydrological management expertise, Fluid Mechanics, LIFTEC-EINA, University of Zaragoza for providing the 1D-2D coupled simulator.