diff --git a/spec/iterator/named_iterable_value.spec.ts b/spec/iterator/named_iterable_value.spec.ts
index e8c3ac56bafbad846a7375060e585d6366203f5f..42926eb2d7d5ac0cf1122c61a0c724cce037dd16 100644
--- a/spec/iterator/named_iterable_value.spec.ts
+++ b/spec/iterator/named_iterable_value.spec.ts
@@ -1,4 +1,4 @@
-import { BaseParam, ExtraResults, ParamDomainValue, Result, ResultElement } from "../../src";
+import { ExtraResults, ParamDefinition, ParamDomainValue, Result, ResultElement } from "../../src";
 
 /**
  * IMPORTANT !
@@ -8,8 +8,8 @@ import { BaseParam, ExtraResults, ParamDomainValue, Result, ResultElement } from
  */
 // import { describe, expect, it, xdescribe, xit } from "../mock_jasmine";
 
-function testBaseParamValues(vals: number[]): BaseParam {
-    const p: BaseParam = new BaseParam("aa", ParamDomainValue.ANY);
+function testParamDefinitionValues(vals: number[]): ParamDefinition {
+    const p: ParamDefinition = new ParamDefinition("aa", ParamDomainValue.ANY);
 
     p.paramValues.setValues(vals);
 
@@ -58,28 +58,28 @@ function testExtraResultsValues(vals: number[]): ExtraResults {
 }
 
 describe("INamedIterableValues  : ", () => {
-    describe("BaseParam  : ", () => {
+    describe("ParamDefinition  : ", () => {
         it("test 1", () => {
             const name = "aa";
-            const p: BaseParam = new BaseParam(name, ParamDomainValue.ANY);
+            const p: ParamDefinition = new ParamDefinition(name, ParamDomainValue.ANY);
             expect(p.name).toEqual(name);
         });
 
         it("test 2", () => {
             const vals: number[] = [];
-            const p = testBaseParamValues(vals);
+            const p = testParamDefinitionValues(vals);
             expect(p.hasMultipleValues).toBeFalsy();
         });
 
         it("test 3", () => {
             const vals: number[] = [0];
-            const p = testBaseParamValues(vals);
+            const p = testParamDefinitionValues(vals);
             expect(p.hasMultipleValues).toBeFalsy();
         });
 
         it("test 4", () => {
             const vals: number[] = [0, 1];
-            const p = testBaseParamValues(vals);
+            const p = testParamDefinitionValues(vals);
             expect(p.hasMultipleValues).toBeTruthy();
         });
     });
diff --git a/src/dichotomie.ts b/src/dichotomie.ts
index 43a29c63b06331eb24da29326bf3979b2647aa47..df166f00733f8f20406d5c868dffeb4ea1099b18 100644
--- a/src/dichotomie.ts
+++ b/src/dichotomie.ts
@@ -5,7 +5,6 @@ import { ParamDefinition } from "./param/param-definition";
 import { ParamDomain, ParamDomainValue } from "./param/param-domain";
 import { Interval } from "./util/interval";
 import { Message, MessageCode } from "./util/message";
-import { Pair } from "./util/pair";
 import { Result } from "./util/result";
 
 class SearchInterval extends Interval {
@@ -13,7 +12,7 @@ class SearchInterval extends Interval {
 
     private _dicho: Dichotomie;
 
-    private _targets: Pair;
+    private _targets: Interval;
 
     constructor(d: Dichotomie, min: number, max: number, s: number) {
         super(min, max);
@@ -43,7 +42,8 @@ class SearchInterval extends Interval {
 
     get targets() {
         if (this._targets === undefined) {
-            this._targets = new Pair(undefined, undefined);
+            // @TODO just set _targets to undefined / null ?
+            this._targets = new Interval(undefined, undefined);
         }
         return this._targets;
     }
@@ -53,6 +53,7 @@ class SearchInterval extends Interval {
      */
     get targetLower() {
         this.updateTargets();
+        // @TODO val1 is not guaranteed to be the lower bound; use .min ?
         return this.targets.val1;
     }
 
@@ -61,17 +62,18 @@ class SearchInterval extends Interval {
      */
     get targetUpper() {
         this.updateTargets();
+        // @TODO val2 is not guaranteed to be the upper bound; use .max ?
         return this.targets.val2;
     }
 
     public next() {
         if (this._step > 0) {
-            this._val1 = this._val2;
-            this._val2 += this._step;
+            this.val1 = this.val2;
+            this.val2 += this._step;
             this.targets.setValues(this.targets.val2, undefined);
         } else {
-            this._val2 = this._val1;
-            this._val1 += this._step;
+            this.val2 = this.val1;
+            this.val1 += this._step;
             this.targets.setValues(undefined, this.targets.val1);
         }
     }
@@ -88,12 +90,12 @@ class SearchInterval extends Interval {
     private updateTargets() {
         let t1 = this.targets.val1;
         if (t1 === undefined) {
-            t1 = this._dicho.CalculX(this._val1).vCalc;
+            t1 = this._dicho.CalculX(this.val1).vCalc;
         }
 
         let t2 = this.targets.val2;
         if (t2 === undefined) {
-            t2 = this._dicho.CalculX(this._val2).vCalc;
+            t2 = this._dicho.CalculX(this.val2).vCalc;
         }
         this.targets.setValues(t1, t2);
     }
@@ -229,7 +231,7 @@ export class Dichotomie extends Debug {
     private isIncreasingFunction(x: number, dom: Interval): boolean {
         const epsilon = 1e-8;
         const bounds = new Interval(x - epsilon, x + epsilon);
-        bounds.setBounds(bounds.intersect(dom)); // au cas où l'on sorte du domaine de la variable de la fonction
+        bounds.setInterval(bounds.intersect(dom)); // au cas où l'on sorte du domaine de la variable de la fonction
 
         const y1 = this.CalculX(bounds.min).vCalc;
         const y2 = this.CalculX(bounds.max).vCalc;
@@ -252,7 +254,7 @@ export class Dichotomie extends Debug {
             if (inters.length === 0) {
                 break;
             }
-            intSearch.setBounds(inters);
+            intSearch.setInterval(inters);
             if (intSearch.hasTargetValue(rTarget)) {
                 ok = true;
                 break;
@@ -293,7 +295,7 @@ export class Dichotomie extends Debug {
         // initialisation de l'intervalle de recherche
         let intSearch: SearchInterval = new SearchInterval(this, rInit - step / 2, rInit + step / 2, step);
         // au cas où l'on sorte du domaine de la variable de la fonction
-        intSearch.setBounds(intSearch.intersect(intMax));
+        intSearch.setInterval(intSearch.intersect(intMax));
 
         // sens de variation de la fonction
         const inc = this.isIncreasingFunction(rInit, intMax);
@@ -318,7 +320,7 @@ export class Dichotomie extends Debug {
         const oldStepSign = intSearch.step > 0 ? 1 : -1;
         intSearch = new SearchInterval(this, rInit + step / 2, rInit + step, step * -oldStepSign);
         // au cas où l'on sorte du domaine de la variable de la fonction
-        intSearch.setBounds(intSearch.intersect(intMax));
+        intSearch.setInterval(intSearch.intersect(intMax));
 
         a = this.searchTarget(rTarget, intSearch, intMax);
         if (a.ok) {
diff --git a/src/index.ts b/src/index.ts
index e26d05fe25b35b7b218d3827775896e39ddc687c..193d48e71bfb343cd4ae153680d4590dc170c5ec 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,4 @@
 export * from "./base";
-export * from "./param/param-base";
 export * from "./param/param-definition";
 export * from "./param/param-domain";
 export * from "./param/params-equation";
@@ -23,7 +22,6 @@ export * from "./util/message";
 export * from "./util/log";
 export * from "./util/result";
 export * from "./util/resultelement";
-export * from "./util/pair";
 export * from "./util/interval";
 export * from "./util/observer";
 export * from "./util/iterator";
diff --git a/src/param/param-base.ts b/src/param/param-base.ts
deleted file mode 100644
index d847fd33dfda79fe787648be5e17d56a54208850..0000000000000000000000000000000000000000
--- a/src/param/param-base.ts
+++ /dev/null
@@ -1,420 +0,0 @@
-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 { ParamDomain, ParamDomainValue } from "./param-domain";
-import { INamedIterableValues, INumberIterator } from "./param-value-iterator";
-import { ParamValueMode } from "./param-value-mode";
-import { ParamValues } from "./param-values";
-
-/**
- * paramètre avec symbole et domaine de définition
- */
-// tslint:disable-next-line:max-classes-per-file
-export class BaseParam extends JalhydObject implements INubReference, INamedIterableValues, IObservable {
-    /**
-     * symbole
-     */
-    private _symbol: string;
-
-    /**
-     * domaine de définition
-     */
-    private _domain: ParamDomain;
-
-    /**
-     * valeur(s) prise(s)
-     */
-    private _paramValues: ParamValues;
-
-    /**
-     * implémentation par délégation de IObservable
-     */
-    private _observable: Observable;
-
-    constructor(symb: string, d: ParamDomain | ParamDomainValue, val?: number) {
-        super();
-        this._symbol = symb;
-
-        this._observable = new Observable();
-
-        this._paramValues = new ParamValues();
-        this._paramValues.setSingleValue(val);
-
-        if (d instanceof ParamDomain) {
-            this._domain = d;
-        } else {
-            this._domain = new ParamDomain(d as ParamDomainValue);
-        }
-
-        this.checkValue(val);
-    }
-
-    get symbol(): string {
-        return this._symbol;
-    }
-
-    public getDomain(): ParamDomain {
-        return this._domain;
-    }
-
-    public get interval(): Interval {
-        return this._domain.interval;
-    }
-
-    public get paramValues(): ParamValues {
-        if (this.isReferenceDefined) {
-            return this.referencedParamValues;
-        }
-        return this._paramValues;
-    }
-
-    /**
-     * gestion de la valeur
-     */
-
-    public get isDefined(): boolean {
-        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;
-        }
-
-        return this._paramValues.currentValue;
-    }
-
-    public get currentValue(): number {
-        return this.getValue();
-    }
-
-    public setValue(val: number, sender?: any) {
-        this.checkValue(val);
-        this._paramValues.currentValue = val;
-        this.notifyValueModified(sender);
-    }
-
-    public get uncheckedValue(): number {
-        return this._paramValues.uncheckedValue;
-    }
-
-    public checkValue(v: number) {
-        const sDomain = ParamDomainValue[this._domain.domain];
-
-        switch (this._domain.domain) {
-            case ParamDomainValue.ANY:
-                break;
-
-            case ParamDomainValue.POS:
-                if (v <= 0) {
-                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POS);
-                    f.extraVar.symbol = this.symbol;
-                    f.extraVar.value = v;
-                    throw f;
-                }
-                break;
-
-            case ParamDomainValue.POS_NULL:
-                if (v < 0) {
-                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POSNULL);
-                    f.extraVar.symbol = this.symbol;
-                    f.extraVar.value = v;
-                    throw f;
-                }
-                break;
-
-            case ParamDomainValue.NOT_NULL:
-                if (v === 0) {
-                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_NULL);
-                    f.extraVar.symbol = this.symbol;
-                    throw f;
-                }
-                break;
-
-            case ParamDomainValue.INTERVAL:
-                const min = this._domain.minValue;
-                const max = this._domain.maxValue;
-                if (v < min || v > max) {
-                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTERVAL);
-                    f.extraVar.symbol = this.symbol;
-                    f.extraVar.value = v;
-                    f.extraVar.minValue = min;
-                    f.extraVar.maxValue = max;
-                    throw f;
-                }
-                break;
-
-            default:
-                const e = new Message(MessageCode.ERROR_PARAMDOMAIN_INVALID);
-                e.extraVar.symbol = this.symbol;
-                e.extraVar.domain = sDomain;
-                throw e;
-        }
-    }
-
-    public checkMin(min: number): boolean {
-        return this.isMinMaxDomainValid(min) && (min < this._paramValues.max);
-    }
-
-    public checkMax(max: number): boolean {
-        return this.isMinMaxDomainValid(max) && (this._paramValues.min < max);
-    }
-
-    public checkStep(step: number): boolean {
-        return this.isMinMaxValid && this._paramValues.stepRefValue.intervalHasValue(step);
-    }
-
-    get isValueValid(): boolean {
-        try {
-            const v = this.getValue();
-            this.checkValue(v);
-            return true;
-        } catch (e) {
-            return false;
-        }
-    }
-
-    get isMinMaxValid(): boolean {
-        return this.checkMinMax(this._paramValues.min, this._paramValues.max);
-    }
-
-    public get isRangeValid(): boolean {
-        switch (this._paramValues.valueMode) {
-            case ParamValueMode.LISTE:
-                return this.isListValid;
-
-            case ParamValueMode.MINMAX:
-                return this.checkStep(this._paramValues.step);
-        }
-
-        // tslint:disable-next-line:max-line-length
-        throw new Error(`"BaseParam.isRangeValid() : valeur ${ParamValueMode[this._paramValues.valueMode]} de ParamValueMode non prise en compte`);
-    }
-
-    public get isValid() {
-        switch (this._paramValues.valueMode) {
-            case ParamValueMode.SINGLE:
-                return this.isValueValid;
-
-            case ParamValueMode.MINMAX:
-            case ParamValueMode.LISTE:
-                return this.isRangeValid;
-
-            case ParamValueMode.CALCUL:
-                return true;
-
-            case ParamValueMode.LINK:
-                if (!this.isReferenceDefined) {
-                    return false;
-                }
-
-                try {
-                    for (const v of this.valuesIterator) {
-                        this.checkValue(v);
-                    }
-                    return true;
-                } catch (e) {
-                    return false;
-                }
-        }
-
-        throw new Error(
-            // tslint:disable-next-line:max-line-length
-            `BaseParam.isValid() : valeur de ParamValueMode '${ParamValueMode[this._paramValues.valueMode]}' non prise en charge`
-        );
-    }
-
-    public get valueMode() {
-        return this._paramValues.valueMode;
-    }
-
-    public set valueMode(m: ParamValueMode) {
-        this._paramValues.valueMode = m;
-    }
-
-    // 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;
-        }
-    }
-
-    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;
-    }
-
-    get referencedValuesIterator(): INumberIterator {
-        return this._paramValues.referencedValuesIterator;
-    }
-
-    get referencedObject(): INamedIterableValues {
-        return this._paramValues.referencedObject;
-    }
-
-    // interface INamedIterableValues
-
-    public get valuesIterator(): INumberIterator {
-        if (this.isReferenceDefined) {
-            return this.referencedValuesIterator;
-        }
-        return this._paramValues.valuesIterator;
-    }
-
-    public get hasMultipleValues(): boolean {
-        return this._paramValues.hasMultipleValues;
-    }
-
-    public get name(): string {
-        return this._symbol;
-    }
-
-    public initValuesIterator(reverse: boolean = false): INumberIterator {
-        return this._paramValues.initValuesIterator(reverse);
-    }
-
-    public get hasNext(): boolean {
-        return this._paramValues.hasNext;
-    }
-
-    public next(): IteratorResult<number> {
-        return this._paramValues.next();
-    }
-
-    public [Symbol.iterator](): IterableIterator<number> {
-        return this._paramValues;
-    }
-
-    // interface IObservable
-
-    /**
-     * ajoute un observateur à la liste
-     */
-    public addObserver(o: Observer) {
-        this._observable.addObserver(o);
-    }
-
-    /**
-     * supprime un observateur de la liste
-     */
-    public removeObserver(o: Observer) {
-        this._observable.removeObserver(o);
-    }
-
-    /**
-     * notifie un événement aux observateurs
-     */
-    public notifyObservers(data: any, sender?: any) {
-        this._observable.notifyObservers(data, sender);
-    }
-
-    /**
-     * notification envoyée après la modification de la valeur du paramètre
-     */
-    private notifyValueModified(sender: any) {
-        this.notifyObservers(
-            {
-                action: "baseparamAfterValue",
-            }, sender
-        );
-    }
-
-    /**
-     * vérifie si un min/max est valide par rapport au domaine de définition
-     */
-    private isMinMaxDomainValid(v: number): boolean {
-        if (v === undefined) {
-            return false;
-        }
-
-        if (this._paramValues.valueMode === ParamValueMode.MINMAX) {
-            try {
-                this.checkValue(v);
-            } catch (e) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private checkMinMax(min: number, max: number): boolean {
-        return this.isMinMaxDomainValid(min) && this.isMinMaxDomainValid(max) && (min < max);
-    }
-
-    private get isListValid(): boolean {
-        if (this._paramValues.valueList === undefined) {
-            return false;
-        }
-
-        for (const v of this._paramValues.valueList) {
-            try {
-                this.checkValue(v);
-            } catch (e) {
-                return false;
-            }
-        }
-        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: number[]) {
-        if ("uid" in o) {
-            // if (o.uid in seenUids)
-            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-definition.ts b/src/param/param-definition.ts
index 43997761ffc4edf10e310ad740f1379b5ce47b0a..d38c0be764ae7780508980140596116da8b9d852 100644
--- a/src/param/param-definition.ts
+++ b/src/param/param-definition.ts
@@ -1,54 +1,106 @@
+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 { BaseParam } from "./param-base";
+import { INubReference, IReferencedNub } from "../value_ref/object_ref";
 import { ParamDomain, ParamDomainValue } from "./param-domain";
+import { INamedIterableValues, INumberIterator } from "./param-value-iterator";
 import { ParamValueMode } from "./param-value-mode";
+import { ParamValues } from "./param-values";
 
 /**
- * calculabilité du paramètre
+ * Calculabilité du paramètre
  */
 export enum ParamCalculability {
-    /**
-     * paramètre fixé (immuable, cad non modifiable après création)
-     */
+    /** paramètre fixé (immuable, cad non modifiable après création) */
     NONE,
-
-    /**
-     * paramètre libre (modifiable)
-     */
+    /** paramètre libre (modifiable) */
     FREE,
-
-    /**
-     * paramètre calculable analytiquement, par méthode de Newton, ...
-     */
+    /** paramètre calculable analytiquement, par méthode de Newton, ... */
     EQUATION,
-
-    /**
-     * paramètre calculable par dichotomie
-     */
+    /** paramètre calculable par dichotomie */
     DICHO
 }
 
 /**
- * définition d'un paramètre d'un noeud de calcul
+ * Paramètre avec symbole, domaine de définition, calculabilité
  */
-// tslint:disable-next-line:max-classes-per-file
-export class ParamDefinition extends BaseParam {
-    /**
-     * calculabilité
-     */
+export class ParamDefinition extends JalhydObject implements INubReference, INamedIterableValues, IObservable {
+
+    /** symbole */
+    private _symbol: string;
+
+    /** domaine de définition */
+    private _domain: ParamDomain;
+
+    /** calculabilité */
     private _calc: ParamCalculability;
 
-    constructor(s: string, d: ParamDomain | ParamDomainValue, val?: number) {
-        super(s, d, val);
+    /** valeur(s) prise(s) */
+    private _paramValues: ParamValues;
+
+    /** implémentation par délégation de IObservable */
+    private _observable: Observable;
+
+    constructor(symb: string, d: ParamDomain | ParamDomainValue, val?: number) {
+        super();
+        this._symbol = symb;
+        this._observable = new Observable();
+        this._paramValues = new ParamValues();
+        this._paramValues.setSingleValue(val);
         this._calc = ParamCalculability.FREE;
+
+        if (d instanceof ParamDomain) {
+            this._domain = d;
+        } else {
+            this._domain = new ParamDomain(d as ParamDomainValue);
+        }
+
+        this.checkValue(val);
+    }
+
+    get symbol(): string {
+        return this._symbol;
+    }
+
+    public getDomain(): ParamDomain {
+        return this._domain;
+    }
+
+    public get interval(): Interval {
+        return this._domain.interval;
+    }
+
+    public get paramValues(): ParamValues {
+        if (this.isReferenceDefined) {
+            return this.referencedParamValues;
+        }
+        return this._paramValues;
     }
 
+    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;
+        }
+
+        return this._calc;
+    }
+
+    set calculability(c: ParamCalculability) {
+        this._calc = c;
+    }
+
+    /** returns value or referenced value */
     get v(): number {
         if (this.isReferenceDefined) {
             const ro = this.referencedObject;
 
-            if (ro instanceof BaseParam) {
+            if (ro instanceof ParamDefinition) {
                 switch (this.referencedParamValues.valueMode) {
                     case ParamValueMode.CALCUL:
                         const r = this.referencedResult;
@@ -67,42 +119,296 @@ export class ParamDefinition extends BaseParam {
             return this.referencedExtraResult;
         }
 
-        return super.getValue();
+        return this.getValue();
     }
 
+    /** set value, with calculability control */
     set v(val: number) {
         if (this.calculability === ParamCalculability.NONE) {
             const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_FIXED);
             e.extraVar.symbol = this.symbol;
             throw e;
         }
-        super.setValue(val);
+        this.setValue(val);
     }
 
-    /*
-     * méthodes de calculabilité
-     */
-
     /**
-     * variable calculable par l'équation ?
+     * gestion de la valeur
      */
-    public isAnalytical(): boolean {
-        return this.calculability === ParamCalculability.EQUATION;
+
+    public get isDefined(): boolean {
+        return this._paramValues.isDefined;
     }
 
-    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);
+    public getValue(): number {
+        if (!this._paramValues.isDefined) {
+            const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED);
             e.extraVar.symbol = this.symbol;
             throw e;
         }
 
-        return this._calc;
+        return this._paramValues.currentValue;
     }
 
-    set calculability(c: ParamCalculability) {
-        this._calc = c;
+    public get currentValue(): number {
+        return this.getValue();
+    }
+
+    public setValue(val: number, sender?: any) {
+        this.checkValue(val);
+        this._paramValues.currentValue = val;
+        this.notifyValueModified(sender);
+    }
+
+    public get uncheckedValue(): number {
+        return this._paramValues.uncheckedValue;
+    }
+
+    public checkValue(v: number) {
+        const sDomain = ParamDomainValue[this._domain.domain];
+
+        switch (this._domain.domain) {
+            case ParamDomainValue.ANY:
+                break;
+
+            case ParamDomainValue.POS:
+                if (v <= 0) {
+                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POS);
+                    f.extraVar.symbol = this.symbol;
+                    f.extraVar.value = v;
+                    throw f;
+                }
+                break;
+
+            case ParamDomainValue.POS_NULL:
+                if (v < 0) {
+                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POSNULL);
+                    f.extraVar.symbol = this.symbol;
+                    f.extraVar.value = v;
+                    throw f;
+                }
+                break;
+
+            case ParamDomainValue.NOT_NULL:
+                if (v === 0) {
+                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_NULL);
+                    f.extraVar.symbol = this.symbol;
+                    throw f;
+                }
+                break;
+
+            case ParamDomainValue.INTERVAL:
+                const min = this._domain.minValue;
+                const max = this._domain.maxValue;
+                if (v < min || v > max) {
+                    const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTERVAL);
+                    f.extraVar.symbol = this.symbol;
+                    f.extraVar.value = v;
+                    f.extraVar.minValue = min;
+                    f.extraVar.maxValue = max;
+                    throw f;
+                }
+                break;
+
+            default:
+                const e = new Message(MessageCode.ERROR_PARAMDOMAIN_INVALID);
+                e.extraVar.symbol = this.symbol;
+                e.extraVar.domain = sDomain;
+                throw e;
+        }
+    }
+
+    public checkMin(min: number): boolean {
+        return this.isMinMaxDomainValid(min) && (min < this._paramValues.max);
+    }
+
+    public checkMax(max: number): boolean {
+        return this.isMinMaxDomainValid(max) && (this._paramValues.min < max);
+    }
+
+    public checkStep(step: number): boolean {
+        return this.isMinMaxValid && this._paramValues.stepRefValue.intervalHasValue(step);
+    }
+
+    get isValueValid(): boolean {
+        try {
+            const v = this.getValue();
+            this.checkValue(v);
+            return true;
+        } catch (e) {
+            return false;
+        }
+    }
+
+    get isMinMaxValid(): boolean {
+        return this.checkMinMax(this._paramValues.min, this._paramValues.max);
+    }
+
+    public get isRangeValid(): boolean {
+        switch (this._paramValues.valueMode) {
+            case ParamValueMode.LISTE:
+                return this.isListValid;
+
+            case ParamValueMode.MINMAX:
+                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`);
+    }
+
+    public get isValid() {
+        switch (this._paramValues.valueMode) {
+            case ParamValueMode.SINGLE:
+                return this.isValueValid;
+
+            case ParamValueMode.MINMAX:
+            case ParamValueMode.LISTE:
+                return this.isRangeValid;
+
+            case ParamValueMode.CALCUL:
+                return true;
+
+            case ParamValueMode.LINK:
+                if (!this.isReferenceDefined) {
+                    return false;
+                }
+
+                try {
+                    for (const v of this.valuesIterator) {
+                        this.checkValue(v);
+                    }
+                    return true;
+                } catch (e) {
+                    return false;
+                }
+        }
+
+        throw new Error(
+            // tslint:disable-next-line:max-line-length
+            `ParamDefinition.isValid() : valeur de ParamValueMode '${ParamValueMode[this._paramValues.valueMode]}' non prise en charge`
+        );
+    }
+
+    public get valueMode() {
+        return this._paramValues.valueMode;
+    }
+
+    public set valueMode(m: ParamValueMode) {
+        this._paramValues.valueMode = m;
+    }
+
+    // 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;
+        }
+    }
+
+    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;
+    }
+
+    get referencedValuesIterator(): INumberIterator {
+        return this._paramValues.referencedValuesIterator;
+    }
+
+    get referencedObject(): INamedIterableValues {
+        return this._paramValues.referencedObject;
+    }
+
+    // interface INamedIterableValues
+
+    public get valuesIterator(): INumberIterator {
+        if (this.isReferenceDefined) {
+            return this.referencedValuesIterator;
+        }
+        return this._paramValues.valuesIterator;
+    }
+
+    public get hasMultipleValues(): boolean {
+        return this._paramValues.hasMultipleValues;
+    }
+
+    public get name(): string {
+        return this._symbol;
+    }
+
+    public initValuesIterator(reverse: boolean = false): INumberIterator {
+        return this._paramValues.initValuesIterator(reverse);
+    }
+
+    public get hasNext(): boolean {
+        return this._paramValues.hasNext;
+    }
+
+    public next(): IteratorResult<number> {
+        return this._paramValues.next();
+    }
+
+    public [Symbol.iterator](): IterableIterator<number> {
+        return this._paramValues;
+    }
+
+    // interface IObservable
+
+    /**
+     * ajoute un observateur à la liste
+     */
+    public addObserver(o: Observer) {
+        this._observable.addObserver(o);
+    }
+
+    /**
+     * supprime un observateur de la liste
+     */
+    public removeObserver(o: Observer) {
+        this._observable.removeObserver(o);
+    }
+
+    /**
+     * notifie un événement aux observateurs
+     */
+    public notifyObservers(data: any, sender?: any) {
+        this._observable.notifyObservers(data, sender);
+    }
+
+    /**
+     * variable calculable par l'équation ?
+     */
+    public isAnalytical(): boolean {
+        return this.calculability === ParamCalculability.EQUATION;
     }
 
     public clone(): ParamDefinition {
@@ -110,4 +416,76 @@ export class ParamDefinition extends BaseParam {
         res._calc = this._calc;
         return res;
     }
+
+    /**
+     * notification envoyée après la modification de la valeur du paramètre
+     */
+    private notifyValueModified(sender: any) {
+        this.notifyObservers(
+            { action: "paramdefinitionAfterValue" }, sender
+        );
+    }
+
+    /**
+     * vérifie si un min/max est valide par rapport au domaine de définition
+     */
+    private isMinMaxDomainValid(v: number): boolean {
+        if (v === undefined) {
+            return false;
+        }
+
+        if (this._paramValues.valueMode === ParamValueMode.MINMAX) {
+            try {
+                this.checkValue(v);
+            } catch (e) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private checkMinMax(min: number, max: number): boolean {
+        return this.isMinMaxDomainValid(min) && this.isMinMaxDomainValid(max) && (min < max);
+    }
+
+    private get isListValid(): boolean {
+        if (this._paramValues.valueList === undefined) {
+            return false;
+        }
+
+        for (const v of this._paramValues.valueList) {
+            try {
+                this.checkValue(v);
+            } catch (e) {
+                return false;
+            }
+        }
+        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: number[]) {
+        if ("uid" in o) {
+            // if (o.uid in seenUids)
+            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-values.ts b/src/param/param-values.ts
index 7fe5049d89ef9d750eddc9c6f9ea186837b16f47..0b285d74a16a9cedccd1c5c424060b5d059435ff 100644
--- a/src/param/param-values.ts
+++ b/src/param/param-values.ts
@@ -1,6 +1,5 @@
-import { Result } from "..";
+import { Interval, Result } from "..";
 import { DefinedNumber } from "../util/definedvalue";
-import { Pair } from "../util/pair";
 import { INubReference, IReferencedNub, NubReference } from "../value_ref/object_ref";
 import { INamedIterableValues, INumberIterator, IterableValues, ParamValueIterator } from "./param-value-iterator";
 import { ParamValueMode } from "./param-value-mode";
@@ -202,9 +201,9 @@ export class ParamValues implements INubReference, IterableValues {
         this._valueMode = ParamValueMode.MINMAX;
     }
 
-    public get stepRefValue(): Pair {
+    public get stepRefValue(): Interval {
         this.checkValueMode(ParamValueMode.MINMAX);
-        return new Pair(1e-9, this._maxValue - this._minValue);
+        return new Interval(1e-9, this._maxValue - this._minValue);
     }
 
     public get step() {
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index ce52378ad39882307008205a533d666d82e0c8e2..697c782fe37e54373872eed9f6e1d3e0c205ec2d 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -4,7 +4,7 @@ import { Result } from "../util/result";
 import { ParallelStructureParams } from "./parallel_structure_params";
 import { Structure } from "./structure";
 
-import { BaseParam } from "../param/param-base";
+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";
@@ -247,7 +247,7 @@ export class ParallelStructure extends Nub {
     public getReferencedParamValues(desc: string): ParamValues {
         try {
             const ro = this.getReferencedObject(desc);
-            if (ro instanceof BaseParam) {
+            if (ro instanceof ParamDefinition) {
                 return ro.paramValues;
             }
             return undefined;
diff --git a/src/util/interval.ts b/src/util/interval.ts
index 8b2a78a1622f4d4dbe0a2626bcfc7940bf69aa2a..8e83f33aac0c33676932de80b474e7fe183258cf 100644
--- a/src/util/interval.ts
+++ b/src/util/interval.ts
@@ -1,12 +1,49 @@
 import { Message, MessageCode } from "./message";
-import { Pair } from "./pair";
 
 /**
- * couple de valeurs ordonnées
+ * Couple de valeurs ordonnées
  */
-export class Interval extends Pair {
-    constructor(bound1: number, bound2: number) {
-        super(bound1, bound2);
+export class Interval {
+
+    constructor(public val1: number, public val2: number) { }
+
+    /** @TODO utile ? */
+    public setValues(v1: number, v2: number) {
+        this.val1 = v1;
+        this.val2 = v2;
+    }
+
+    /** "constructeur" par copie */
+    public setInterval(i: Interval) {
+        this.setValues(i.val1, i.val2);
+    }
+
+    get min() {
+        return Math.min(this.val1, this.val2);
+    }
+
+    get max() {
+        return Math.max(this.val1, this.val2);
+    }
+
+    get length(): number {
+        return this.max - this.min;
+    }
+
+    public intervalHasValue(v: number) {
+        return this.min <= v && v <= this.max;
+    }
+
+    public intersect(i: Interval): Interval {
+        const min = Math.max(this.min, i.min);
+        const max = Math.min(this.max, i.max);
+
+        let intersection = null;
+        if (min <= max) {
+            intersection = new Interval(min, max);
+        } // else no intersection
+
+        return intersection;
     }
 
     public checkValue(v: number) {
@@ -14,7 +51,6 @@ export class Interval extends Pair {
             const e = new Message(MessageCode.ERROR_INTERVAL_UNDEF);
             throw e;
         }
-
         if (!this.intervalHasValue(v)) {
             const e = new Message(MessageCode.ERROR_INTERVAL_OUTSIDE);
             e.extraVar.value = v;
@@ -23,17 +59,7 @@ export class Interval extends Pair {
         }
     }
 
-    get length(): number {
-        return this.max - this.min;
-    }
-
-    public intersect(i: Interval): Interval {
-        const min = Math.max(this.min, i.min);
-        const max = Math.min(this.max, i.max);
-        return new Interval(min, max);
-    }
-
-    public setBounds(i: Pair) {
-        this.setPair(i);
+    public toString(): string {
+        return "[" + this.min + "," + this.max + "]";
     }
 }
diff --git a/src/util/pair.ts b/src/util/pair.ts
deleted file mode 100644
index 1ea1b6b35ab3affcfe0987a2db1825d5e9cb76ea..0000000000000000000000000000000000000000
--- a/src/util/pair.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * couple de valeurs non ordonnées
- */
-export class Pair {
-    protected _val1: number;
-    protected _val2: number;
-
-    constructor(v1: number, v2: number) {
-        this.setValues(v1, v2);
-    }
-
-    get val1() {
-        return this._val1;
-    }
-
-    get val2() {
-        return this._val2;
-    }
-
-    public setValues(v1: number, v2: number) {
-        this._val1 = v1;
-        this._val2 = v2;
-    }
-
-    public setPair(p: Pair) {
-        this.setValues(p._val1, p._val2);
-    }
-
-    public undefine() {
-        this._val1 = undefined;
-        this._val2 = undefined;
-    }
-
-    get min() {
-        return Math.min(this._val1, this._val2);
-    }
-
-    get max() {
-        return Math.max(this._val1, this._val2);
-    }
-
-    public intervalHasValue(v: number) {
-        return this.min <= v && v <= this.max;
-    }
-
-    public toString(): string {
-        return "[" + this.min + "," + this.max + "]";
-    }
-}