diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 3e8a34f29bde03236fd9e236b9b55c5498ad226d..c2bfec5d7293cc48d99ba43d51b9633ffbf12bad 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -122,6 +122,7 @@ import { DialogShowMessageComponent } from "./components/dialog-show-message/dia
 import { DialogConfirmLoadSessionURLComponent } from "./components/dialog-confirm-load-session-url/dialog-confirm-load-session-url.component";
 import { StructureFieldsetContainerComponent } from "./components/structure-fieldset-container/structure-fieldset-container.component";
 import { BasinFieldsetContainerComponent } from "./components/basin-fieldset-container/basin-fieldset-container.component";
+import { PrebarrageService } from "./services/prebarrage.service";
 
 const appRoutes: Routes = [
     { path: "list/search", component: CalculatorListComponent },
@@ -265,6 +266,7 @@ const appRoutes: Routes = [
         HttpService,
         I18nService,
         NotificationsService,
+        PrebarrageService,
         {
             provide: ErrorStateMatcher,
             useClass: ImmediateErrorStateMatcher
diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts
index f294c65e1c3933f926c54bbad53077be75cde7df..955ab75bdc07a2c83c324bf5f457b4ebe91abb29 100644
--- a/src/app/components/pb-schema/pb-schema.component.ts
+++ b/src/app/components/pb-schema/pb-schema.component.ts
@@ -4,8 +4,8 @@ import { MatDialog } from "@angular/material/dialog";
 import screenfull from "screenfull";
 
 import {
-    PreBarrage, PbBassin, PbBassinParams, PbCloison, Observer, IObservable, MermaidUtil
- } from "jalhyd";
+    PbBassin, PbCloison, Observer, IObservable, MermaidUtil
+} from "jalhyd";
 
 import mermaid from "mermaid";
 
@@ -19,9 +19,9 @@ import { FormulairePrebarrage } from "../../formulaire/definition/form-prebarrag
 import { AppComponent } from "../../app.component";
 
 import { fv } from "app/util";
-import { FormulaireNode } from "app/formulaire/elements/formulaire-node";
 import { ServiceFactory } from "app/services/service-factory";
 import { DefinedBoolean } from "app/definedvalue/definedboolean";
+import { PrebarrageService } from "app/services/prebarrage.service";
 
 /**
  * The interactive schema for calculator type "PreBarrage" (component)
@@ -47,10 +47,6 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     /** flag de validité du composant */
     private _isValid: DefinedBoolean;
 
-    private upstreamId = "amont";
-
-    private downstreamId = "aval";
-
     /** événément de changement de validité */
     @Output()
     private validChange = new EventEmitter();
@@ -59,9 +55,6 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     @Output()
     private nodeSelected = new EventEmitter();
 
-    /** underlying PB */
-    private model: PreBarrage;
-
     /** Latest clicked item: a PbCloison, a PbBassin or undefined if river "Upstream" or "Downstream" was clicked */
     private _selectedItem: PbCloison | PbBassin;
 
@@ -72,7 +65,8 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         @Inject(forwardRef(() => GenericCalculatorComponent)) private calculatorComponent: GenericCalculatorComponent,
         private i18nService: I18nService,
         private hotkeysService: HotkeysService,
-        private newPbCloisonDialog: MatDialog
+        private newPbCloisonDialog: MatDialog,
+        private predamService: PrebarrageService
     ) {
         this.hotkeysService.add(new Hotkey("del", AppComponent.onHotkey(this.removeOnHotkey, this)));
         this._isValid = new DefinedBoolean();
@@ -102,10 +96,6 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     /** called when fullscreen state changes */
     public fullscreenChange(isFullscreen: boolean) { }
 
-    public get selectedItem(): any {
-        return this._selectedItem;
-    }
-
     public ngAfterContentInit(): void {
         mermaid.initialize({
             flowchart: {
@@ -185,36 +175,38 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         this.pbSchema.wallsSuffixes = {};
         const def: string[] = [ "graph TB" ];
 
+        const pbModel = this.predamService.model;
+
         // river upstream / downstream
         let upstreamLabel = this.i18nService.localizeText("INFO_LIB_AMONT");
         let downstreamLabel = this.i18nService.localizeText("INFO_LIB_AVAL");
         // add result data Z and Q, if any
         if (
-            this.model?.result?.resultElements
-            && this.model.result.resultElements[0]?.ok
+            pbModel.result?.resultElements
+            && pbModel.result.resultElements[0]?.ok
         ) {
             // when a parameter is variating, index of the variating parameter
             // values to build the data from
             const form = this.calculatorComponent.formulaire as FormulairePrebarrage;
             const idx = form.pbResults.variableIndex;
-            const qValue = this.model.prms.Q.isCalculated
-                ? this.model.result.resultElements[idx].vCalc
+            const qValue = pbModel.prms.Q.isCalculated
+                ? pbModel.result.resultElements[idx].vCalc
                 : (
-                    this.model.prms.Q.hasMultipleValues
-                        ? this.model.prms.Q.getInferredValuesList(this.model.variatingLength())[idx]
-                        : this.model.prms.Q.singleValue
+                    pbModel.prms.Q.hasMultipleValues
+                        ? pbModel.prms.Q.getInferredValuesList(pbModel.variatingLength())[idx]
+                        : pbModel.prms.Q.singleValue
                 );
             // upstream
             upstreamLabel += "<br>";
             upstreamLabel += "Q = " + fv(qValue);
             upstreamLabel += "<br>";
             upstreamLabel += "Z = " + fv(
-                this.model.prms.Z1.isCalculated
-                    ? this.model.result.resultElements[idx].vCalc
+                pbModel.prms.Z1.isCalculated
+                    ? pbModel.result.resultElements[idx].vCalc
                     : (
-                        this.model.prms.Z1.hasMultipleValues
-                        ? this.model.prms.Z1.getInferredValuesList(this.model.variatingLength())[idx]
-                            : this.model.prms.Z1.singleValue
+                        pbModel.prms.Z1.hasMultipleValues
+                            ? pbModel.prms.Z1.getInferredValuesList(pbModel.variatingLength())[idx]
+                            : pbModel.prms.Z1.singleValue
                     )
             );
             // downstream
@@ -222,14 +214,14 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
             downstreamLabel += "Q = " + fv(qValue);
             downstreamLabel += "<br>";
             downstreamLabel += "Z = " + fv(
-                this.model.prms.Z2.hasMultipleValues
-                    ? this.model.prms.Z2.getInferredValuesList(this.model.variatingLength())[idx]
-                    : this.model.prms.Z2.singleValue
-                );
+                pbModel.prms.Z2.hasMultipleValues
+                    ? pbModel.prms.Z2.getInferredValuesList(pbModel.variatingLength())[idx]
+                    : pbModel.prms.Z2.singleValue
+            );
         }
         // add to graph definition
-        def.push(`${this.upstreamId}("${upstreamLabel}")`);
-        def.push(`${this.downstreamId}("${downstreamLabel}")`);
+        def.push(`${this.predamService.upstreamId}("${upstreamLabel}")`);
+        def.push(`${this.predamService.downstreamId}("${downstreamLabel}")`);
 
         // styles
         def.push("classDef wall fill:#e8e8e8,stroke-width:0;");
@@ -240,7 +232,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         def.push("classDef node-highlighted-error fill:#d92f03;"); // irstea-rouille (material "accent"), 900
 
         const sortedWalls: PbCloison[] = [];
-        for (const c of this.model.children) {
+        for (const c of pbModel.children) {
             if (c instanceof PbBassin) {
                 def.push(`${c.uid}("${this.itemDescriptionWithResultData(c)}")`); // rounded edges
                 def.push(`class ${c.uid} basin;`);
@@ -253,8 +245,8 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         // sort then draw walls
         sortedWalls.sort(this.triCloisonsGaucheDroite);
         for (const c of sortedWalls) {
-            const upstreamBasinId = c.bassinAmont === undefined ? this.upstreamId : c.bassinAmont.uid;
-            const downstreamBasinId = c.bassinAval === undefined ? this.downstreamId : c.bassinAval.uid;
+            const upstreamBasinId = c.bassinAmont === undefined ? this.predamService.upstreamId : c.bassinAmont.uid;
+            const downstreamBasinId = c.bassinAval === undefined ? this.predamService.downstreamId : c.bassinAval.uid;
             // record this wall
             const basinsPair = upstreamBasinId + "-" + downstreamBasinId;
             if (! (basinsPair in this.existingWalls)) {
@@ -307,22 +299,6 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         return (sommeA <= sommeB ? -1 : 1);
     }
 
-    /**
-     * check if a list of (Mermaid transformed) ids matches a given id
-     * @param ids ids to transform the Mermaid way
-     * @param itemId id to find
-     */
-    private matchMermaidIds(ids: string[], itemId: string): boolean {
-        return ids.find(id => MermaidUtil.isMermaidEqualIds(id, itemId)) !== undefined;
-    }
-
-    /**
-     * return upstream (and downstream) basin objet
-     */
-    private get upstreamBassin(): PbBassin {
-        return (this.model as unknown) as PbBassin;
-    }
-
     /**
      * @param item DOM element
      */
@@ -332,15 +308,11 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         this.clearHighlightedItems();
         item.classList.add("node-highlighted");
         // find what was clicked
-        if (this.matchMermaidIds([this.upstreamId, this.downstreamId], item.id)) {
-            this._selectedItem = this.upstreamBassin;
-        } else {
-            this._selectedItem = this.model.findChild(item.id);
-        }
+        this._selectedItem = this.predamService.findFromItemId(item.id);
         this.highlightErrorItems(item.id);
         // show proper form and hide results
         this.nodeSelected.emit({
-            node: this._selectedItem === this.upstreamBassin ? undefined : this._selectedItem
+            node: this._selectedItem === this.predamService.upstreamBassin ? undefined : this._selectedItem
         });
         // exit fullscreen
         this.exitFullscreen();
@@ -445,7 +417,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
             if (!done) {
                 if (MermaidUtil.isMermaidEqualIds("amont", item.id)) {
                     this.selectNode(item);
-                    this._selectedItem = this.upstreamBassin;
+                    this._selectedItem = this.predamService.upstreamBassin;
                     done = true;
                 }
             }
@@ -454,7 +426,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
 
     // at this time @Input data is supposed to be already populated
     public ngOnInit() {
-        this.model = this.pbSchema.pb;
+        this.predamService.model = this.pbSchema.pb;
     }
 
     public get enableAddItems(): boolean {
@@ -462,7 +434,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     }
 
     public get enableRemoveButton() {
-        if (this._selectedItem === this.upstreamBassin) {
+        if (this._selectedItem === this.predamService.upstreamBassin) {
             return false;
         }
         // if deleting a PbCloison would replace it by a new one at
@@ -485,20 +457,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
 
     /** Removes a basin or wall, and all related items */
     public onRemoveClick() {
-        this.model.deleteChild(this._selectedItem.findPositionInParent());
-        // never let an unconnected basin ! (not done in model to prevent unwanted
-        // automatic child addition when clearing children)
-        if (this._selectedItem instanceof PbCloison) {
-            const emptyFields: boolean = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit;
-            // if no downstream connections remain, connect to river downstream
-            if (this._selectedItem.bassinAmont?.cloisonsAval.length === 0) {
-                this.model.addChild(new PbCloison(this._selectedItem.bassinAmont, undefined, undefined, emptyFields));
-            }
-            // if no upstream connections remain, connect to river upstream
-            if (this._selectedItem.bassinAval?.cloisonsAmont.length === 0) {
-                this.model.addChild(new PbCloison(undefined, this._selectedItem.bassinAval, undefined, emptyFields));
-            }
-        }
+        this.predamService.deleteSelected(this._selectedItem, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit);
         this.clearResults();
         this.unselect();
         this.refreshWithSelection();
@@ -522,10 +481,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
 
     /** Copies a wall */
     public onCopyClick() {
-        const wall = this._selectedItem as PbCloison;
-        const wallCopy = new PbCloison(wall.bassinAmont, wall.bassinAval, undefined, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit);
-        wallCopy.loadObjectRepresentation(wall.objectRepresentation());
-        this.model.addChild(wallCopy);
+        const wallCopy: PbCloison = this.predamService.copyWall(this._selectedItem as PbCloison, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit);
         this.clearResults();
         this.refreshWithSelection(wallCopy.uid);
         this.calculatorComponent.showPBInputData = true;
@@ -537,8 +493,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
 
     /** Adds a new lone basin */
     public onAddBasinClick() {
-        const newBasin = new PbBassin(new PbBassinParams(20, 99, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit));
-        this.model.addChild(newBasin);
+        const newBasin = this.predamService.addBasin(ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit);
         this.clearResults();
         this.refreshWithSelection(newBasin.uid);
         this.calculatorComponent.showPBInputData = true;
@@ -549,7 +504,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     }
 
     public get enableAddWallButton(): boolean {
-        return (this.model.bassins.length > 0);
+        return this.predamService.hasBasins;
     }
 
     /** Adds a new lone wall, opening a modal to choose connected basins */
@@ -559,7 +514,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
             DialogNewPbCloisonComponent,
             {
                 data: {
-                    basins: this.model.bassins
+                    basins: this.predamService.bassins
                 },
                 disableClose: true
             }
@@ -567,13 +522,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         // apply modifications
         dialogRef.afterClosed().subscribe(result => {
             if (result.up !== undefined && result.down !== undefined) {
-                const wall = new PbCloison(
-                    result.up === 0 ? undefined : this.model.bassins[result.up - 1],
-                    result.down === 0 ? undefined : this.model.bassins[result.down - 1],
-                    undefined,
-                    ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit
-                );
-                this.model.addChild(wall);
+                const wall = this.predamService.addWall(result.up, result.down, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit);
                 this.clearResults();
                 this.refreshWithSelection(wall.uid);
                 this.calculatorComponent.showPBInputData = true;
@@ -588,16 +537,15 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     public get enableUpButton() {
         return (
             this._selectedItem instanceof PbBassin
-            && this.model.findBasinPosition(this._selectedItem.uid) !== 0
-            && this.isStandaloneBasin(this._selectedItem)
+            && this.predamService.findBasinPosition(this._selectedItem.uid) !== 0
+            && this.predamService.isStandaloneBasin(this._selectedItem)
         );
     }
 
     public onMoveBasinUpClick() {
         if (this._selectedItem instanceof PbBassin) {
-            this.model.moveBasin(this._selectedItem.uid, this.model.findBasinPosition(this._selectedItem.uid) - 1);
+            this.predamService.moveBasinUp(this._selectedItem.uid);
         }
-        const basin = this._selectedItem; // utilité ?
         this.clearResults();
         this.refreshWithSelection(this._selectedItem.uid);
         this.calculatorComponent.showPBInputData = true;
@@ -610,16 +558,15 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
     public get enableDownButton() {
         return (
             this._selectedItem instanceof PbBassin
-            && this.model.findBasinPosition(this._selectedItem.uid) !== this.model.bassins.length - 1
-            && this.isStandaloneBasin(this._selectedItem)
+            && !this.predamService.isLastBasin(this._selectedItem.uid)
+            && this.predamService.isStandaloneBasin(this._selectedItem)
         );
     }
 
     public onMoveBasinDownClick() {
         if (this._selectedItem instanceof PbBassin) {
-            this.model.moveBasin(this._selectedItem.uid, this.model.findBasinPosition(this._selectedItem.uid) + 1);
+            this.predamService.moveBasinDown(this._selectedItem.uid);
         }
-        const basin = this._selectedItem;
         this.clearResults();
         this.refreshWithSelection(this._selectedItem.uid);
         this.calculatorComponent.showPBInputData = true;
@@ -665,29 +612,13 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         image.src = blobURL;
     }
 
-    /**
-     * Returns true if given basin is either connected to nothing, or only to
-     * river upstream or downstream
-     */
-    private isStandaloneBasin(basin: PbBassin) {
-        return (
-            (
-                basin.cloisonsAmont.length === 0
-                || basin.cloisonsAmont.map(c => c.bassinAmont).every(e => e === undefined)
-            ) && (
-                basin.cloisonsAval.length === 0
-                || basin.cloisonsAval.map(c => c.bassinAval).every(e => e === undefined)
-            )
-        );
-    }
-
     /**
      * Computes the global Pab validity : validity of every cell of every row
      */
     private updateValidity() {
         // check that at least 1 basin is present and a route from river
         // upstream to river downstream exists (2nd check includes 1st)
-        this._isValid.value = this.model.hasUpDownConnection() && !this.model.hasBasinNotConnected();
+        this._isValid.value = this.predamService.isValid();
 
         if (this._isValid.changed) {
             this.validChange.emit();
@@ -707,32 +638,17 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
         });
     }
 
-    /**
-     * turn 'aval', 'amont' and Mermaid ids to nub real uid
-     */
-    private toNubUid(id: string): string {
-        if (id !== undefined && id !== null) {
-            if (this.matchMermaidIds([this.upstreamId, this.downstreamId], id)) {
-                return this.model.uid;
-            }
-            if (id.startsWith("flowchart-")) { // Mermaid style id (ie. flowchart-id-xx)
-                return id.split('-')[1];
-            }
-        }
-        return id;
-    }
-
     private highlightErrorItems(selectedUid: string) {
         this.nativeElement.querySelectorAll("g.node").forEach(item => {
             item.classList.remove("node-error");
             item.classList.remove("node-highlighted-error");
         });
         const invalidUids: string[] = this.pbSchema.form.checkParameters();
-        selectedUid = this.toNubUid(selectedUid);
+        selectedUid = this.predamService.toNubUid(selectedUid);
         if (invalidUids.length > 0) {
             this.nativeElement.querySelectorAll("g.node").forEach(item => {
                 // in this case, item is a HTML node of the SVG schema which id is a nub uid
-                const itemId = this.toNubUid(item.id);
+                const itemId = this.predamService.toNubUid(item.id);
 
                 if (invalidUids.includes(itemId)) {  // if current item is among invalid ones
                     if (selectedUid === itemId) { // if current item is the selected item
@@ -761,17 +677,17 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni
      * Refreshes the schema; if uid is given, selects the node having this
      * nub uid, else keeps previous selection
      */
-    private refreshWithSelection(uid ?: string) {
+    private refreshWithSelection(uid?: string) {
         // console.debug(`PbSchemaComponent.refreshWithSelection(${uid})`);
         // remember previously selected node
         const selectedNodeUID = this._selectedItem?.uid;
         this.refresh();
         // select a specific node on the schema
         if (uid !== undefined) {
-            this.selectNodeOnSchema(this.model.findChild(uid));
+            this.selectNodeOnSchema(this.predamService.findChild(uid));
         } else if (selectedNodeUID !== undefined) {
             // re-select previously selected node
-            this.selectNodeOnSchema(this.model.findChild(selectedNodeUID));
+            this.selectNodeOnSchema(this.predamService.findChild(selectedNodeUID));
         }
     }
 
diff --git a/src/app/services/prebarrage.service.ts b/src/app/services/prebarrage.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3e43facd3870c5c5d438d0b600cb7e7fa6c5f4b3
--- /dev/null
+++ b/src/app/services/prebarrage.service.ts
@@ -0,0 +1,169 @@
+import { Injectable } from "@angular/core";
+import { MermaidUtil, PbBassin, PbBassinParams, PbCloison, PreBarrage } from "jalhyd";
+
+/**
+ * service relatif au schéma de prébarrage
+ */
+@Injectable()
+export class PrebarrageService {
+    /** predam data */
+    private _model: PreBarrage;
+
+    public readonly upstreamId = "amont";
+
+    public readonly downstreamId = "aval";
+
+    public get model(): PreBarrage {
+        return this._model;
+    }
+
+    public set model(pb: PreBarrage) {
+        this._model = pb;
+    }
+
+    /**
+     * return upstream (and downstream) basin object
+     */
+    public get upstreamBassin(): PbBassin {
+        return (this._model as unknown) as PbBassin;
+    }
+
+    public deleteSelected(selectedItem: PbCloison | PbBassin, emptyFields: boolean) {
+        this._model.deleteChild(selectedItem.findPositionInParent());
+        // never let an unconnected basin ! (not done in model to prevent unwanted
+        // automatic child addition when clearing children)
+        if (selectedItem instanceof PbCloison) {
+            // if no downstream connections remain, connect to river downstream
+            if (selectedItem.bassinAmont?.cloisonsAval.length === 0) {
+                this._model.addChild(new PbCloison(selectedItem.bassinAmont, undefined, undefined, emptyFields));
+            }
+            // if no upstream connections remain, connect to river upstream
+            if (selectedItem.bassinAval?.cloisonsAmont.length === 0) {
+                this._model.addChild(new PbCloison(undefined, selectedItem.bassinAval, undefined, emptyFields));
+            }
+        }
+    }
+
+    public copyWall(wall: PbCloison, emptyFields: boolean): PbCloison {
+        const wallCopy = new PbCloison(wall.bassinAmont, wall.bassinAval, undefined, emptyFields);
+        wallCopy.loadObjectRepresentation(wall.objectRepresentation());
+        this._model.addChild(wallCopy);
+        return wallCopy;
+    }
+
+    public addBasin(emptyFields: boolean): PbBassin {
+        const newBasin = new PbBassin(new PbBassinParams(20, 99, emptyFields));
+        this._model.addChild(newBasin);
+        return newBasin;
+    }
+
+    public get hasBasins(): boolean {
+        return this._model.bassins.length > 0;
+    }
+
+    public get bassins(): PbBassin[] {
+        return this._model.bassins;
+    }
+
+    public addWall(upstreamIndex: number, downstreamIndex: number, emptyFields: boolean): PbCloison {
+        const wall = new PbCloison(
+            upstreamIndex === 0 ? undefined : this._model.bassins[upstreamIndex - 1],
+            downstreamIndex === 0 ? undefined : this._model.bassins[downstreamIndex - 1],
+            undefined,
+            emptyFields
+        );
+        this._model.addChild(wall);
+        return wall;
+    }
+
+    /**
+     * Returns true if given basin is either connected to nothing, or only to
+     * river upstream or downstream
+     */
+    public isStandaloneBasin(basin: PbBassin) {
+        return (
+            (
+                basin.cloisonsAmont.length === 0
+                || basin.cloisonsAmont.map(c => c.bassinAmont).every(e => e === undefined)
+            ) && (
+                basin.cloisonsAval.length === 0
+                || basin.cloisonsAval.map(c => c.bassinAval).every(e => e === undefined)
+            )
+        );
+    }
+
+    /**
+     * @param uid nub uid
+     */
+    public findBasinPosition(uid: string): number {
+        return this._model.findBasinPosition(uid);
+    }
+
+    /**
+     * @param uid nub uid
+     */
+    public moveBasinUp(uid: string) {
+        this._model.moveBasin(uid, this._model.findBasinPosition(uid) - 1);
+    }
+
+    /**
+     * @param uid nub uid
+     */
+    public moveBasinDown(uid: string) {
+        this._model.moveBasin(uid, this._model.findBasinPosition(uid) + 1);
+    }
+
+    /**
+     * @param uid nub uid
+     */
+    public isLastBasin(uid: string): boolean {
+        return this._model.findBasinPosition(uid) === this._model.bassins.length - 1
+    }
+
+    public isValid(): boolean {
+        return this._model.hasUpDownConnection() && !this._model.hasBasinNotConnected();
+    }
+
+    /**
+     * @param uid nub uid
+     */
+    public findChild(uid: string): PbBassin | PbCloison {
+        return this._model.findChild(uid);
+    }
+
+    /**
+     * turn 'aval', 'amont' and Mermaid ids to nub real uid
+     */
+    public toNubUid(itemId: string): string {
+        if (itemId !== undefined && itemId !== null) {
+            if (this.matchMermaidIds([this.upstreamId, this.downstreamId], itemId)) {
+                return this.model.uid;
+            }
+            if (itemId.startsWith("flowchart-")) { // Mermaid style id (ie. flowchart-id-xx)
+                return itemId.split('-')[1];
+            }
+        }
+        return itemId;
+    }
+
+    /**
+     * check if a list of (Mermaid transformed) ids matches a given id
+     * @param ids ids to transform the Mermaid way
+     * @param itemId id to find
+     */
+    private matchMermaidIds(ids: string[], itemId: string): boolean {
+        return ids.find(id => MermaidUtil.isMermaidEqualIds(id, itemId)) !== undefined;
+    }
+
+    /**
+     * @param itemId Mermaid id to find
+     * @returns 
+     */
+    public findFromItemId(itemId: string) {
+        if (this.matchMermaidIds([this.upstreamId, this.downstreamId], itemId)) {
+            return this.upstreamBassin;
+        } else {
+            return this.model.findChild(itemId);
+        }
+    }
+}
diff --git a/src/app/services/service-factory.ts b/src/app/services/service-factory.ts
index a566f3aabb97fc5b2db06dcc5388def593fac7b9..e3ea55cae3c7ce504924688dac8ae1517f3268ba 100644
--- a/src/app/services/service-factory.ts
+++ b/src/app/services/service-factory.ts
@@ -3,6 +3,7 @@ import { FormulaireService } from "./formulaire.service";
 import { I18nService } from "./internationalisation.service";
 import { HttpService } from "./http.service";
 import { NotificationsService } from "./notifications.service";
+import { PrebarrageService } from "./prebarrage.service";
 
 /**
  * A "Singleton" the TS way, that holds pointers to all services, to be accessed
@@ -15,10 +16,12 @@ export const ServiceFactory: {
     i18nService: I18nService;
     httpService: HttpService;
     notificationsService: NotificationsService;
+    prebarrageService: PrebarrageService;
 } = {
     applicationSetupService: undefined,
     formulaireService: undefined,
     i18nService: undefined,
     httpService: undefined,
-    notificationsService: undefined
+    notificationsService: undefined,
+    prebarrageService: undefined
 };