diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html
index b68a85d56669609ca12e28023b6c4bd62701baa0..d3b0c017eeb1010229cc3362691195e9eecd3d9d 100644
--- a/src/app/components/pab-table/pab-table.component.html
+++ b/src/app/components/pab-table/pab-table.component.html
@@ -65,12 +65,13 @@
                     {{ h.title }}
                 </th>
             </tr>
-            <tr>
-                <th *ngFor="let col of columns" (click)="toggleSelection(col, $event)"
-                    (mousedown)="preventCtrlClickBorder($event)" [class.selectable-cell]="isSelectable(col)"
-                    [class.selected-cell]="isSelected(col)">
+            <tr *ngFor="let col of columns">
+                <th *ngFor="let cell of col.cells" (click)="toggleSelection(cell, $event)"
+                    (mousedown)="preventCtrlClickBorder($event)" [class.selectable-cell]="isSelectable(cell)"
+                    [class.selected-cell]="isSelected(cell)" [attr.rowspan]="rowSpan(cell)"
+                    [attr.colspan]="colSpan(cell)" [title]="cellTitle(cell)">
 
-                    {{ col.title }}
+                    {{ cell.title }}
                 </th>
             </tr>
         </ng-template>
diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index dc2470aef9334fdf718ddc095c103a460279dece..8d48ab20a3b7a42edc349e47a265f229f51b342c 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -84,7 +84,6 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         private i18nService: I18nService,
         private formService: FormulaireService,
         private editPabDialog: MatDialog,
-        private appSetupService: ApplicationSetupService,
         private notifService: NotificationsService
     ) {
         this.selectedItems = [];
@@ -465,19 +464,30 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
 
         // 0. build spanned headers over real columns
         this.headers = [];
-        // 1 header for basin
+        // 1 column for basin number
         let bs: any[] = this.model.children;
         bs = bs.concat(this.model.downWall);
+        this.headers.push({
+            title: this.i18nService.localizeText("INFO_PAB_NUM_BASSIN"),
+            selectable: bs,
+            rowspan: 2
+        });
+        // 3 columns for basin information
         this.headers.push({
             title: this.i18nService.localizeText("INFO_PAB_BASSIN"),
-            colspan: 5,
+            colspan: 3,
+            selectable: bs
+        });
+        // 1 col for wall
+        this.headers.push({
+            title: this.i18nService.localizeText("INFO_PB_CLOISON"),
             selectable: bs
         });
         // 1 header for each device of the wall having the most devices (including downwall)
         for (let i = 0; i < maxNbDevices; i++) {
             this.headers.push({
                 title: sprintf(this.i18nService.localizeText("INFO_PAB_CLOISON_OUVRAGE_N"), (i + 1)),
-                colspan: 3,
+                colspan: 2,
                 selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
                 selectableColumn: i
             });
@@ -485,43 +495,42 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
 
         // A. build columns set
         this.cols = [];
-        // 5 cols for basin
-        this.cols.push({
-            title: this.i18nService.localizeText("INFO_PAB_NUM_BASSIN"),
-            selectable: bs
-        });
-        this.cols.push({
+        const headerRow1 = { cells: [] };
+        const headerRow2 = { cells: [] };
+        this.cols.push(headerRow1);
+        this.cols.push(headerRow2);
+
+        // 3 cols for basin information
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB"),
             selectable: bs
         });
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB"),
             selectable: bs
         });
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB"),
             selectable: bs
         });
-        this.cols.push({
-            title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM"),
-            selectable: bs
-        });
-        // no col for wall type (defined by rowspan-2 header above)
-        // 3 cols for each device of the wall having the most devices (including downwall)
+
+        // 2 cols for each device of the wall having the most devices (including downwall)
         for (let i = 0; i < maxNbDevices; i++) {
-            this.cols.push({
-                title: this.i18nService.localizeText("INFO_PAB_HEADER_TYPE"),
-                selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
-                selectableColumn: i
-            });
-            this.cols.push({
+            const sel = this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]);
+            if (i == 0) {
+                headerRow1.cells.push({
+                    title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM"),
+                    selectable: bs,
+                });
+            }
+            headerRow1.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_PARAMETERS"),
-                selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
+                selectable: sel,
                 selectableColumn: i
             });
-            this.cols.push({
+            headerRow1.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_VALUES"),
-                selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
+                selectable: sel,
                 selectableColumn: i
             });
         }
@@ -535,27 +544,41 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 value: l
             };
         });
