diff --git a/spec/value_ref/value_ref_variable_extraresult.spec.ts b/spec/value_ref/value_ref_variable_extraresult.spec.ts
index 4181371846363a2fe1f32b669a41db192231bb10..384e8270717a4407e7fa1dac6ceea45c26f3a3fd 100644
--- a/spec/value_ref/value_ref_variable_extraresult.spec.ts
+++ b/spec/value_ref/value_ref_variable_extraresult.spec.ts
@@ -1,5 +1,5 @@
 // tslint:disable-next-line:max-line-length
-import { CourbeRemous, CourbeRemousParams, cSnRectang, MethodeResolution, ParamsSectionRectang, Result } from "../../src";
+import { CourbeRemous, CourbeRemousParams, cSnRectang, MethodeResolution, ParamsSectionRectang, Result, ParamDefinition, ParamDomain, ParamDomainValue } from "../../src";
 
 /**
  * IMPORTANT !
@@ -47,10 +47,11 @@ describe("référence d'un paramètre à un résultat complémentaire multivalu
             0.9962500000000004, 0.9970000000000003, 0.9977500000000002,
             0.9985000000000002, 0.9992500000000001, 1];
 
-        const vs = rem.getLinkableValues("flu");
+        const fakeParamDef = new ParamDefinition(undefined, "flu", ParamDomainValue.ANY);
+        const vs = rem.getLinkableValues(fakeParamDef);
         expect(Object.keys(vs).length).toEqual(1);
 
-        const vs2 = vs[0].value;
+        const vs2 = vs[0].element;
         expect(vs2.name).toEqual("flu");
 
         let i = 0;
diff --git a/src/compute-node.ts b/src/compute-node.ts
index ee8892db68a2b8ffaec6a560634b187eb1a26ccb..28fa7eccbd0bd61a0ec0008ace18fb8c75d26b55 100644
--- a/src/compute-node.ts
+++ b/src/compute-node.ts
@@ -36,8 +36,17 @@ export enum ComputeNodeType {
  * noeud de calcul
  */
 export abstract class ComputeNode extends JalhydObject implements IDebug {
+    /**
+     * Set of ParamDefinition, used as input of this node
+     */
     protected _prms: ParamsEquation;
 
+    /**
+     * { symbol => ParamFamily } map for ExtraResults; defines a priori which
+     * future extra result can be linked to other Nub's parameters
+     */
+    protected _extraResultsFamilies: any;
+
     private _debug: Debug;
 
     constructor(prms: ParamsEquation, dbg: boolean = false) {
@@ -55,13 +64,17 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
         this._prms.Pr.calculability = ParamCalculability.FREE;
         this.setParametersCalculability();
         this._prms.DefineCalculability();
+        this.setExtraResultsFamilies();
     }
 
     public get prms(): ParamsEquation {
         return this._prms;
     }
 
-    /** Retrieves a parameter from its symbol (unique in a given Nub) */
+    /**
+     * Retrieves a parameter from its symbol (unique in a given Nub)
+     * @WARNING also retrieves **extra results** and returns them as ParamDefinition !
+     */
     public getParameter(name: string): ParamDefinition {
         for (const p of this.parameterIterator) {
             if (p.symbol === name) {
@@ -93,6 +106,17 @@ export abstract class ComputeNode extends JalhydObject implements IDebug {
         return this._debug.DBG;
     }
 
+    /**
+     * Define ParamFamily (@see ParamDefinition) for extra results
+     */
+    protected setExtraResultsFamilies() {
+        this._extraResultsFamilies = {};
+    }
+
+    public get extraResultsFamilies()  {
+        return this._extraResultsFamilies;
+    }
+
     protected abstract setParametersCalculability(): void;
 
 }
diff --git a/src/cond_distri.ts b/src/cond_distri.ts
index 6ad742b7fd67e9680f2b87baca753fa39e131dc2..1b97c1bd95c9caa878d5899abd7b0ff0edd82068 100644
--- a/src/cond_distri.ts
+++ b/src/cond_distri.ts
@@ -1,5 +1,5 @@
 import { Nub } from "./nub";
-import { ParamCalculability, ParamDefinition } from "./param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "./param/param-definition";
 import { ParamDomainValue } from "./param/param-domain";
 import { ParamsEquation } from "./param/params-equation";
 import { Result } from "./util/result";
@@ -27,10 +27,10 @@ export class ConduiteDistribParams extends ParamsEquation {
 
     constructor(rQ: number, rD: number, rJ: number, rLg: number, rNu: number) {
         super();
-        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ);
-        this.D = new ParamDefinition(this, "D", ParamDomainValue.POS, rD);
+        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ, ParamFamily.FLOWS);
+        this.D = new ParamDefinition(this, "D", ParamDomainValue.POS, rD, ParamFamily.DIAMETERS);
         this.J = new ParamDefinition(this, "J", ParamDomainValue.POS, rJ);
-        this.Lg = new ParamDefinition(this, "Lg", ParamDomainValue.POS, rLg);
+        this.Lg = new ParamDefinition(this, "Lg", ParamDomainValue.POS, rLg, ParamFamily.LENGTHS);
         this.Nu = new ParamDefinition(this, "Nu", ParamDomainValue.POS, rNu);
 
         this.addParamDefinition(this.Q);
diff --git a/src/dichotomie.ts b/src/dichotomie.ts
index 00ba788d772a92c2cb3b83774c032ead3d7f5353..b17acfe1bfd897b7f52ea572e4c3ff058034a1df 100644
--- a/src/dichotomie.ts
+++ b/src/dichotomie.ts
@@ -273,7 +273,7 @@ export class Dichotomie extends Debug {
     private getStartInterval(rTarget: number, rInit: number): any {
         this.debug("intervalle de départ");
 
-        const prmDom: ParamDomain = this._paramX.getDomain();
+        const prmDom: ParamDomain = this._paramX.domain;
         const step = 0.001;
         // const step = this.nub.prms.Pr.v;
 
diff --git a/src/index.ts b/src/index.ts
index 28bdee68b1a1d5c67df4234f8924f3c7ee880d1a..67bf8be63d14f736f14cafe00f5b81fe70bdb152 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -30,5 +30,6 @@ export * from "./structure/structure";
 export * from "./structure/structure_params";
 export * from "./structure/factory_structure";
 export * from "./structure/structure_props";
+export * from "./value_ref/object_ref";
 export * from "./jalhyd_object";
 export * from "./date_revision";
diff --git a/src/jalhyd_object.ts b/src/jalhyd_object.ts
index 398456e3b199a576d0f2f23cb1c3aa773dc2f515..0911cb24a6c2b5a2a997440feb173948bbfa86cd 100644
--- a/src/jalhyd_object.ts
+++ b/src/jalhyd_object.ts
@@ -1,3 +1,5 @@
+import { ParamFamily } from "./param/param-definition";
+
 export interface IJalhydObject {
     readonly uid: string;
 }
@@ -6,6 +8,10 @@ export interface INamedObject extends IJalhydObject {
     readonly name: string;
 }
 
+export interface IObjectWithFamily extends IJalhydObject {
+    readonly family: ParamFamily;
+}
+
 export abstract class JalhydObject implements IJalhydObject {
 
     public get uid(): string {
diff --git a/src/lechaptcalmon.ts b/src/lechaptcalmon.ts
index e003c54b6c2484ffde65134146e05234b73a24ad..a00363fce1eda374cd487a1f7de8ac0761d9b1d9 100644
--- a/src/lechaptcalmon.ts
+++ b/src/lechaptcalmon.ts
@@ -1,5 +1,5 @@
 import { Nub } from "./nub";
-import { ParamCalculability, ParamDefinition } from "./param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "./param/param-definition";
 import { ParamDomainValue } from "./param/param-domain";
 import { ParamsEquation } from "./param/params-equation";
 import { Result } from "./util/result";
@@ -31,10 +31,10 @@ export class LechaptCalmonParams extends ParamsEquation {
 
     constructor(rQ: number, rD: number, rJ: number, rLg: number, rL: number, rM: number, rN: number) {
         super();
-        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ);
-        this._D = new ParamDefinition(this, "D", ParamDomainValue.POS, rD);
+        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ, ParamFamily.FLOWS);
+        this._D = new ParamDefinition(this, "D", ParamDomainValue.POS, rD, ParamFamily.DIAMETERS);
         this._J = new ParamDefinition(this, "J", ParamDomainValue.POS, rJ);
-        this._Lg = new ParamDefinition(this, "Lg", ParamDomainValue.POS, rLg);
+        this._Lg = new ParamDefinition(this, "Lg", ParamDomainValue.POS, rLg, ParamFamily.LENGTHS);
         this._L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL);
         this._M = new ParamDefinition(this, "M", ParamDomainValue.POS, rM);
         this._N = new ParamDefinition(this, "N", ParamDomainValue.POS, rN);
diff --git a/src/macrorugo/macrorugo.ts b/src/macrorugo/macrorugo.ts
index 3d26de1cfa7d065f2fcd6f944a97203e7bc800cb..97fa19e024cd59836f0c66d86e58606b26b08b95 100644
--- a/src/macrorugo/macrorugo.ts
+++ b/src/macrorugo/macrorugo.ts
@@ -1,5 +1,5 @@
 import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
+import { ParamCalculability, ParamFamily } from "../param/param-definition";
 import { ParamValueMode } from "../param/param-value-mode";
 import { Result } from "../util/result";
 import { MacrorugoParams } from "./macrorugo_params";
@@ -140,6 +140,13 @@ export class MacroRugo extends Nub {
         this.prms.Cd0.calculability = ParamCalculability.FREE;
     }
 
+    protected setExtraResultsFamilies() {
+        this._extraResultsFamilies = {
+            ZF2: ParamFamily.ELEVATIONS,
+            Q_GuideTech: ParamFamily.FLOWS
+        };
+    }
+
     /**
      * Equation from Cassan, L., Laurens, P., 2016. Design of emergent and submerged rock-ramp fish passes.
      * Knowledge & Management of Aquatic Ecosystems 45.
diff --git a/src/macrorugo/macrorugo_params.ts b/src/macrorugo/macrorugo_params.ts
index 4fbfc30dcbd30a9f09d8e86484890c15d482531d..016cee473a5d0a324c933a6a01db4d7db9b220db 100644
--- a/src/macrorugo/macrorugo_params.ts
+++ b/src/macrorugo/macrorugo_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
 
@@ -56,22 +56,22 @@ export class MacrorugoParams extends ParamsEquation {
                 rY: number, rRF: number, rCB: number, rPBD: number, rPBH: number, rCd0: number) {
         super();
 
-        this._ZF1 = new ParamDefinition(this, "ZF1", ParamDomainValue.POS, rZF1);
+        this._ZF1 = new ParamDefinition(this, "ZF1", ParamDomainValue.POS, rZF1, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this._ZF1);
 
-        this._L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL);
+        this._L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL, ParamFamily.LENGTHS);
         this.addParamDefinition(this._L);
 
-        this._B = new ParamDefinition(this, "B", ParamDomainValue.POS, rB);
+        this._B = new ParamDefinition(this, "B", ParamDomainValue.POS, rB, ParamFamily.WIDTHS);
         this.addParamDefinition(this._B);
 
-        this._If = new ParamDefinition(this, "If", ParamDomainValue.POS, rIf);
+        this._If = new ParamDefinition(this, "If", ParamDomainValue.POS, rIf, ParamFamily.SLOPES);
         this.addParamDefinition(this._If);
 
-        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ);
+        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ, ParamFamily.FLOWS);
         this.addParamDefinition(this._Q);
 
-        this._Y = new ParamDefinition(this, "Y", ParamDomainValue.POS, rY);
+        this._Y = new ParamDefinition(this, "Y", ParamDomainValue.POS, rY, ParamFamily.HEIGHTS);
         this.addParamDefinition(this._Y);
 
         this._Ks = new ParamDefinition(this, "Ks", ParamDomainValue.POS_NULL, rRF);
@@ -80,10 +80,10 @@ export class MacrorugoParams extends ParamsEquation {
         this._C = new ParamDefinition(this, "C", ParamDomainValue.POS, rCB);
         this.addParamDefinition(this._C);
 
-        this._PBD = new ParamDefinition(this, "PBD", ParamDomainValue.POS, rPBD);
+        this._PBD = new ParamDefinition(this, "PBD", ParamDomainValue.POS, rPBD, ParamFamily.DIAMETERS);
         this.addParamDefinition(this._PBD);
 
-        this._PBH = new ParamDefinition(this, "PBH", ParamDomainValue.POS, rPBH);
+        this._PBH = new ParamDefinition(this, "PBH", ParamDomainValue.POS, rPBH, ParamFamily.HEIGHTS);
         this.addParamDefinition(this._PBH);
 
         this._Cd0 = new ParamDefinition(this, "Cd0", ParamDomainValue.POS, rCd0);
diff --git a/src/nub.ts b/src/nub.ts
index cb4ba15fe6ed65dbaffd8c9bdf32f26bd95ad7ad..4fc141821d7e013ec1b78bcc30831d7eb82f9a6f 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -1,18 +1,17 @@
 import { ParamDefinition, Session } from ".";
 import { ComputeNode } from "./compute-node";
 import { Dichotomie } from "./dichotomie";
-import { INamedIterableValues, INumberIterator, IterableValues } from "./param/param-value-iterator";
+import { INamedIterableValues, IterableValues } from "./param/param-value-iterator";
 import { ParamValueMode } from "./param/param-value-mode";
-import { ParamValues } from "./param/param-values";
 import { Props } from "./props";
 import { Result } from "./util/result";
-import { IReferencedNub } from "./value_ref/object_ref";
+import { LinkedValue } from "./value_ref/object_ref";
 
 /**
  * Classe abstraite de Noeud de calcul dans une session :
  * classe de base pour tous les calculs
  */
-export abstract class Nub extends ComputeNode implements IReferencedNub {
+export abstract class Nub extends ComputeNode {
 
     /** paramétrage de la dichotomie */
     public dichoStartIntervalMaxSteps: number = 100;
@@ -77,6 +76,18 @@ export abstract class Nub extends ComputeNode implements IReferencedNub {
         return res;
     }
 
+    /**
+     * Returns the parameter set to CALC mode, if any
+     */
+    public getComputedParam(): ParamDefinition {
+        for (const p of this._prms) {
+            if (p.valueMode === ParamValueMode.CALCUL) {
+                return p;
+            }
+        }
+        return undefined;
+    }
+
     /**
      * effectue une série de calculs sur un paramètre
      * @param rInit solution approximative du paramètre
@@ -99,6 +110,7 @@ export abstract class Nub extends ComputeNode implements IReferencedNub {
                 }
             }
 
+            // checks which values are variating, if any
             switch (p.valueMode) {
                 case ParamValueMode.SINGLE:
                     break;
@@ -110,14 +122,23 @@ export abstract class Nub extends ComputeNode implements IReferencedNub {
 
                 case ParamValueMode.CALCUL:
                     // Le paramètre lié est un résultat de calcul
-                    if (p.isReferenceDefined && p.referencedResult.nbResultElements > 1) {
+                    // @TODO check this (check ultimate target param value mode ?)
+                    // @TODO WTF comment un mode CALCUL peut-il avoir une référence ??
+                    if (
+                        p.isReferenceDefined()
+                        && p.referencedValue.isResult()
+                        && (p.referencedValue.element as Result).nbResultElements > 1
+                    ) {
                         variatedValues = this.setVariatedValues(p, variatedValues);
                     }
                     break;
 
                 case ParamValueMode.LINK:
-                    const ro = p.referencedObject;
-                    if (ro !== undefined && ro.hasMultipleValues) {
+                    if (
+                        p.isReferenceDefined()
+                        && p.referencedValue.isResult()
+                        && (p.referencedValue.element as Result).nbResultElements > 1
+                    ) {
                         variatedValues = this.setVariatedValues(p, variatedValues);
                     }
                     break;
@@ -181,123 +202,96 @@ export abstract class Nub extends ComputeNode implements IReferencedNub {
         return p.v;
     }
 
-    // interface IReferencedNub
-
-    public getReferencedParamValues(desc: string): ParamValues {
-        const prm = this.getParameter(desc);
-        if (prm !== undefined) {
-            return prm.paramValues;
-        }
-        return undefined;
-    }
-
-    public getReferencedResult(desc?: string): Result {
-        if (desc === undefined || (this._result !== undefined && this._result.name === desc)) {
-            return this._result;
-        }
-
-        // il y a des valeurs par défaut pour la précision et la valeur initiale,
-        // mais il faudra prévoir un mécanisme pour les transmettre
-        return this.CalcSerie(0.1, desc);
-    }
-
-    public getReferencedExtraResult(desc: string): any {
-        const tmp: string[] = desc.split(".");
-        const r: Result = this.getReferencedResult(tmp[0]);
-        return r.getExtraResult(tmp[1]);
-    }
-
-    public getReferencedValuesIterator(desc: string): INumberIterator {
-        const ro = this.getReferencedObject(desc);
-        return ro.valuesIterator;
-    }
-
-    public getReferencedObject(desc: string): INamedIterableValues {
-        const tmp = desc.split(".");
-
-        if (tmp.length === 1) {
-            // paramètre (ex "Q")
-            return this.getParameter(desc);
-        }
+    /**
+     * Liste des valeurs (paramètre, résultat, résultat complémentaire) liables à un paramètre
+     * @param src paramètre auquel lier d'autres valeurs
+     * @param excludeResult true si on veut exclure des valeurs retournées le résultat/résultat complémentaire
+     *                      correspondant à la clé de recherche
+     */
+    public getLinkableValues(src: ParamDefinition): LinkedValue[] {
+        const res: LinkedValue[] = [];
+        const symbol = src.symbol;
+
+        // if parameter comes from the same Nub, no linking is possible at all;
+        // different Structures in the same parent are different Nubs so they
+        // can get linked to each other
+        if (src.nubUid !== this.uid) {
+
+            // 1. parameters
+            for (const p of this._prms) {
+                // if symbol and Nub type are identical, or if family is identical
+                if (
+                    (p.symbol === symbol && this.calcType === src.nubCalcType)
+                    || (p.family !== undefined && (p.family === src.family))
+                ) {
+                    // a calculated parameter cannot be a link target; instead, its future result
+                    // will be targeted (@see machanism in LinkedValue)
+                    if (p.valueMode === ParamValueMode.CALCUL) {
+                        // beware of circular dependencies !
+                        if (! this.resultDependsOnNub(src.nubUid)) {
+                            res.push(new LinkedValue(this, p, p.symbol));
+                        }
+                    } else {
+                        // beware of circular dependencies !
+                        if (p.valueMode !== ParamValueMode.LINK || ! p.dependsOnParameter(src)) {
+                            res.push(new LinkedValue(this, p, p.symbol));
+                        }
+                    }
+                }
+            }
 
-        if (tmp[1] === "") {
-            // résultat (ex "Q.")
-            if (this._result !== undefined) {
-                return this._result;
+            // 2. extra results
+            if (this._extraResultsFamilies) {
+                // beware of circular dependencies !
+                if (! this.resultDependsOnNub(src.nubUid)) {
+                    const erk = Object.keys(this._extraResultsFamilies);
+                    for (const erSymbol of erk) {
+                        const erFamily = this._extraResultsFamilies[erSymbol];
+                        // if family is identical
+                        if (erFamily === src.family) {
+                            res.push(new LinkedValue(this, undefined, erSymbol));
+                        }
+                    }
+                }
             }
         }
 
-        // les autres objets référençables n'implémentant pas IJalhydObject...
-        return undefined;
+        return res;
     }
 
     /**
-     * liste des valeurs (paramètre, résultat, résultat complémentaire) liables à un paramètre
-     * @param src objet qui sert de clé de recherche des paramètres liables, de type INamedObject | string
-     * @param excludeResult true si on veut exclure des valeurs retournées le résultat/résultat complémentaire
-     *                      correspondant à la clé de recherche
-     * @returns tableau d'objets de la forme { "name":string, "value":INamedIterableValues, "nub":Nub},
-     *   nub=Nub d'origine de la "value"
-     *
-     *   l'étiquette "name" (cf. INubReference.defineReference) est de la forme <n | ouvrage[n] | N1>[.[N2]]
-     *     n : indice de de l'ouvrage dans le cas des ouvrages parallèles
-     *     N1 : un nom de paramètre/résultat (dans le cas d'un résultat, il est suivi d'un point)
-     *     N2 : nom de résultat complémentaire (optionnel)
-     *     ex :
-     *       Q, Z1 (paramètres)
-     *       J. (résultat)
-     *       .Yf (résultat complémentaire du résultat courant)
-     *       Q.Yf (résultat complémentaire du résultat nommé "Q")
-     *       0.Q : paramètre Q du 1er ouvrage (ouvrages parallèles)
-     *       ouvrage[1].Q_Mode : résultat complémentaire du 2ème ouvrage (ouvrages parallèles)
+     * Returns true if the computation of the current Nub requires, directly
+     * or not, anything (parameter or result) from the given Nub UID "uid"
+     * (to prevent circular linking)
+     * @param uid
      */
-    public getLinkableValues(src: any, prefix?: string, excludeResult: boolean = false): any[] {
-        const res: any[] = [];
-
-        const isStr = typeof (src) === "string";
-        const name = isStr ? src : src.name;
-        const hasUid = isStr ? false : "uid" in src;
-
-        // paramètres
+    public resultDependsOnNub(uid: string): boolean {
+        // does any of our parameters depend on the target Nub ?
         for (const p of this._prms) {
-            // pour éviter d'ajouter le paramètre d'entrée dans le tableau résultat
-            const cond = hasUid ? p.uid !== src.uid : true;
-            if (cond) {
-                switch (p.valueMode) {
-                    case ParamValueMode.SINGLE:
-                    case ParamValueMode.MINMAX:
-                    case ParamValueMode.LISTE:
-                        switch (name) {
-                            case "Z1":
-                            case "Z2":
-                                if (p.symbol === "Z1" || p.symbol === "Z2") {
-                                    res.push({ name: this.addPrefix(p.symbol, prefix), value: p, nub: this });
-                                }
-                                break;
-
-                            default:
-                                if (p.symbol === name) {
-                                    res.push({ name: this.addPrefix(p.symbol, prefix), value: p, nub: this });
-                                }
-                        }
+            if (p.valueMode === ParamValueMode.LINK) {
+                if (p.dependsOnNub(uid)) {
+                    return true;
                 }
             }
         }
+        return false;
+    }
 
-        // résultat
-        if (this._result !== undefined && !excludeResult) {
-            if (this._result.name === name) {
-                res.push({ name: this.addPrefix(`${name}.`, prefix), value: this._result, nub: this });
-            }
-
-            // résultats complémentaires
-            const erIter = this._result.getIterableExtraResults(name);
-            if (erIter !== undefined) {
-                res.push({ name: this.addPrefix(`${this._result.name}.${name}`, prefix), value: erIter, nub: this });
+    /**
+     * Returns true if the computation of the current Nub has multiple values
+     * (whether it is already computed or not), by detecting if any parameter,
+     * linked or not, is variated
+     */
+    public resultHasMultipleValues(): boolean {
+        for (const p of this._prms) {
+            if (p.valueMode === ParamValueMode.MINMAX || p.valueMode === ParamValueMode.LISTE) {
+                return true;
+            } else if (p.valueMode === ParamValueMode.LINK) {
+                // indirect recursivity
+                return p.referencedValue.hasMultipleValues();
             }
         }
-
-        return res;
+        return false;
     }
 
     /**
@@ -413,10 +407,9 @@ export abstract class Nub extends ComputeNode implements IReferencedNub {
         return dicho.Dichotomie(target.v, rPrec, rInit);
     }
 
-    private addPrefix(str: string, prefix: string) {
-        return prefix === undefined ? str : `${prefix}${str}`;
-    }
-
+    /**
+     * Sets the variated values and warns if there were already some
+     */
     private setVariatedValues(newValues: INamedIterableValues, oldValues: IterableValues) {
         if (oldValues === undefined) {
             return newValues;
diff --git a/src/pab/pab_dimension.ts b/src/pab/pab_dimension.ts
index 40631cceebeb70cd92899d58d055d556b6eb9862..355f806a57e944256353b2e02c78f16f924c6eb2 100644
--- a/src/pab/pab_dimension.ts
+++ b/src/pab/pab_dimension.ts
@@ -1,5 +1,5 @@
 import { Nub } from "../nub";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
 import { Result } from "../util/result";
@@ -21,10 +21,10 @@ export class PabDimensionParams extends ParamsEquation {
 
     constructor(rL: number, rW: number, rY: number, rV?: number) {
         super();
-        this._L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL);
-        this._W = new ParamDefinition(this, "W", ParamDomainValue.POS, rW);
-        this._Y = new ParamDefinition(this, "Y", ParamDomainValue.POS, rY);
-        this._V = new ParamDefinition(this, "V", ParamDomainValue.POS, rV);
+        this._L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL, ParamFamily.LENGTHS);
+        this._W = new ParamDefinition(this, "W", ParamDomainValue.POS, rW, ParamFamily.WIDTHS);
+        this._Y = new ParamDefinition(this, "Y", ParamDomainValue.POS, rY, ParamFamily.HEIGHTS);
+        this._V = new ParamDefinition(this, "V", ParamDomainValue.POS, rV, ParamFamily.VOLUMES);
 
         this.addParamDefinition(this._L);
         this.addParamDefinition(this._W);
diff --git a/src/pab/pab_puissance.ts b/src/pab/pab_puissance.ts
index 5a397b63625f88c3085f3ab69fe5c03fafd914bc..e02dbc953cf1558d961cd98c99f9719cad3363bb 100644
--- a/src/pab/pab_puissance.ts
+++ b/src/pab/pab_puissance.ts
@@ -1,5 +1,5 @@
 import { Nub } from "../nub";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
 import { Result } from "../util/result";
@@ -21,9 +21,9 @@ export class PabPuissanceParams extends ParamsEquation {
 
     constructor(rDH: number, rQ: number, rV: number, rPV?: number) {
         super();
-        this._DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, rDH);
-        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ);
-        this._V = new ParamDefinition(this, "V", ParamDomainValue.POS, rV);
+        this._DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, rDH, ParamFamily.HEIGHTS);
+        this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ, ParamFamily.FLOWS);
+        this._V = new ParamDefinition(this, "V", ParamDomainValue.POS, rV, ParamFamily.VOLUMES);
         this._PV = new ParamDefinition(this, "PV", ParamDomainValue.POS, rPV);
 
         this.addParamDefinition(this._DH);
diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts
index ea4fdb8ea49b394988d97f31bfca518263921d6b..5c86b0dbbf906fd2bf7ae90ab5f29d6b26ba67ae 100644
--- a/src/param/param-definition.ts
+++ b/src/param/param-definition.ts
@@ -1,10 +1,9 @@
+import { CalculatorType } from "../compute-node";
+import { Nub } from "../nub";
 import { Interval } from "../util/interval";
 import { Message, MessageCode } from "../util/message";
-
-import { IJalhydObject, JalhydObject } from "../jalhyd_object";
 import { IObservable, Observable, Observer } from "../util/observer";
-import { Result } from "../util/result";
-import { INubReference, IReferencedNub } from "../value_ref/object_ref";
+import { LinkedValue } from "../value_ref/object_ref";
 import { ParamDomain, ParamDomainValue } from "./param-domain";
 import { INamedIterableValues, INumberIterator } from "./param-value-iterator";
 import { ParamValueMode } from "./param-value-mode";
@@ -26,9 +25,25 @@ export enum ParamCalculability {
 }
 
 /**
- * Paramètre avec symbole, domaine de définition, calculabilité
+ * Parameter family: defines linkability with other parameters/results
+ */
+export enum ParamFamily {
+    LENGTHS, // longueur
+    WIDTHS, // largeur
+    SLOPES, // pente
+    HEIGHTS, // profondeur, tirant d'eau, chute
+    ELEVATIONS, // cote
+    VOLUMES,
+    FLOWS, // débit
+    DIAMETERS,
+    // SPEEDS // vitesses, seulement des résultats
+}
+
+/**
+ * Paramètre avec symbole, famille, domaine de définition, calculabilité,
+ * pointant éventuellement vers un autre paramètre / résultat
  */
-export class ParamDefinition implements INubReference, INamedIterableValues, IObservable {
+export class ParamDefinition implements INamedIterableValues, IObservable {
 
     /** le paramètre doit-il être exposé (par ex: affiché par l'interface graphique) ? */
     public visible: boolean = true;
@@ -36,7 +51,8 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     /** symbole */
     private _symbol: string;
 
-    private _parent: ParamsEquation | JalhydObject;
+    /** related parameters groups; indirectly gives access to the Nub using this parameter */
+    private _parent: ParamsEquation;
 
     /** domaine de définition */
     private _domain: ParamDomain;
@@ -47,17 +63,24 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     /** valeur(s) prise(s) */
     private _paramValues: ParamValues;
 
+    /** parameters family, for linking */
+    private _family: ParamFamily;
+
+    /** pointer to another Parameter / Result, in case of LINK mode */
+    private _referencedValue: LinkedValue;
+
     /** implémentation par délégation de IObservable */
     private _observable: Observable;
 
-    constructor(parent: ParamsEquation | JalhydObject, symb: string, d: ParamDomain | ParamDomainValue,
-                val?: number, visible: boolean = true) {
+    constructor(parent: ParamsEquation, symb: string, d: ParamDomain | ParamDomainValue,
+                val?: number, family?: ParamFamily, visible: boolean = true) {
         this._parent = parent;
         this._symbol = symb;
         this._observable = new Observable();
         this._paramValues = new ParamValues();
         this._paramValues.setSingleValue(val);
         this._calc = ParamCalculability.FREE;
+        this._family = family;
         this.visible = visible;
 
         if (d instanceof ParamDomain) {
@@ -72,7 +95,7 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     /**
      * set parent a-posteriori; used by nghyd when populating forms
      */
-    set parent(parent: ParamsEquation | JalhydObject) {
+    set parent(parent: ParamsEquation) {
         this._parent = parent;
     }
 
@@ -82,23 +105,44 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
      * ex: 123_Q
      */
     get uid(): string {
+        return this.nubUid + "_" + this._symbol;
+    }
+
+    /**
+     * Identifiant unique du Nub parent
+     */
+    get nubUid(): string {
         let parentUid: string = null;
-        if (this._parent instanceof JalhydObject) {
-            parentUid = String(this._parent.uid);
-        } else if (this._parent instanceof ParamsEquation) {
+        if (this._parent) {
             // uid du ComputeNode utilisant le ParamsEquation
             parentUid = String(this._parent.nubUid);
         } else {
-            throw new Error("ParamDefinition.uid : parameter has no parent !");
+            throw new Error("ParamDefinition.nubUid : parameter has no parent !");
+        }
+        return parentUid;
+    }
+
+    /**
+     * Type de modult du Nub parent
+     */
+    get nubCalcType(): CalculatorType {
+        let parentCalcType: CalculatorType;
+        if (this._parent) {
+            // uid du ComputeNode utilisant le ParamsEquation
+            if (this._parent.parent instanceof Nub) {
+                parentCalcType = this._parent.parent.calcType;
+            }
+        } else {
+            throw new Error("ParamDefinition.nubCalcType : parameter has no parent !");
         }
-        return parentUid + "_" + this._symbol;
+        return parentCalcType;
     }
 
     get symbol(): string {
         return this._symbol;
     }
 
-    public getDomain(): ParamDomain {
+    public get domain(): ParamDomain {
         return this._domain;
     }
 
@@ -106,16 +150,27 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
         return this._domain.interval;
     }
 
+    /**
+     * Current values set associated to this parameter; might
+     * be a targetted set of values, if parameter is in LINK mode
+     */
     public get paramValues(): ParamValues {
-        if (this.isReferenceDefined) {
-            return this.referencedParamValues;
+        if (this._referencedValue) {
+            return this._referencedValue.getParamValues();
         }
         return this._paramValues;
     }
 
+    public get referencedValue() {
+        return this._referencedValue;
+    }
+
+    public get family() {
+        return this._family;
+    }
+
     get calculability(): ParamCalculability {
         if (this._calc === undefined) {
-            //   throw "value of parameter '" + this._symbol + "' calculability is not defined";
             const e = new Message(MessageCode.ERROR_PARAMDEF_CALC_UNDEFINED);
             e.extraVar.symbol = this.symbol;
             throw e;
@@ -128,34 +183,17 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
         this._calc = c;
     }
 
-    /** returns value or referenced value */
+    /**
+     * Proxy to getValue()
+     */
     get v(): number {
-        if (this.isReferenceDefined) {
-            const ro = this.referencedObject;
-
-            if (ro instanceof ParamDefinition) {
-                switch (this.referencedParamValues.valueMode) {
-                    case ParamValueMode.CALCUL:
-                        const r = this.referencedResult;
-                        if (r.nbResultElements === 1) {
-                            return r.resultElement.vCalc;
-                        }
-                        throw new Error(`il n'y a pas exactement un ResultElement dans le Result "${r.name}"`);
-
-                    default:
-                        return this.referencedParamValues.currentValue;
-                }
-            } else if (ro instanceof Result) {
-                return ro.currentValue;
-            }
-
-            return this.referencedExtraResult;
-        }
-
         return this.getValue();
     }
 
-    /** set value, with calculability control */
+    /**
+     * set value, with calculability control
+     * @TODO move calculability control to setValue() ?
+     */
     set v(val: number) {
         if (this.calculability === ParamCalculability.NONE) {
             const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_FIXED);
@@ -168,33 +206,55 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     /**
      * gestion de la valeur
      */
-
     public get isDefined(): boolean {
-        return this._paramValues.isDefined;
+        return this.paramValues.isDefined;
     }
 
     public getValue(): number {
-        if (!this._paramValues.isDefined) {
-            const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED);
-            e.extraVar.symbol = this.symbol;
-            throw e;
+        if (this.isReferenceDefined()) {
+            // transparent proxy to linked value
+            try {
+                /* console.log("---> get value reference proxy for", this.symbol, this.nubCalcType,
+                    this.referencedValue.symbol,
+                    this.referencedValue.element ? this.referencedValue.element.constructor.name : "walou"); */
+                return this.referencedValue.getValue();
+            } catch (e) {
+                // target value is not yet defined (generally because target is an extra result)
+                return undefined;
+            }
+        } else {
+            // current value from own values set
+            if (! this._paramValues.isDefined) {
+                const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED);
+                e.extraVar.symbol = this.symbol;
+                throw e;
+            }
+            return this._paramValues.currentValue;
         }
-
-        return this._paramValues.currentValue;
     }
 
+    // for INumberiterator interface
     public get currentValue(): number {
         return this.getValue();
     }
 
+    /**
+     * Sets the current value of the parameter's own values set;
+     * should never be called when in LINK mode
+     * @param val
+     * @param sender
+     */
     public setValue(val: number, sender?: any) {
+        if (this.valueMode === ParamValueMode.LINK) {
+            console.error("!! trying to set current value in LINK mode");
+        }
         this.checkValue(val);
         this._paramValues.currentValue = val;
         this.notifyValueModified(sender);
     }
 
     public get uncheckedValue(): number {
-        return this._paramValues.uncheckedValue;
+        return this.paramValues.uncheckedValue;
     }
 
     public checkValue(v: number) {
@@ -252,15 +312,15 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     }
 
     public checkMin(min: number): boolean {
-        return this.isMinMaxDomainValid(min) && (min < this._paramValues.max);
+        return this.isMinMaxDomainValid(min) && (min < this.paramValues.max);
     }
 
     public checkMax(max: number): boolean {
-        return this.isMinMaxDomainValid(max) && (this._paramValues.min < max);
+        return this.isMinMaxDomainValid(max) && (this.paramValues.min < max);
     }
 
     public checkStep(step: number): boolean {
-        return this.isMinMaxValid && this._paramValues.stepRefValue.intervalHasValue(step);
+        return this.isMinMaxValid && this.paramValues.stepRefValue.intervalHasValue(step);
     }
 
     get isValueValid(): boolean {
@@ -274,24 +334,24 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     }
 
     get isMinMaxValid(): boolean {
-        return this.checkMinMax(this._paramValues.min, this._paramValues.max);
+        return this.checkMinMax(this.paramValues.min, this.paramValues.max);
     }
 
     public get isRangeValid(): boolean {
-        switch (this._paramValues.valueMode) {
+        switch (this.valueMode) {
             case ParamValueMode.LISTE:
                 return this.isListValid;
 
             case ParamValueMode.MINMAX:
-                return this.checkStep(this._paramValues.step);
+                return this.checkStep(this.paramValues.step);
         }
 
         // tslint:disable-next-line:max-line-length
-        throw new Error(`"ParamDefinition.isRangeValid() : valeur ${ParamValueMode[this._paramValues.valueMode]} de ParamValueMode non prise en compte`);
+        throw new Error(`"ParamDefinition.isRangeValid() : valeur ${ParamValueMode[this.valueMode]} de ParamValueMode non prise en compte`);
     }
 
     public get isValid() {
-        switch (this._paramValues.valueMode) {
+        switch (this.valueMode) {
             case ParamValueMode.SINGLE:
                 return this.isValueValid;
 
@@ -303,10 +363,9 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
                 return true;
 
             case ParamValueMode.LINK:
-                if (!this.isReferenceDefined) {
+                if (! this._referencedValue) {
                     return false;
                 }
-
                 try {
                     for (const v of this.valuesIterator) {
                         this.checkValue(v);
@@ -319,7 +378,7 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
 
         throw new Error(
             // tslint:disable-next-line:max-line-length
-            `ParamDefinition.isValid() : valeur de ParamValueMode '${ParamValueMode[this._paramValues.valueMode]}' non prise en charge`
+            `ParamDefinition.isValid() : valeur de ParamValueMode '${ParamValueMode[this.valueMode]}' non prise en charge`
         );
     }
 
@@ -331,6 +390,73 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
         this._paramValues.valueMode = m;
     }
 
+    /**
+     * If parameter mode is LINK, returns the value mode of the ultimately
+     * targetted parameter, else returns its own value mode; if targetted
+     * value is a result, returns undefined
+     */
+    /* public get finalValueMode(): ParamValueMode {
+        if (this.valueMode === ParamValueMode.LINK && this.isReferenceDefined()) {
+            if (this._referencedValue.isParameter()) {
+                return (this._referencedValue.value as ParamDefinition).finalValueMode;
+            } else {
+                return undefined;
+            }
+        } else {
+            return this.valueMode;
+        }
+    } */
+
+    /**
+     * Sets the current parameter to LINK mode, pointing to the given
+     * symbol (might be a Parameter (computed or not) or an ExtraResult)
+     * of the given Nub
+     *
+     * Prefer @see defineReferenceFromLinkedValue() whenever possible
+     *
+     * @param nub
+     * @param symbol
+     */
+    public defineReference(nub: Nub, symbol: string) {
+        // clear current reference
+        this.undefineReference();
+        // find what the symbol points to
+        if (nub) {
+            // 1. extra result ?
+            // - start here to avoid extra results being presented as
+            // parameters by the iterator internally used by nub.getParameter()
+            // - extra results with no family are not linkable
+            if (Object.keys(nub.extraResultsFamilies).includes(symbol)) {
+                this._referencedValue = new LinkedValue(nub, undefined, symbol);
+            } else {
+                // 2. is it a parameter (possibly in CALC mode) ?
+                const p = nub.getParameter(symbol);
+                if (p) {
+                    this._referencedValue = new LinkedValue(nub, p, symbol);
+                }
+            }
+        }
+        if (this._referencedValue) {
+            // set value mode
+            this.valueMode = ParamValueMode.LINK;
+        } else {
+            throw new Error(`defineReference - could not find target for ${nub.uid}.${symbol}`);
+        }
+    }
+
+    public defineReferenceFromLinkedValue(target: LinkedValue) {
+        this._referencedValue = target;
+        this.valueMode = ParamValueMode.LINK;
+    }
+
+    public undefineReference() {
+        this._referencedValue = undefined;
+    }
+
+    public isReferenceDefined(): boolean {
+        return (this._referencedValue !== undefined);
+    }
+
     /**
      * Returns an object representation of the Parameter's current state
      */
@@ -357,78 +483,90 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
                 break;
 
             case ParamValueMode.LINK:
-                paramRep.targetNub = (this.referencedNub as any).uid;
-                paramRep.targetParam = this.referenceDefinition;
+                paramRep.targetNub = this._referencedValue.nub.uid;
+                paramRep.targetParam = this._referencedValue.symbol;
                 break;
         }
         return paramRep;
     }
 
-    // interface INubReference
-
-    public defineReference(target: IReferencedNub, desc: string) {
-        const oldDef = this._paramValues.referenceDefinition;
-        const oldTarget = this._paramValues.referencedNub;
-        try {
-            this._paramValues.defineReference(target, desc);
-            this.checkReferenceCircularity(this, []);
-        } catch (e) {
-            this._paramValues.defineReference(oldTarget, oldDef);
-            throw e;
+    /**
+     * Returns true if the current parameter is linked, directly or not,
+     * to the given parameter "p" (to prevent circular linking)
+     * @param p
+     */
+    public dependsOnParameter(p: ParamDefinition): boolean {
+        let linked = false;
+        if (this.valueMode === ParamValueMode.LINK && this.isReferenceDefined()) {
+            const ref = this._referencedValue;
+            // direct reference ?
+            if (ref.nub.uid === p.nubUid && ref.symbol === p.symbol) {
+                linked = true;
+            } else { // indirect reference ?
+                if (ref.isParameter()) {
+                    // recursive call to linked parameter
+                    linked = (ref.element as ParamDefinition).dependsOnParameter(p);
+                } else if (ref.isResult() || ref.isExtraResult()) {
+                    // must not be linked to a result of the candidate parameter's Nub
+                    linked = (ref.nub.uid === p.nubUid);
+                }
+            }
         }
+        return linked;
     }
 
-    public undefineReference() {
-        this._paramValues.undefineReference();
-    }
-
-    get referenceDefinition(): string {
-        return this._paramValues.referenceDefinition;
-    }
-
-    get referencedNub(): IReferencedNub {
-        return this._paramValues.referencedNub;
-    }
-
-    get isReferenceDefined(): boolean {
-        return this._paramValues.isReferenceDefined;
-    }
-
-    get referencedParamValues(): ParamValues {
-        return this._paramValues.referencedParamValues;
-    }
-
-    get referencedResult(): Result {
-        return this._paramValues.referencedResult;
-    }
-
-    get referencedExtraResult(): any {
-        return this._paramValues.referencedExtraResult;
+    /**
+     * Returns true if the current parameter is linked, directly or not,
+     * to the Nub having UID "uid" (to prevent circular linking)
+     * @param uid
+     */
+    public dependsOnNub(uid: string): boolean {
+        let linked = false;
+        if (this.valueMode === ParamValueMode.LINK && this.isReferenceDefined()) {
+            const ref = this._referencedValue;
+            // direct reference ?
+            if (ref.nub.uid === uid) {
+                linked = true;
+            } else { // indirect reference ?
+                if (ref.isParameter()) {
+                    // recursive call to linked parameter
+                    linked = (ref.element as ParamDefinition).dependsOnNub(uid);
+                }
+            }
+        }
+        return linked;
     }
 
-    get referencedValuesIterator(): INumberIterator {
-        return this._paramValues.referencedValuesIterator;
-    }
+    // interface INamedIterableValues
 
-    get referencedObject(): INamedIterableValues {
-        return this._paramValues.referencedObject;
+    get name(): string {
+        return this._symbol;
     }
 
-    // interface INamedIterableValues
-
+    /**
+     * Transparent proxy to own values iterator or targetted values iterator (in LINK mode)
+     */
     public get valuesIterator(): INumberIterator {
-        if (this.isReferenceDefined) {
-            return this.referencedValuesIterator;
+        if (this._referencedValue) {
+            return this._referencedValue.getParamValues().valuesIterator;
         }
         return this._paramValues.valuesIterator;
     }
 
+    /**
+     * Returns true if there are more than 1 value associated to this parameter;
+     * might be its own values (MINMAX / LISTE mode), or targetted values (LINK mode)
+     */
     public get hasMultipleValues(): boolean {
-        return this._paramValues.hasMultipleValues;
-    }
-
-    public get name(): string {
-        return this._symbol;
+        if (this._referencedValue) {
+            return this._referencedValue.hasMultipleValues();
+        } else {
+            if (this.valueMode === ParamValueMode.CALCUL) {
+                return (this._parent.parent as Nub).resultHasMultipleValues();
+            } else {
+                return this._paramValues.hasMultipleValues;
+            }
+        }
     }
 
     public initValuesIterator(reverse: boolean = false): INumberIterator {
@@ -479,7 +617,7 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
 
     public clone(): ParamDefinition {
         const res = new ParamDefinition(this._parent, this._symbol,
-            this.getDomain().clone(), this.uncheckedValue, this.visible);
+            this.domain.clone(), this.uncheckedValue, this._family, this.visible);
         res._calc = this._calc;
         return res;
     }
@@ -500,15 +638,13 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
         if (v === undefined) {
             return false;
         }
-
-        if (this._paramValues.valueMode === ParamValueMode.MINMAX) {
+        if (this.valueMode === ParamValueMode.MINMAX) {
             try {
                 this.checkValue(v);
             } catch (e) {
                 return false;
             }
         }
-
         return true;
     }
 
@@ -517,11 +653,11 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
     }
 
     private get isListValid(): boolean {
-        if (this._paramValues.valueList === undefined) {
+        if (this.paramValues.valueList === undefined) {
             return false;
         }
 
-        for (const v of this._paramValues.valueList) {
+        for (const v of this.paramValues.valueList) {
             try {
                 this.checkValue(v);
             } catch (e) {
@@ -531,27 +667,4 @@ export class ParamDefinition implements INubReference, INamedIterableValues, IOb
         return true;
     }
 
-    /**
-     * vérifie l'absence de référence circulaire
-     * @param seenUids liste des uids déjà vérifiés
-     * @param o objet à tester (son uid est il déjà dans la liste ?)
-     */
-    private checkReferenceCircularity(o: any, seenUids: string[]) {
-        if ("uid" in o) {
-            if (seenUids.indexOf(o.uid) !== -1) {
-                throw new Error(`références circulaires détectées (uids : ${seenUids})`);
-            }
-
-            seenUids.push(o.uid);
-
-            if ("referencedObject" in o) {
-                const curr = o as INubReference;
-                const next = curr.referencedObject;
-                if (next !== undefined) {
-                    this.checkReferenceCircularity(next as IJalhydObject, seenUids);
-                }
-            }
-        }
-    }
-
 }
diff --git a/src/param/param-value-iterator.ts b/src/param/param-value-iterator.ts
index 9b233c5291ad625575f9d9ac8da9ab5c723dd533..7e245be877d29eca174038bafdf7f57fc65be815 100644
--- a/src/param/param-value-iterator.ts
+++ b/src/param/param-value-iterator.ts
@@ -1,4 +1,4 @@
-import { INamedObject } from "../jalhyd_object";
+import { INamedObject, IObjectWithFamily } from "../jalhyd_object";
 import { ArrayReverseIterator } from "../util/iterator";
 import { ParamValueMode } from "./param-value-mode";
 import { ParamValues } from "./param-values";
@@ -47,7 +47,7 @@ export interface IterableValues extends INumberIterator {
 /**
  * objets pouvant avoir un nom et un itérateur sur une série de valeurs numériques
  */
-export interface INamedIterableValues extends INamedObject, IterableValues {
+export interface INamedIterableValues extends INamedObject, IObjectWithFamily, IterableValues {
 }
 
 /**
diff --git a/src/param/param-values.ts b/src/param/param-values.ts
index 733d86553f085e48f9c22fefe9e28787e07431c0..e1c97a0e6b94c2956f5c7e5424e834843629f4c3 100644
--- a/src/param/param-values.ts
+++ b/src/param/param-values.ts
@@ -1,14 +1,13 @@
-import { Interval, Result } from "..";
-import { INubReference, IReferencedNub, NubReference } from "../value_ref/object_ref";
-import { INamedIterableValues, INumberIterator, IterableValues, ParamValueIterator } from "./param-value-iterator";
+import { Interval } from "..";
+import { INumberIterator, IterableValues, ParamValueIterator } from "./param-value-iterator";
 import { ParamValueMode } from "./param-value-mode";
 
-export class ParamValues implements INubReference, IterableValues {
-
-    /**
-     * implémentation par délégation de INubReference
-     */
-    public _nubRef: NubReference;
+/**
+ * Represents the value(s) taken by a Parameter, along with and depending on
+ * the value mode; linked values are not managed here, only the LINK value
+ * mode is defined here
+ */
+export class ParamValues implements IterableValues {
 
     /**
      * mode de génération des valeurs : min/max, liste, ...
@@ -50,10 +49,6 @@ export class ParamValues implements INubReference, IterableValues {
      */
     private _iterator: INumberIterator;
 
-    constructor() {
-        this._nubRef = new NubReference();
-    }
-
     public setValues(o: number | any, max?: number, step?: number) {
         if (typeof (o) === "number") {
             if (max === undefined) {
@@ -126,9 +121,6 @@ export class ParamValues implements INubReference, IterableValues {
      * valeur courante
      */
     public get currentValue(): number {
-        if (this.isReferenceDefined) {
-            return this._nubRef.referencedObject.currentValue;
-        }
         return this._currentValue;
     }
 
@@ -140,9 +132,6 @@ export class ParamValues implements INubReference, IterableValues {
      * valeur dans le mode SINGLE
      */
     public get singleValue(): number {
-        if (this.isReferenceDefined) {
-            return this._nubRef.referencedParamValues.singleValue;
-        }
         return this._singleValue;
     }
 
@@ -165,9 +154,6 @@ export class ParamValues implements INubReference, IterableValues {
             case ParamValueMode.MINMAX:
                 return this._minValue;
 
-            case ParamValueMode.LINK:
-                return this._nubRef.referencedParamValues.min;
-
             default:
                 this.checkValueMode(ParamValueMode.MINMAX); // pour générer une erreur
                 return undefined; // pour le compilo
@@ -184,9 +170,6 @@ export class ParamValues implements INubReference, IterableValues {
             case ParamValueMode.MINMAX:
                 return this._maxValue;
 
-            case ParamValueMode.LINK:
-                return this._nubRef.referencedParamValues.max;
-
             default:
                 this.checkValueMode(ParamValueMode.MINMAX);
                 return undefined; // pour le compilo
@@ -208,9 +191,6 @@ export class ParamValues implements INubReference, IterableValues {
             case ParamValueMode.MINMAX:
                 return this._stepValue;
 
-            case ParamValueMode.LINK:
-                return this._nubRef.referencedParamValues.step;
-
             default:
                 this.checkValueMode(ParamValueMode.MINMAX); // pour générer une erreur
                 return undefined; // pour le compilo
@@ -240,52 +220,6 @@ export class ParamValues implements INubReference, IterableValues {
         return new ParamValueIterator(this, reverse);
     }
 
-    // interface INubReference
-
-    public defineReference(target: IReferencedNub, desc: string) {
-        this.valueMode = ParamValueMode.LINK;
-        this._nubRef.defineReference(target, desc);
-    }
-
-    public undefineReference() {
-        this._nubRef.undefineReference();
-    }
-
-    public get referencedNub(): IReferencedNub {
-        return this._nubRef.referencedNub;
-    }
-
-    public get referenceDefinition(): string {
-        return this._nubRef.referenceDefinition;
-    }
-
-    public get isReferenceDefined(): boolean {
-        return this._valueMode === ParamValueMode.LINK && this._nubRef.isReferenceDefined;
-    }
-
-    public get referencedParamValues(): ParamValues {
-        return this._nubRef.referencedParamValues;
-    }
-
-    public get referencedResult(): Result {
-        return this._nubRef.referencedResult;
-    }
-
-    public get referencedExtraResult(): any {
-        return this._nubRef.referencedExtraResult;
-    }
-
-    public get referencedValuesIterator(): any {
-        return this._nubRef.referencedValuesIterator;
-    }
-
-    public get referencedObject(): INamedIterableValues {
-        if (this.isReferenceDefined) {
-            return this._nubRef.referencedObject;
-        }
-        return undefined;
-    }
-
     // interface IterableValues
 
     public get valuesIterator(): INumberIterator {
@@ -293,28 +227,19 @@ export class ParamValues implements INubReference, IterableValues {
     }
 
     public get hasMultipleValues(): boolean {
-        let it;
-        if (this.isReferenceDefined) {
-            it = this.referencedValuesIterator;
-        } else {
-            // dans certains cas (mode LINK mais aucune valeur liable compatible), on ne peut avoir d'itérateur
-            if (this._valueMode !== ParamValueMode.LINK) {
-                it = this.getValuesIterator();
+        const it = this.getValuesIterator();
+        if (it) {
+            let n = 0;
+            for (const v of it) {
+                n++;
+                if (n > 1) {
+                    break;
+                }
             }
-        }
-
-        if (it === undefined) {
+            return n > 1;
+        } else {
             return false;
         }
-
-        let n = 0;
-        for (const v of it) {
-            n++;
-            if (n > 1) {
-                break;
-            }
-        }
-        return n > 1;
     }
 
     public initValuesIterator(reverse: boolean = false): INumberIterator {
@@ -324,10 +249,6 @@ export class ParamValues implements INubReference, IterableValues {
                 this._iterator = this.getValuesIterator(reverse);
                 break;
 
-            case ParamValueMode.LINK:
-                this._iterator = this.referencedObject.initValuesIterator(reverse);
-                break;
-
             default:
                 throw new Error(`ParamValues : mode de valeurs ${ParamValueMode[this._valueMode]} incorrect`);
         }
@@ -348,13 +269,9 @@ export class ParamValues implements INubReference, IterableValues {
      */
     public next(): IteratorResult<number> {
         let res;
-        if (this.isReferenceDefined) {
-            res = this.referencedObject.next();
-        } else {
-            res = this._iterator.next();
-            if (!res.done) {
-                this._currentValue = res.value;
-            }
+        res = this._iterator.next();
+        if (!res.done) {
+            this._currentValue = res.value;
         }
         return res;
     }
diff --git a/src/param/params-equation.ts b/src/param/params-equation.ts
index d25392d64a84906b97cf766d44d0a3841de33119..ce3218aeca676abbfc62df551dea5fce7d98ff0d 100644
--- a/src/param/params-equation.ts
+++ b/src/param/params-equation.ts
@@ -1,7 +1,6 @@
-import { MapIterator } from "../util/iterator";
-
 import { ComputeNode } from "../compute-node";
-import { ParamCalculability, ParamDefinition } from "./param-definition";
+import { MapIterator } from "../util/iterator";
+import { ParamDefinition } from "./param-definition";
 import { ParamDomainValue } from "./param-domain";
 
 export interface IParamDefinitionIterator extends IterableIterator<ParamDefinition> {
@@ -89,7 +88,10 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> {
     /** précision de calcul par défaut */
     private static DEFAULT_COMPUTE_PREC = 0.0001;
 
-    /** pointeur vers la calculette qui utilise ces paramètres */
+    /**
+     * Pointeur vers la calculette qui utilise ces paramètres; défini dans le constructeur
+     * du Nub en général, au moment où il reçoit les ParamsEquation
+     */
     public parent: ComputeNode;
 
     protected _paramMap: { [key: string]: ParamDefinition } = {};
diff --git a/src/remous.ts b/src/remous.ts
index 2432df05d7b411f5f1ede8c87865d2a273fd2f22..ffe33c4c55f8a2c62d9529c111f2031231ba56a6 100644
--- a/src/remous.ts
+++ b/src/remous.ts
@@ -2,7 +2,7 @@ import { ParamValues } from ".";
 import { round, XOR } from "./base";
 import { Dichotomie } from "./dichotomie";
 import { Nub } from "./nub";
-import { ParamCalculability, ParamDefinition } from "./param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "./param/param-definition";
 import { ParamDomainValue } from "./param/param-domain";
 import { ParamsEquation } from "./param/params-equation";
 import { acSection, ParamsSection } from "./section/section_type";
@@ -51,16 +51,22 @@ export class CourbeRemousParams extends ParamsEquation {
     constructor(s: acSection, rYamont: number, rYAval: number, rLong: number, rDx: number) {
         super();
         this._section = s;
-        this._Yamont = new ParamDefinition(this, "Yamont", ParamDomainValue.POS, rYamont);
-        this._Yaval = new ParamDefinition(this, "Yaval", ParamDomainValue.POS, rYAval);
-        this._Long = new ParamDefinition(this, "Long", ParamDomainValue.POS, rLong);
+        this._Yamont = new ParamDefinition(this, "Yamont", ParamDomainValue.POS, rYamont, ParamFamily.HEIGHTS);
+        this._Yaval = new ParamDefinition(this, "Yaval", ParamDomainValue.POS, rYAval, ParamFamily.HEIGHTS);
+        this._Long = new ParamDefinition(this, "Long", ParamDomainValue.POS, rLong, ParamFamily.LENGTHS);
         this._Dx = new ParamDefinition(this, "Dx", ParamDomainValue.POS, rDx);
 
         this.addParamDefinition(this._Yamont);
         this.addParamDefinition(this._Yaval);
         this.addParamDefinition(this._Long);
         this.addParamDefinition(this._Dx);
-        this.addParamDefinitions(this._section.prms);
+        // merge parameters from "section" but change their parent ParamsEquation, so that the
+        // grand-parent Nub is Remous and not acSection (for linking)
+        for (const p of this._section.prms) {
+            p.parent = this;
+            this.addParamDefinition(p);
+        }
+
         this.DefineCalculability(); // Pour ne pas remettre en undefined les prms de _section
     }
 
@@ -507,6 +513,15 @@ export class CourbeRemous extends Nub {
         throw new Error("CourbeRemous.Equation() : parameter " + sVarCalc + " not allowed");
     }
 
+    protected setExtraResultsFamilies() {
+        this._extraResultsFamilies = {
+            B: ParamFamily.WIDTHS,
+            Yf: ParamFamily.HEIGHTS,
+            Yt: ParamFamily.HEIGHTS,
+            Yco: ParamFamily.HEIGHTS
+        };
+    }
+
     private get Sn(): acSection {
         return this.prms.Sn;
     }
diff --git a/src/section/section_circulaire.ts b/src/section/section_circulaire.ts
index 0a0d9c90a8dc3c6d718f19192fd4cb6c9e379bee..0efae0855dd9f3e6eb62f09ea962cb7a8c415f5d 100644
--- a/src/section/section_circulaire.ts
+++ b/src/section/section_circulaire.ts
@@ -1,4 +1,4 @@
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { Message, MessageCode } from "../util/message";
 import { Result } from "../util/result";
@@ -9,7 +9,7 @@ export class ParamsSectionCirc extends ParamsSection {
 
         constructor(rD: number, rY: number, rKs: number, rQ: number, rIf: number, rYB: number) {
                 super(rY, undefined, rKs, rQ, rIf, rYB);
-                this._D = new ParamDefinition(this, "D", ParamDomainValue.POS, rD);
+                this._D = new ParamDefinition(this, "D", ParamDomainValue.POS, rD, ParamFamily.DIAMETERS);
 
                 this.addParamDefinition(this._D);
                 // hide params
diff --git a/src/section/section_parametree.ts b/src/section/section_parametree.ts
index e19f134731f1c703b63933b91336a3fafd5a46f5..63f4c3d95a499dbadd9054291b34944492b29448 100644
--- a/src/section/section_parametree.ts
+++ b/src/section/section_parametree.ts
@@ -1,14 +1,19 @@
 import { Nub } from "../nub";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomain, ParamDomainValue } from "../param/param-domain";
 import { ParamValueMode } from "../param/param-value-mode";
+import { ParamsEquation } from "../param/params-equation";
 import { Result } from "../util/result";
 import { ResultElement } from "../util/resultelement";
 import { acSection } from "./section_type";
 
+// dummy ParamsEquation for code consistency
+export class SectionParams extends ParamsEquation {}
+
 /**
  * Nub sur les sections paramétrées
  */
+// tslint:disable-next-line:max-classes-per-file
 export class SectionParametree extends Nub {
 
     public get section(): acSection {
@@ -153,6 +158,17 @@ export class SectionParametree extends Nub {
     // tslint:disable-next-line:no-empty
     protected setParametersCalculability(): void {}
 
+    protected setExtraResultsFamilies() {
+        this._extraResultsFamilies = {
+            B: ParamFamily.WIDTHS,
+            Yc: ParamFamily.HEIGHTS,
+            Yn: ParamFamily.HEIGHTS,
+            Yf: ParamFamily.HEIGHTS,
+            Yt: ParamFamily.HEIGHTS,
+            Yco: ParamFamily.HEIGHTS
+        };
+    }
+
     private initSectionVars() {
         this._sectionVars = {};
         this.initSectionVar("Hs");
@@ -208,7 +224,8 @@ export class SectionParametree extends Nub {
                 throw new Error(`SectionParametree.createSectionVar() : symbole ${symbol} non pris en charge`);
         }
 
-        const res = new ParamDefinition(this, symbol, dom);
+        const pe = new SectionParams(this);
+        const res = new ParamDefinition(pe, symbol, dom);
         res.calculability = ParamCalculability.EQUATION;
         return res;
     }
diff --git a/src/section/section_trapez.ts b/src/section/section_trapez.ts
index 7e5e085ab2612d89f59e2d73243853624f87adb2..789c93ea3a2a4b5217a0740ed6f92fdf892a540f 100644
--- a/src/section/section_trapez.ts
+++ b/src/section/section_trapez.ts
@@ -1,4 +1,4 @@
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { Result } from "../util/result";
 import { acSection, ParamsSection } from "./section_type";
@@ -11,7 +11,8 @@ export class ParamsSectionTrapez extends ParamsSection {
                     rQ: number, rIf: number, rYB: number) {
 
                 super(rY, undefined, rKs, rQ, rIf, rYB);
-                this._LargeurFond = new ParamDefinition(this, "LargeurFond", ParamDomainValue.POS_NULL, rLargeurFond);
+                this._LargeurFond = new ParamDefinition(this, "LargeurFond", ParamDomainValue.POS_NULL,
+                        rLargeurFond, ParamFamily.WIDTHS);
                 this._Fruit = new ParamDefinition(this, "Fruit", ParamDomainValue.POS_NULL, rFruit);
 
                 this.addParamDefinition(this._LargeurFond);
diff --git a/src/section/section_type.ts b/src/section/section_type.ts
index ca74eaee7f429a8cf8433df5dfc18c9a48566e2e..9941393ee9447c90b80dc6072a0805b916277e28 100644
--- a/src/section/section_type.ts
+++ b/src/section/section_type.ts
@@ -1,5 +1,5 @@
 import { ComputeNode } from "../compute-node";
-import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
 import { Message, MessageCode } from "../util/message";
@@ -22,9 +22,9 @@ export abstract class cParamsCanal extends ParamsEquation {
         constructor(rKs: number, rQ: number, rIf: number, rYB: number) {
                 super();
                 this._Ks = new ParamDefinition(this, "Ks", ParamDomainValue.POS, rKs);
-                this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, rQ);
-                this._If = new ParamDefinition(this, "If", ParamDomainValue.ANY, rIf);
-                this._YB = new ParamDefinition(this, "YB", ParamDomainValue.POS, rYB);
+                this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, rQ, ParamFamily.FLOWS);
+                this._If = new ParamDefinition(this, "If", ParamDomainValue.ANY, rIf, ParamFamily.SLOPES);
+                this._YB = new ParamDefinition(this, "YB", ParamDomainValue.POS, rYB, ParamFamily.HEIGHTS);
 
                 this.addParamDefinition(this._Ks);
                 this.addParamDefinition(this._Q);
@@ -82,9 +82,9 @@ export abstract class ParamsSection extends cParamsCanal {
                     rIf: number,
                     rYB: number) {
                 super(rKs, rQ, rIf, rYB);
-                this._Y = new ParamDefinition(this, "Y", ParamDomainValue.POS_NULL, rY);
+                this._Y = new ParamDefinition(this, "Y", ParamDomainValue.POS_NULL, rY, ParamFamily.HEIGHTS);
                 this._LargeurBerge = new ParamDefinition(
-                    this, "LargeurBerge", ParamDomainValue.POS_NULL, rLargeurBerge);
+                    this, "LargeurBerge", ParamDomainValue.POS_NULL, rLargeurBerge, ParamFamily.WIDTHS);
 
                 this.addParamDefinition(this._Y);
                 this.addParamDefinition(this._LargeurBerge);
diff --git a/src/session.ts b/src/session.ts
index b17ff9439ffc3e87e6fa4291b7e88b75091df14f..621e1526e7aaa3f1fb1b94f6867dfe17ff67d27d 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -23,9 +23,11 @@ import { cSnTrapez, ParamsSectionTrapez } from "./section/section_trapez";
 import { acSection } from "./section/section_type";
 
 // Classes relatives aux structures
+import { ParamDefinition } from "./param/param-definition";
 import { CreateStructure } from "./structure/factory_structure";
 import { Structure } from "./structure/structure";
 import { LoiDebit, StructureType } from "./structure/structure_props";
+import { LinkedValue } from "./value_ref/object_ref";
 
 export class Session {
 
@@ -368,7 +370,21 @@ export class Session {
     }
 
     /**
-     * Creates a Nub from an object representation and adds it tot he current session; returns
+     * Returns a list of nub/symbol couples, that can be linked to the given
+     * parameter, amoung all current nubs
+     * @param p
+     */
+    public getLinkableValues(p: ParamDefinition): LinkedValue[] {
+        let res: LinkedValue[] = [];
+        for (const n of this._nubs) {
+            const linkableValues = n.getLinkableValues(p);
+            res = res.concat(linkableValues);
+        }
+        return res;
+    }
+
+    /**
+     * Creates a Nub from an object representation and adds it to the current session; returns
      * a pointer to the Nub and its JSON metadata
      * @param obj object representation of a single Nub
      */
diff --git a/src/structure/cloisons_params.ts b/src/structure/cloisons_params.ts
index 5d3e378e0b836db59f28be6db0e325b7c42495f2..0d1e4aa66eba95a4171c3bfb82952a03e220f0ce 100644
--- a/src/structure/cloisons_params.ts
+++ b/src/structure/cloisons_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParallelStructureParams } from "./parallel_structure_params";
 
@@ -29,13 +29,13 @@ export class CloisonsParams extends ParallelStructureParams {
      */
     constructor(rQ: number, rZ1: number, rLB: number, rBB: number, rPB: number, rDH: number) {
         super(rQ, rZ1, rZ1 - rDH);
-        this.LB = new ParamDefinition(this, "LB", ParamDomainValue.POS, rLB);
+        this.LB = new ParamDefinition(this, "LB", ParamDomainValue.POS, rLB, ParamFamily.LENGTHS);
         this.addParamDefinition(this.LB);
-        this.BB = new ParamDefinition(this, "BB", ParamDomainValue.POS, rBB);
+        this.BB = new ParamDefinition(this, "BB", ParamDomainValue.POS, rBB, ParamFamily.WIDTHS);
         this.addParamDefinition(this.BB);
-        this.PB = new ParamDefinition(this, "PB", ParamDomainValue.POS, rPB);
+        this.PB = new ParamDefinition(this, "PB", ParamDomainValue.POS, rPB, ParamFamily.HEIGHTS);
         this.addParamDefinition(this.PB);
-        this.DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, rDH);
+        this.DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, rDH, ParamFamily.HEIGHTS);
         this.addParamDefinition(this.DH);
         // hide Z2
         this.Z2.visible = false;
diff --git a/src/structure/dever.ts b/src/structure/dever.ts
index 43199715635c19554344297e1a95467bbb3ccd7a..4af0244f17285ba418d5c9b052d8595158d625e4 100644
--- a/src/structure/dever.ts
+++ b/src/structure/dever.ts
@@ -1,4 +1,4 @@
-import { ParamCalculability } from "../param/param-definition";
+import { ParamCalculability, ParamFamily } from "../param/param-definition";
 import { Result } from "../util/result";
 import { DeverParams } from "./dever_params";
 import { ParallelStructure } from "./parallel_structure";
@@ -95,6 +95,12 @@ export class Dever extends ParallelStructure {
         this.prms.Z2.calculability = ParamCalculability.NONE;
     }
 
+    protected setExtraResultsFamilies() {
+        this._extraResultsFamilies = {
+            CvQT: ParamFamily.FLOWS
+        };
+    }
+
     /**
      * Calcul de la somme des aires des ouvrages.
      * @note N.B. : doit être appelé après calcul si le calcul porte sur Z1 ou
diff --git a/src/structure/dever_params.ts b/src/structure/dever_params.ts
index a8a8a15e02b3c7aa27385c524ffb55eff70e929d..87b3509de30e7ce2a325b3e879d63fa48c478bd0 100644
--- a/src/structure/dever_params.ts
+++ b/src/structure/dever_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParallelStructureParams } from "./parallel_structure_params";
 
@@ -21,9 +21,9 @@ export class DeverParams extends ParallelStructureParams {
      */
     constructor(rQ: number, rZ1: number, rBR: number, rZR: number) {
         super(rQ, rZ1, - Infinity);
-        this.BR = new ParamDefinition(this, "BR", ParamDomainValue.ANY, rBR);
+        this.BR = new ParamDefinition(this, "BR", ParamDomainValue.ANY, rBR, ParamFamily.WIDTHS);
         this.addParamDefinition(this.BR);
-        this.ZR = new ParamDefinition(this, "ZR", ParamDomainValue.ANY, rZR);
+        this.ZR = new ParamDefinition(this, "ZR", ParamDomainValue.ANY, rZR, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this.ZR);
         // hide fields
         this.Z2.visible = false;
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index bfbc4067101ed83661cad2872117a416d7ea27a8..9ef6b309d665ac44ea99e27f7971860b8302c7d5 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -5,12 +5,11 @@ import { ParallelStructureParams } from "./parallel_structure_params";
 import { Structure } from "./structure";
 
 import { ParamDefinition } from "../param/param-definition";
-import { INamedIterableValues } from "../param/param-value-iterator";
-import { ParamValues } from "../param/param-values";
 import { IParamDefinitionIterator, ParamsEquation, ParamsEquationArrayIterator } from "../param/params-equation";
 
 import { Props } from "../props";
 import { Session } from "../session";
+import { LinkedValue } from "../value_ref/object_ref";
 import { loiAdmissiblesOuvrages, LoiDebit } from "./structure_props";
 
 export { ParallelStructureParams };
@@ -142,8 +141,15 @@ export class ParallelStructure extends Nub {
      * @return true si la structure donnée est dans la liste
      */
     public hasStructure(structure: Nub): boolean {
+        return this.hasStructureUid(structure.uid);
+    }
+
+    /**
+     * @return true si la structure donnée est dans la liste
+     */
+    public hasStructureUid(structureUid: string): boolean {
         for (const s of this._structures) {
-            if (s.uid === structure.uid) {
+            if (s.uid === structureUid) {
                 return true;
             }
         }
@@ -270,70 +276,46 @@ export class ParallelStructure extends Nub {
         return res;
     }
 
-    // interface IReferencedNub
-    public getReferencedObject(desc: string): INamedIterableValues {
-        try {
-            // analyse n.X
-            const i: IStructureVarCalc = this.getStructureVarCalc(desc);
-            return this._structures[i.index].getParameter(i.prm);
-        } catch (e) {
-            // desc n'est pas de la forme n.X
-            try {
-                // analyse ouvrage[n].X
-                const i: IStructureVarCalc = this.getStructureVarCalc2(desc);
-                const res = this._structures[i.index].result;
-                if (res === undefined) {
-                    return undefined;  // pas de résultat calculé
-                }
-                return res.getExtraResult(i.prm);
-            } catch (e) {
-                // desc n'est pas de la forme ouvrage[n].X
-            }
-        }
-        // pas de la forme n.X ou ouvrage[n].X ou erreur sur n ou X
-        return super.getReferencedObject(desc);
-    }
-
-    public getReferencedParamValues(desc: string): ParamValues {
-        try {
-            const ro = this.getReferencedObject(desc);
-            if (ro instanceof ParamDefinition) {
-                return ro.paramValues;
-            }
-            return undefined;
-        } catch (e) {
-            // pas de la forme n.X ou ouvrage[n].X ou erreur sur n ou X
-            const param = this.getParameter(desc);
-            if (param === undefined) {
-                return undefined;
-            }
-            return param.paramValues;
-        }
-    }
-
-    public getReferencedExtraResult(desc: string): any {
-        return this._result.getExtraResult(desc);
-    }
-
     /**
      * liste des valeurs (paramètre, résultat, résultat complémentaire) liables à un paramètre
-     * @param src objet qui sert de clé de recherche des paramètres liables, de type INamedObject | string
-     * @returns tableau d'objets de la forme :
-     *          { "name":string, "value":INamedIterableValues, "nub":Nub}, nub=Nub d'origine de la "value"
+     * @param src paramètre auquel lier d'autres valeurs
      */
-    public getLinkableValues(src: any): any[] {
-        // paramètres liables de ce Nub
-        let res = super.getLinkableValues(src);
-        let i = 0;
+    public getLinkableValues(src: ParamDefinition): LinkedValue[] {
+        let res: LinkedValue[] = [];
+        // linabkle parameters of this Nub, unless src comes from a child Structure
+        if (! this.hasStructureUid(src.nubUid)) {
+            res = super.getLinkableValues(src);
+        }
+        // paramètres liables des Nub structures enfants
         for (const s of this._structures) {
-            // paramètres liables des Nub structures enfants
-            const childStructureLinkableParams = s.getLinkableValues(src, undefined, true);
+            const childStructureLinkableParams = s.getLinkableValues(src);
             res = res.concat(childStructureLinkableParams);
-            i++;
         }
         return res;
     }
 
+    /**
+     * Returns true if the computation of the current Nub requires, directly
+     * or not, anything (parameter or result) from the given Nub UID "uid";
+     * includes checking child Structures if any
+     * (to prevent circular linking)
+     * @param uid
+     */
+    public resultDependsOnNub(uid: string): boolean {
+        let depends = super.resultDependsOnNub(uid);
+        // does any of our child structures parameters depend on the target Nub ?
+        if (! depends) {
+            structuresloop:
+            for (const s of this.structures) {
+                if (s.resultDependsOnNub(uid)) {
+                    depends = true;
+                    break structuresloop;
+                }
+            }
+        }
+        return depends;
+    }
+
     /**
      * Returns an object representation of the Nub's current state; compared to generic
      * Nub::objectRepresentation(), represents the parallel structures in a specific way
diff --git a/src/structure/parallel_structure_params.ts b/src/structure/parallel_structure_params.ts
index 6bcfd33e7e65936a92a0089eb9b6ea461690e0d5..b4d05f6bdb1a8cf8a4f167d8264ba9caac56986a 100644
--- a/src/structure/parallel_structure_params.ts
+++ b/src/structure/parallel_structure_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
 
@@ -23,11 +23,11 @@ export class ParallelStructureParams extends ParamsEquation {
      */
     constructor(rQ: number, rZ1: number, rZ2: number) {
         super();
-        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.ANY, rQ);
+        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.ANY, rQ, ParamFamily.FLOWS);
         this.addParamDefinition(this.Q);
-        this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, rZ1);
+        this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, rZ1, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this.Z1);
-        this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, rZ2);
+        this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, rZ2, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this.Z2);
     }
 }
diff --git a/src/structure/rectangular_structure_params.ts b/src/structure/rectangular_structure_params.ts
index 1ffab8094b4975e9faaeb271ba4a98fcbebb5390..b7de51e6ba2042b920b05a2f7f13062d9e09864a 100644
--- a/src/structure/rectangular_structure_params.ts
+++ b/src/structure/rectangular_structure_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { StructureParams } from "./structure_params";
 
@@ -25,7 +25,7 @@ export class RectangularStructureParams extends StructureParams {
      */
     constructor(rQ: number, rZDV: number, rZ1: number, rZ2: number, rL: number, rCd: number, rW: number = Infinity) {
         super(rQ, rZDV, rZ1, rZ2, rW);
-        this.L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL);
+        this.L = new ParamDefinition(this, "L", ParamDomainValue.POS, rL, ParamFamily.WIDTHS);
         this.addParamDefinition(this.L);
         this.Cd = new ParamDefinition(this, "Cd", ParamDomainValue.POS, rCd);
         this.addParamDefinition(this.Cd);
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index 7a59fdbe58fc365565f1d150bdbfaa8829e57f41..c525d94890fb118a080d76d1dc7ae63d60e427a7 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -1,7 +1,8 @@
 import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition";
 import { Message, MessageCode } from "../util/message";
 import { Result } from "../util/result";
+import { LinkedValue } from "../value_ref/object_ref";
 
 import { ParallelStructure } from "./parallel_structure";
 import { StructureParams } from "./structure_params";
@@ -90,6 +91,15 @@ export abstract class Structure extends Nub {
         return this.parent.getIndexForStructure(this);
     }
 
+    public getLinkableValues(src: ParamDefinition): LinkedValue[] {
+        const res: LinkedValue[] = [];
+        // OK unless the source parameter belongs to this Structure's parent
+        if (this.parent.uid !== src.nubUid) {
+            return super.getLinkableValues(src);
+        }
+        return res;
+    }
+
     /**
      * Calcul de l'aire d'écoulement sur le seuil ou dans l'orifice
      */
@@ -256,4 +266,10 @@ export abstract class Structure extends Nub {
         }
     }
 
+    protected setExtraResultsFamilies() {
+        this._extraResultsFamilies = {
+            Q: ParamFamily.FLOWS
+        };
+    }
+
 }
diff --git a/src/structure/structure_kivi_params.ts b/src/structure/structure_kivi_params.ts
index a690bd61ab73d6c8cc405d000d1f3daa59edabf9..9ab1cd4cff20b60d6ee5a8ce3dceb39ac656a92d 100644
--- a/src/structure/structure_kivi_params.ts
+++ b/src/structure/structure_kivi_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { StructureParams } from "./structure_params";
 
@@ -30,13 +30,13 @@ export class StructureKiviParams extends StructureParams {
         rZRAM: number
     ) {
         super(rQ, rZDV, rZ1, rZ2, Infinity);
-        this.L = new ParamDefinition(this, "L", ParamDomainValue.POS_NULL, rL);
+        this.L = new ParamDefinition(this, "L", ParamDomainValue.POS_NULL, rL, ParamFamily.WIDTHS);
         this.addParamDefinition(this.L);
         this.alpha = new ParamDefinition(this, "alpha", ParamDomainValue.POS, rAlpha);
         this.addParamDefinition(this.alpha);
         this.beta = new ParamDefinition(this, "beta", ParamDomainValue.POS_NULL, rBeta);
         this.addParamDefinition(this.beta);
-        this.ZRAM = new ParamDefinition(this, "ZRAM", ParamDomainValue.ANY, rZRAM);
+        this.ZRAM = new ParamDefinition(this, "ZRAM", ParamDomainValue.ANY, rZRAM, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this.ZRAM);
     }
 }
diff --git a/src/structure/structure_orifice_submerged_params.ts b/src/structure/structure_orifice_submerged_params.ts
index 2c4ca25838a77d9533c808d1702bb9bbd260d2e2..68b0fc8ce2eef16034c0bcdc38eb38daaebd6a02 100644
--- a/src/structure/structure_orifice_submerged_params.ts
+++ b/src/structure/structure_orifice_submerged_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { StructureParams } from "../structure/structure_params";
 
diff --git a/src/structure/structure_params.ts b/src/structure/structure_params.ts
index 3f3018c4c00d8f44a28cdda2e60f2c46ce505cf1..c70a06b90d616907c957a9cabbab1f41b0636565 100644
--- a/src/structure/structure_params.ts
+++ b/src/structure/structure_params.ts
@@ -1,5 +1,5 @@
 import { Nub } from "../nub";
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { ParamsEquation } from "../param/params-equation";
 
@@ -40,21 +40,21 @@ export class StructureParams extends ParamsEquation {
      */
     constructor(rQ: number, rZDV: number, rZ1: number, rZ2: number, rW: number = Infinity) {
         super();
-        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.ANY, rQ, false); // hidden by default
+        this.Q = new ParamDefinition(this, "Q", ParamDomainValue.ANY, rQ, ParamFamily.FLOWS, false);
         this.addParamDefinition(this.Q);
-        this.ZDV = new ParamDefinition(this, "ZDV", ParamDomainValue.ANY, rZDV);
+        this.ZDV = new ParamDefinition(this, "ZDV", ParamDomainValue.ANY, rZDV, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this.ZDV);
-        this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, rZ1, false); // hidden by default
+        this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, rZ1, ParamFamily.ELEVATIONS, false);
         this.addParamDefinition(this.Z1);
-        this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, rZ2, false); // hidden by default
+        this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, rZ2, ParamFamily.ELEVATIONS, false);
         this.addParamDefinition(this.Z2);
         this.h1 = new ParamDefinition(this, "h1", ParamDomainValue.POS_NULL,
-            Math.max(0, this.Z1.v - this.ZDV.v), false); // hidden by default
+            Math.max(0, this.Z1.v - this.ZDV.v), ParamFamily.HEIGHTS, false);
         this.addParamDefinition(this.h1);
         this.h2 = new ParamDefinition(this, "h2", ParamDomainValue.POS_NULL,
-            Math.max(0, this.Z2.v - this.ZDV.v), false); // hidden by default
+            Math.max(0, this.Z2.v - this.ZDV.v), ParamFamily.HEIGHTS, false);
         this.addParamDefinition(this.h2);
-        this.W = new ParamDefinition(this, "W", ParamDomainValue.POS_NULL, rW, false); // hidden by default
+        this.W = new ParamDefinition(this, "W", ParamDomainValue.POS_NULL, rW, ParamFamily.WIDTHS, false);
         this.addParamDefinition(this.W);
         // hide params
         this.Pr.visible = false;
diff --git a/src/structure/structure_triangular_trunc_weir_free_params.ts b/src/structure/structure_triangular_trunc_weir_free_params.ts
index 6226c35e0601a77c434efa529b8286df76ff1b9a..694f2b9db203e606ce38e9fa2bb292c6bda7f091 100644
--- a/src/structure/structure_triangular_trunc_weir_free_params.ts
+++ b/src/structure/structure_triangular_trunc_weir_free_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { StructureParams } from "./structure_params";
 
@@ -33,7 +33,7 @@ export class TriangularTruncStructureParams extends StructureParams {
         super(rQ, rZDV, rZ1, - Infinity, rW);
         this.BT = new ParamDefinition(this, "BT", ParamDomainValue.POS, rBT);
         this.addParamDefinition(this.BT);
-        this.ZT = new ParamDefinition(this, "ZT", ParamDomainValue.POS, rZT);
+        this.ZT = new ParamDefinition(this, "ZT", ParamDomainValue.POS, rZT, ParamFamily.ELEVATIONS);
         this.addParamDefinition(this.ZT);
         this.Cd = new ParamDefinition(this, "Cd", ParamDomainValue.POS, rCd);
         this.addParamDefinition(this.Cd);
diff --git a/src/structure/structure_triangular_weir_free_params.ts b/src/structure/structure_triangular_weir_free_params.ts
index 7c4253ec2624e3d5a9ca3cc17a29a5b39af04ec3..89745252bc6052ecae255546f5b00a2f6767f178 100644
--- a/src/structure/structure_triangular_weir_free_params.ts
+++ b/src/structure/structure_triangular_weir_free_params.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from "../param/param-definition";
+import { ParamDefinition, ParamFamily } from "../param/param-definition";
 import { ParamDomainValue } from "../param/param-domain";
 import { StructureParams } from "./structure_params";
 
diff --git a/src/util/message.ts b/src/util/message.ts
index 966f4cb6abe30932eb5d8237735310c17e5c55b9..cd5b6e391250a41ce7262a6cfe7b65f44dfc7648 100644
--- a/src/util/message.ts
+++ b/src/util/message.ts
@@ -63,6 +63,11 @@ export enum MessageCode {
      */
     ERROR_PARAMDEF_VALUE_UNDEFINED,
 
+    /**
+     * la valeur de la cible d'un ParamDefinition est non définie
+     */
+    ERROR_PARAMDEF_LINKED_VALUE_UNDEFINED,
+
     /**
      * la valeur d'un ParamDefinition ne peut pas être changée
      */
diff --git a/src/util/result.ts b/src/util/result.ts
index 55a9e877c1a963c3f5a9388b752fa63251032a57..356b1c8ccaf0005099a9814ecf69e7f714e13aff 100644
--- a/src/util/result.ts
+++ b/src/util/result.ts
@@ -1,6 +1,11 @@
 import { JalhydObject } from "../jalhyd_object";
-// tslint:disable-next-line:max-line-length
-import { INamedIterableValues, INumberIterator, NumberArrayIterator, NumberArrayReverseIterator } from "../param/param-value-iterator";
+import { ParamFamily } from "../param/param-definition";
+import {
+    INamedIterableValues,
+    INumberIterator,
+    NumberArrayIterator,
+    NumberArrayReverseIterator
+} from "../param/param-value-iterator";
 import { cLog } from "./log";
 import { Message, MessageCode, MessageSeverity } from "./message";
 import { ResultElement } from "./resultelement";
@@ -11,6 +16,13 @@ import { ResultElement } from "./resultelement";
  */
 // tslint:disable-next-line:max-classes-per-file
 export class Result extends JalhydObject implements INamedIterableValues {
+
+    /** nom de la variable/paramètre calculé */
+    public name: string;
+
+    /** "parameters" family, for linked parameters */
+    public family: ParamFamily;
+
     /**
      * Messages (erreurs, infos, ...)
      */
@@ -18,11 +30,6 @@ export class Result extends JalhydObject implements INamedIterableValues {
 
     private _resultElements: ResultElement[];
 
-    /**
-     * nom de la variable/paramètre calculé
-     */
-    private _name: string;
-
     /**
      * itérateur sur les valeurs des ResultElements
      */
@@ -43,14 +50,6 @@ export class Result extends JalhydObject implements INamedIterableValues {
         }
     }
 
-    public get name(): string {
-        return this._name;
-    }
-
-    public set name(n: string) {
-        this._name = n;
-    }
-
     /**
      * retourne le journal de la calculette
      */
@@ -201,10 +200,6 @@ export class Result extends JalhydObject implements INamedIterableValues {
         }
     }
 
-    // protected get messageCount(): number {
-    //     return this._globalLog.messages.length;
-    // }
-
     /**
      * ajoute un message au journal
      */
@@ -345,6 +340,9 @@ export class Result extends JalhydObject implements INamedIterableValues {
  */
 // tslint:disable-next-line:max-classes-per-file
 export class ExtraResults extends JalhydObject implements INamedIterableValues {
+
+    public family: ParamFamily;
+
     private _name: string;
 
     private _values: number[];
diff --git a/src/value_ref/object_ref.ts b/src/value_ref/object_ref.ts
index baba13fb94b3c03a90d5dfe3f6243898b5939658..3db161ae793733f22b87c737f869f5c26fd00c13 100644
--- a/src/value_ref/object_ref.ts
+++ b/src/value_ref/object_ref.ts
@@ -1,196 +1,128 @@
-import { INamedIterableValues, INumberIterator } from "../param/param-value-iterator";
+import { Nub } from "../nub";
+import { ParamDefinition } from "../param/param-definition";
+import { INamedIterableValues } from "../param/param-value-iterator";
+import { ParamValueMode } from "../param/param-value-mode";
 import { ParamValues } from "../param/param-values";
-import { Result } from "../util/result";
+import { Message, MessageCode } from "../util/message";
 
-/*
- * gestion de la valeur d'un paramètre par référence à une autre valeur (paramètre, résultat, résultat complémentaire)
- *
- * la référence (cf. INubReference.defineReference) (cf. INubReference.defineReference)
- * est de la forme <n | ouvrage[n] | N1>[.[N2]]
- *     n : indice de de l'ouvrage dans le cas des ouvrages parallèles
- *     N1 : un nom de paramètre/résultat (dans le cas d'un résultat, il est suivi d'un point)
- *     N2 : nom de résultat complémentaire (optionnel)
- *     ex :
- *       Q, Z1 (paramètres)
- *       J. (résultat)
- *       .Yf (résultat complémentaire du résultat courant)
- *       Q.Yf (résultat complémentaire du résultat nommé "Q")
- *       0.Q : paramètre Q du 1er ouvrage (ouvrages parallèles)
- *       ouvrage[1].Q_Mode : résultat complémentaire du 2ème ouvrage (ouvrages parallèles)
- */
+export class LinkedValue {
+    /** linked value metadata (ex: calculator title for GUI) */
+    public meta: any;
 
-/**
- * Nub dont certaines valeurs sont référençables pour réutilisation
- * (d'une calculette sur une autre par ex)
- */
-export interface IReferencedNub {
+    /** target Nub */
+    private _nub: Nub;
 
-    /**
-     * getter des valeurs
-     * @param desc : description sous forme symbolique
-     */
-    getReferencedParamValues(desc: string): ParamValues;
-
-    /**
-     * getter du résultat
-     * @param desc : description sous forme symbolique
-     */
-    getReferencedResult(desc?: string): Result;
-
-    /**
-     * getter du résultat complémentaire
-     * @param desc : description sous forme symbolique
-     */
-    getReferencedExtraResult(desc: string): any;
-
-    /**
-     * itérateur sur les valeurs
-     */
-    getReferencedValuesIterator(desc: string): INumberIterator;
-
-    /**
-     * objet (paramètre/résultat/résultat complémentaire) référencé
-     */
-    getReferencedObject(desc: string): INamedIterableValues;
-}
-
-/**
- * référence vers un Nub contenant une valeur vers laquelle on crée un lien
- */
-export interface INubReference {
-
-    /**
-     * description symbolique de la référence
-     */
-    readonly referenceDefinition: string;
-
-    /**
-     * true si la référence a été définie
-     */
-    readonly isReferenceDefined: boolean;
-
-    /**
-     * instance de ParamValues référencée
-     */
-    readonly referencedParamValues: ParamValues;
-
-    /**
-     * instance de Result référencée
-     */
-    readonly referencedResult: Result;
+    /** target value : ParamDefinition (possibly in CALC mode) | undefined (ExtraResults) */
+    private _element: INamedIterableValues;
 
-    /**
-     * instance de résultat complémentaire référencée
-     */
-    readonly referencedExtraResult: any;
+    /** parameter / result symbol (ex: "Q") */
+    private _symbol: string;
 
-    /**
-     * itérateur sur les valeurs référencées
-     */
-    readonly referencedValuesIterator: INumberIterator;
-
-    /**
-     * objet (paramètre/résultat/résultat complémentaire) référencé
-     */
-    readonly referencedObject: INamedIterableValues;
+    constructor(nub: Nub, element: INamedIterableValues, symbol: string, meta: any = {}) {
+        this._nub = nub;
+        this._element = element;
+        this._symbol = symbol;
+        this.meta = meta;
+    }
 
-    /**
-     * définition de la valeur référencée dans le Nub
-     * @param target Nub contenant la valeur qu'on va référencer
-     * @param desc : description de la valeur pointée sous forme symbolique. Exemples : Q, <n° d'ouvrage>.Z1
-     */
-    defineReference(target: IReferencedNub, desc: string): void;
+    public get nub() { return this._nub; }
+    public get element() { return this._element; }
+    public get symbol() { return this._symbol; }
 
     /**
-     * supprime la référence
+     * Returns true if targetted value is a ParamDefinition (in CALC mode or not),
+     * and not an extra result
      */
-    undefineReference(): void;
-}
-
-/**
- * implémentation par défaut de INubReference
- */
-export class NubReference implements INubReference {
-    private _referencedNub: IReferencedNub;
-
-    private _refDefinition: string;
-
-    public defineReference(target: IReferencedNub, desc: string) {
-        this._referencedNub = target;
-        this._refDefinition = desc;
+    public isParameter(): boolean {
+        return (this.element instanceof ParamDefinition);
     }
 
     /**
-     * supprime la référence
+     * Returns true if targetted value is a ParamDefinition in CALC mode
+     * (might not have any value yet)
      */
-    public undefineReference() {
-        this._referencedNub = undefined;
-        this._refDefinition = undefined;
+    public isResult(): boolean {
+        return (
+            this.isParameter()
+            && (this.element as ParamDefinition).valueMode === ParamValueMode.CALCUL
+        );
     }
 
     /**
-     * description symbolique de la référence
+     * Returns true if targetted value is an extra result
+     * (might not have any value yet)
      */
-    public get referenceDefinition(): string {
-        return this._refDefinition;
-    }
-
-    public get isReferenceDefined(): boolean {
-        return this._referencedNub !== undefined && this._refDefinition !== undefined;
+    public isExtraResult(): boolean {
+        return (
+            this.nub !== undefined
+            && this.symbol !== undefined
+            && ! this.isParameter()
+        );
     }
 
     /**
-     * Nub référencé
-     */
-    public get referencedNub(): IReferencedNub {
-        return this._referencedNub;
+     * Returns true if v and the current objects have the same :
+     *  - Nub UID
+     *  - symbol
+     *  - value type (Parameter / Result)
+     * (ignores metadata)
+     * @param v
+     */
+    public equals(v: LinkedValue): boolean {
+        return (
+            v
+            && (v.nub.uid === this.nub.uid)
+            && (v.symbol === this.symbol)
+            && (
+                (v.element === undefined && this.element === undefined)
+                || (
+                    v.element !== undefined
+                    && this.element !== undefined
+                    && v.element.constructor.name === this.element.constructor.name
+                )
+            )
+        );
     }
 
     /**
-     * instance de ParamValues référencée
+     * Returs the ParamValues for the linked Parameter if any, or a
+     * pseudo ParamValues object if the targetted element is a Result
+     * or ExtraResults
      */
-    public get referencedParamValues(): ParamValues {
-        if (!this.isReferenceDefined) {
-            return undefined;
+    public getParamValues(): ParamValues {
+        if (this.isParameter()) {
+            return (this.element as ParamDefinition).paramValues;
+        } else {
+            // @TODO implement
+            throw new Error("not implemented - get pseudo ParamValues for ExtraResults");
         }
-        const rpv = this._referencedNub.getReferencedParamValues(this._refDefinition);
-        if (rpv) {
-            rpv._nubRef = this;
-        }
-        return rpv;
     }
 
     /**
-     * instance de Result référencée
+     * Returns the current value of this.paramValues; throws an error if
+     * this.paramValues is not defined
      */
-    public get referencedResult(): Result {
-        if (!this.isReferenceDefined) {
-            return undefined;
+    public getValue() {
+        if (! this.getParamValues().isDefined) {
+            const e = new Message(MessageCode.ERROR_PARAMDEF_LINKED_VALUE_UNDEFINED);
+            e.extraVar.symbol = this.symbol;
+            throw e;
         }
-        return this._referencedNub.getReferencedResult(this._refDefinition);
+        return this.getParamValues().currentValue;
     }
 
     /**
-     * instance de résultat complémentaire référencée
+     * Returns true if
+     * - a parameter is targetted and it has multiple values
+     * - a result / extra result is targetted and it has more than 1 value
      */
-    public get referencedExtraResult(): any {
-        if (!this.isReferenceDefined) {
-            return undefined;
+    public hasMultipleValues(): boolean {
+        if (this.isParameter()) {
+            return (this.element as ParamDefinition).hasMultipleValues;
+        } else if (this.isResult() || this.isExtraResult()) {
+            // guess if parent Nub has any variating parameter (linked or not)
+            return this.nub.resultHasMultipleValues();
         }
-        return this._referencedNub.getReferencedExtraResult(this._refDefinition);
-    }
-
-    /**
-     * itérateur sur les valeurs référencées
-     */
-    public get referencedValuesIterator(): INumberIterator {
-        return this._referencedNub.getReferencedValuesIterator(this._refDefinition);
-    }
-
-    /**
-     * objet (paramètre/résultat/résultat complémentaire) référencé
-     */
-    public get referencedObject(): INamedIterableValues {
-        return this._referencedNub.getReferencedObject(this._refDefinition);
+        return false;
     }
 }