+
+        // NOTE : EB = empty cell (3 columns wide) for LB,BB,ZRMB
+        //        EZRAM = empty cell below ZRAM value (QA editor height + 1)
+
+        const minQAEditorRowCount: number = 1;
+
         // B.1 many rows for each wall
         let childIndex = 0;
         for (const cloison of this.model.children) {
-            // as much rows as the greatest number of parameters among its devices
-            const maxNbParams = this.findMaxNumberOfDeviceParameters(cloison);
-            for (let i = 0; i < maxNbParams; i++) {
-                // build device params row
+            // maximum device parameter count for all devices in this wall
+            const maxDeviceParamCount = this.findMaxNumberOfDeviceParameters(cloison);
+
+            // total row count for this wall = max device parameter row count + 1 line for device type
+            // minimum = 1 row (EB) + 1 row (LB,BB,ZRMB cells) + QA editor
+            const totalRowCount = Math.max(maxDeviceParamCount + 1, 1 + 1 + minQAEditorRowCount);
+
+            // QA editor row count : total row count - 1 (LB,BB,ZRMB cells) - 1 (EB, see note)
+            const QAEditorRowCount = Math.max(totalRowCount - 2, minQAEditorRowCount);
+
+            // total parameter rows (all parameters without device type) = total row count - 1
+            const paramRowCount = totalRowCount - 1;
+
+            for (let r = 0; r < totalRowCount; r++) {
                 const deviceParamRow = { selectable: cloison, cells: [] };
-                // basin number and ZRAM
-                if (i === 0) {
+                if (r === 0) {
                     // basin number
                     deviceParamRow.cells.push({
                         value: childIndex + 1,
-                        rowspan: maxNbParams + 1,
+                        rowspan: totalRowCount,
                         class: "basin_number",
                         selectable: cloison
                     });
-                    // 3 empty cells
+                    // empty line (EB cell, see note)
                     deviceParamRow.cells.push({
                         colspan: 3,
-                        rowspan: maxNbParams - 1,
                         selectable: cloison
                     });
                     // ZRAM
@@ -564,111 +587,46 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
                     });
                 }
-                // basin cells on the last but 1 row
-                if (i === maxNbParams - 1) {
+                // LB, BB, ZRMB, EZRAM cell (see note)
+                else if (r === 1) {
+                    // Longueur bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.LB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB")
                     });
+                    // Largeur bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.BB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB")
                     });
+                    // Cote radier mi bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.ZRMB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB")
                     });
-                }
-                // 1 empty cell below ZRAM
-                if (i === 1) {
+                    // empty cell (EZRAM cell, see note)
                     deviceParamRow.cells.push({
-                        rowspan: maxNbParams,
+                        rowspan: paramRowCount,
                         selectable: cloison
                     });
                 }
-                // device param cells : 3 cells for each device
-                for (const ouvrage of cloison.structures) {
-                    const nvParam = ouvrage.getNthVisibleParam(i);
-                    const nvParamTitle = nvParam ? this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol) : "";
-                    // cell 1 : device type
-                    if (i === 0) { // 1st row
-                        deviceParamRow.cells.push({
-                            model: ouvrage,
-                            modelValue: ouvrage.getPropValue("loiDebit"),
-                            options: loisCloisons,
-                            selectable: ouvrage
-                        });
-                    }
-                    // fill space below device type selector
-                    if (i === 1) {
-                        deviceParamRow.cells.push({
-                            rowspan: (maxNbParams - 1),
-                            selectable: ouvrage
-                        });
-                    }
-                    // cell 2 : param name
-                    if (nvParam) {
-                        deviceParamRow.cells.push({
-                            value: nvParam.symbol,
-                            title: nvParamTitle,
-                            selectable: ouvrage
-                        });
-                    } else {
-                        deviceParamRow.cells.push({
-                            selectable: ouvrage
-                        });
-                    }
-                    // cell 3 : param value
-                    if (nvParam) {
-                        deviceParamRow.cells.push({
-                            model: nvParam,
-                            title: nvParamTitle,
-                            selectable: ouvrage
-                        });
-                    } else {
-                        deviceParamRow.cells.push({
-                            selectable: ouvrage
-                        });
-                    }
-                }
-                // fill horizontal space
-                const devDiff =  (maxNbDevices - cloison.structures.length);
-                if (i === 0) {
-                    for (let j = 0; j < devDiff; j++) {
-                        deviceParamRow.cells.push({
-                            colspan: 3,
-                            rowspan: maxNbParams,
-                            selectable: cloison,
-                            selectableColumn: cloison.structures.length + j
-                        });
-                    }
-                }
-                // done !
-                this.rows.push(deviceParamRow);
-            }
-            // 1 row for QA editor
-            const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form);
-            qaParam.radioConfig = ParamRadioConfig.VAR;
-            const qaRow: { selectable: any, cells: any[] } = {
-                selectable: undefined,
-                cells: [
-                    {
+                else if (r === 2) {
+                    // rows for QA editor
+                    const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form);
+                    qaParam.radioConfig = ParamRadioConfig.VAR;
+                    deviceParamRow.cells.push({
                         model: qaParam,
                         colspan: 3,
+                        rowspan: QAEditorRowCount,
                         qa: true,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA")
-                    }
-                ]
-            };
-            // as many pairs of columns as the maximum number of devices
-            qaRow.cells.push({
-                colspan: maxNbDevices * 3,
-                // selectable: cloison @TODO oui ou non ?
-            });
-            // done !
-            this.rows.push(qaRow);
+                    });
+                }
 
-            childIndex ++;
+                // devices
+                this.fillParallelStructureCells(deviceParamRow, r, paramRowCount, loisCloisons);
+            }
+            childIndex++;
         }
 
         // B.2 many rows for downwall
@@ -680,22 +638,23 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
             };
         });
         // as much rows as the greatest number of parameters among its devices
-        const maxNbParamsDW = this.findMaxNumberOfDeviceParameters(this.model.downWall);
-        for (let i = 0; i < maxNbParamsDW; i++) {
+        const dwParamCount = this.findMaxNumberOfDeviceParameters(this.model.downWall); // device parameter count
+        const paramRowCount = dwParamCount + 1; // max line number for parameters (without device type)
+        for (let r = 0; r < paramRowCount; r++) {
             // build device params row
             const deviceParamRowDW = { selectable: this.model.downWall, cells: [] };
-            // basin number
-            if (i === 0) {
+            if (r === 0) {
+                // "downstream"
                 deviceParamRowDW.cells.push({
                     value: "Aval",
-                    rowspan: maxNbParamsDW,
+                    rowspan: paramRowCount,
                     class: "basin_number",
                     selectable: this.model.downWall
                 });
                 // 3 empty cells
                 deviceParamRowDW.cells.push({
                     colspan: 3,
-                    rowspan: maxNbParamsDW ,
+                    rowspan: paramRowCount,
                     selectable: this.model.downWall
                 });
                 // ZRAM
@@ -704,74 +663,68 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
                 });
             }
-            if (i === 1) {
-                // 1 empty cell
+            if (r === 1) {
+                // 1 empty cell (in place of the QA editor)
                 deviceParamRowDW.cells.push({
-                    rowspan: maxNbParamsDW - 1,
+                    rowspan: dwParamCount,
                     selectable: this.model.downWall
                 });
             }
-            // downwall device param cells : 3 cells for each device
-            for (const ouvrage of this.model.downWall.structures) {
-                const nvParam = ouvrage.getNthVisibleParam(i);
-                const nvParamTitle = nvParam ? this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol) : "";
-                // cell 1 : device type
-                if (i === 0) { // 1st row
-                    deviceParamRowDW.cells.push({
-                        model: ouvrage,
-                        modelValue: ouvrage.getPropValue("loiDebit"),
-                        options: loisAval
-                    });
-                }
-                // fill space
-                if (i === 1) {
-                    deviceParamRowDW.cells.push({
-                        rowspan: (maxNbParamsDW - 1),
-                        selectable: ouvrage
+
+            // devices
+            this.fillParallelStructureCells(deviceParamRowDW, r, paramRowCount, loisAval);
+        }
+
+        this.updateValidity();
+    }
+
+    private fillParallelStructureCells(tableRow: any, rowIndex: number, maxStructParamRowCount: number, loisAdmissibles: any[]) {
+        const ps: ParallelStructure = tableRow.selectable;
+        for (const struct of ps.structures) { // for each device
+            const structParamCount = this.nubVisibleParameterCount(struct);
+            if (rowIndex === 0) {
+                // 1st row : device type
+                tableRow.cells.push({
+                    model: struct,
+                    modelValue: struct.getPropValue("loiDebit"),
+                    options: loisAdmissibles,
+                    selectable: struct,
+                    colspan: 2
+                });
+            }
+            else if (rowIndex === structParamCount + 1) {
+                // fill remaining space
+                const remaining = maxStructParamRowCount - structParamCount;
+                if (remaining > 0) {
+                    tableRow.cells.push({
+                        colspan: 2,
+                        rowspan: remaining,
+                        selectable: struct
                     });
                 }
-                // cell 2 : param name
+            }
+            else {
+                // parameter row
+                const nvParam = struct.getNthVisibleParam(rowIndex - 1);
                 if (nvParam) {
-                    deviceParamRowDW.cells.push({
+                    const nvParamTitle = this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol);
+                    // parameter name
+                    tableRow.cells.push({
                         value: nvParam.symbol,
                         title: nvParamTitle,
-                        selectable: ouvrage
-                    });
-                } else {
-                    deviceParamRowDW.cells.push({
-                        selectable: ouvrage
+                        selectable: struct
                     });
-                }
-                // cell 3 : param value
-                if (nvParam) {
-                    deviceParamRowDW.cells.push({
+                    // parameter value
+                    tableRow.cells.push({
                         model: nvParam,
                         title: nvParamTitle,
-                        selectable: ouvrage
-                    });
-                } else {
-                    deviceParamRowDW.cells.push({
-                        selectable: ouvrage
-                    });
-                }
-            }
-            // fill horizontal space
-            const devDiff =  (maxNbDevices - this.model.downWall.structures.length);
-            if (i === 0) {
-                for (let j = 0; j < devDiff; j++) {
-                    deviceParamRowDW.cells.push({
-                        colspan: 3,
-                        rowspan: maxNbParamsDW,
-                        selectable: this.model.downWall,
-                        selectableColumn: this.model.downWall.structures.length + j
+                        selectable: struct
                     });
                 }
             }
-            // done !
-            this.rows.push(deviceParamRowDW);
         }
-
-        this.updateValidity();
+        // done !
+        this.rows.push(tableRow);
     }
 
     /**
@@ -790,18 +743,20 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         return maxNbDevices;
     }
 
+    private nubVisibleParameterCount(n: Nub) {
+        let res = 0;
+        for (const p of n.parameterIterator) {
+            if (p.visible) {
+                res++;
+            }
+        }
+        return res;
+    }
+
     private findMaxNumberOfDeviceParameters(struct: ParallelStructure): number {
         let maxNbParams = 1;
-        for (const d of struct.getChildren()) {
-            let nbParams = 0;
-            for (const p of d.parameterIterator) {
-                if (p.visible) {
-                    // console.log("(counting)", p.symbol);
-                    nbParams ++;
-                }
-            }
-            // console.log(">>> child params: ", nbParams);
-            maxNbParams = Math.max(maxNbParams, nbParams);
+        for (const child of struct.getChildren()) {
+            maxNbParams = Math.max(maxNbParams, this.nubVisibleParameterCount(child));
         }
         return maxNbParams;
     }
@@ -1039,7 +994,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         for (let i = 0; i < this.childrenToAdd; i++) {
             for (const si of this.selectedItems) {
                 const newChild = Session.getInstance().createNub(
-                    si.properties.clone(),
+                    si,
                     si.parent
                 );
                 // copy parameter values
@@ -1052,7 +1007,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 if (si instanceof ParallelStructure) {
                     for (const c of si.getChildren()) {
                         const newGrandChild = Session.getInstance().createNub(
-                            c.properties.clone(),
+                            c,
                             newChild
                         );
                         // copy children parameters values
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index b7b836bd09864cbe81f26ff922b9d154c1a98a70..b31fc6330b5b2de4bd86edeefe7fcff5786c7fa5 100755
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -470,7 +470,7 @@
     "INFO_PAB_OUVRAGES": "Devices",
     "INFO_PAB_EDIT_VALUES": "Modify values",
     "INFO_CALCULATE_FIRST": "Calculate this module first",
-    "INFO_PAB_NUM_BASSIN": "Basin #",
+    "INFO_PAB_NUM_BASSIN": "Basin/wall #",
     "INFO_PAB_HEADER_TYPE": "Type",
     "INFO_PAB_HEADER_PARAMETERS": "Parameters",
     "INFO_PAB_HEADER_VALUES": "Values",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 1b2892173b6f6383f61f07fac4766fbc1288b0b5..21aca059bcbca69d01786097c849cecafa1e842d 100755
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -471,7 +471,7 @@
     "INFO_PAB_OUVRAGES": "Ouvrages",
     "INFO_PAB_EDIT_VALUES": "Modifier les valeurs",
     "INFO_CALCULATE_FIRST": "Calculer ce module d'abord",
-    "INFO_PAB_NUM_BASSIN": "N° de bassin",
+    "INFO_PAB_NUM_BASSIN": "N° de bassin/cloison",
     "INFO_PAB_HEADER_TYPE": "Type",
     "INFO_PAB_HEADER_PARAMETERS": "Paramètres",
     "INFO_PAB_HEADER_VALUES": "Valeurs",