diff --git a/spec/solveur/solveur.spec.ts b/spec/solveur/solveur.spec.ts
index 978dab0bb14dfcd6f2d7af6a8b050598ceb55099..680d44a9207675b32e22c77f4c09475e69fb94a6 100644
--- a/spec/solveur/solveur.spec.ts
+++ b/spec/solveur/solveur.spec.ts
@@ -25,11 +25,9 @@ describe("solveur multi-modules", () => {
         pn.prms.DHT.defineReference(pc, "DH");
         pp.prms.DH.defineReference(pn, "DH");
         // solveur
-        const s = new Solveur(
-            new SolveurParams(pc.prms.Z1, 324.907),
-            false
-        );
-        s.properties.setPropValue("nubToCalculate", pp.uid);
+        const s = new Solveur(new SolveurParams(324.907), false);
+        s.nubToCalculate = pp;
+        s.searchedParameter = pc.prms.Z1;
         const res = s.CalcSerie();
         expect(res.vCalc).toBeCloseTo(2.156, 3);
     });
@@ -50,12 +48,9 @@ describe("solveur multi-modules", () => {
         pn.prms.DHT.defineReference(pc, "DH");
         pp.prms.DH.defineReference(pn, "DH");
         // solveur
-        const s = new Solveur(
-            new SolveurParams(pc.prms.Z1, 324.907),
-            false
-        );
+        const s = new Solveur(new SolveurParams(324.907), false);
         expect(() => {
-            s.properties.setPropValue("nubToCalculate", pp.uid);
+            s.nubToCalculate = pp;
         }).toThrowError("Solveur.update(): Nub to calculate must not have multiple values");
     });
 
@@ -73,13 +68,11 @@ describe("solveur multi-modules", () => {
         Session.getInstance().registerNub(pn);
         Session.getInstance().registerNub(pp);
         // solveur
-        const s = new Solveur(
-            new SolveurParams(pc.prms.Z1, 324.907),
-            false
-        );
+        const s = new Solveur(new SolveurParams(324.907), false);
+        s.searchedParameter = pc.prms.Z1;
         expect(() => {
-            s.properties.setPropValue("nubToCalculate", pp.uid);
-        }).toThrowError("Solveur.update(): Nub to calculate is not linked to result of X's parent Nub");
+            s.nubToCalculate = pp;
+        }).toThrowError("Solveur.update(): Nub to calculate is not linked to result of searchedParameter parent Nub");
     });
 
     it("test 4: PAB Chute <= PAB Nombre <= PAB Puissance, redéfinition des paramètres", () => {
@@ -97,14 +90,11 @@ describe("solveur multi-modules", () => {
         pn.prms.DHT.defineReference(pc, "DH");
         pp.prms.DH.defineReference(pn, "DH");
         // solveur
-        const s = new Solveur(
-            // new SolveurParams(pc.prms.Z1, 324.907),
-            new SolveurParams(pc.prms.Z2, 123),
-            false
-        );
-        s.properties.setPropValue("nubToCalculate", pp.uid);
+        const s = new Solveur(new SolveurParams(123), false);
+        s.nubToCalculate = pp;
+        s.searchedParameter = pc.prms.Z2;
         // defining values a-posteriori
-        s.prms.X = pc.prms.Z1;
+        s.searchedParameter = pc.prms.Z1;
         s.prms.Ytarget.singleValue = 324.907;
         s.prms.Xinit.singleValue = 1.9;
         const res = s.CalcSerie();
@@ -126,11 +116,9 @@ describe("solveur multi-modules", () => {
         pn.prms.DHT.defineReference(pc, "DH");
         pp.prms.DH.defineReference(pn, "DH");
         // solveur
-        const s = new Solveur(
-            new SolveurParams(pc.prms.Z1),
-            false
-        );
-        s.properties.setPropValue("nubToCalculate", pp.uid);
+        const s = new Solveur(new SolveurParams(), false);
+        s.nubToCalculate = pp;
+        s.searchedParameter = pc.prms.Z1;
         s.prms.Ytarget.setValues(100, 500, 50);
         const res = s.CalcSerie();
         const expectedValues = [ 1.01, 1.264, 1.519, 1.774, 2.029, 2.284, 2.539, 2.794, 3.048 ];
@@ -140,4 +128,29 @@ describe("solveur multi-modules", () => {
         }
     });
 
+    it("test 6: target nubs / searched params lists", () => {
+        // contexte
+        const pc = new PabChute(new PabChuteParams(2, 0.5, 666));
+        pc.calculatedParam = pc.prms.DH;
+        const pn = new PabNombre(new PabNombreParams(666, 10, 666));
+        pn.calculatedParam = pn.prms.DH;
+        const pp = new PabPuissance(new PabPuissanceParams(666, 0.1, 0.5, 666));
+        pp.calculatedParam = pp.prms.PV;
+        Session.getInstance().clear();
+        Session.getInstance().registerNub(pc);
+        Session.getInstance().registerNub(pn);
+        Session.getInstance().registerNub(pp);
+        pn.prms.DHT.defineReference(pc, "DH");
+        pp.prms.DH.defineReference(pn, "DH");
+        // check lists
+        const targetNubs = Session.getInstance().getDownstreamNubs();
+        expect(targetNubs.length).toBe(2); // pn, pp
+        const searchedParamsPp = Solveur.getDependingNubsSearchableParams(pp);
+        expect(searchedParamsPp.length).toBe(3); // pc.Z1, pc.Z2, pn.N
+        expect(searchedParamsPp.map((p) => p.symbol)).toEqual([ "N", "Z1", "Z2" ]);
+        const searchedParamsPn = Solveur.getDependingNubsSearchableParams(pn);
+        expect(searchedParamsPn.length).toBe(2); // pc.Z1, pc.Z2
+        expect(searchedParamsPn.map((p) => p.symbol)).toEqual([ "Z1", "Z2" ]);
+    });
+
 });
diff --git a/src/nub.ts b/src/nub.ts
index d35727caa0c395064d91b4a2dddf4c76e358fa14..e644b1af74281716166b8d946131822d08e992ff 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -672,7 +672,7 @@ export abstract class Nub extends ComputeNode implements IObservable {
      * without following links (stops when it finds a Nub that has to
      * be calculated). Used to trigger chain calculation.
      */
-    public getRequiredNubs(visited: string[] = []) {
+    public getRequiredNubs(visited: string[] = []): Nub[] {
         const requiredNubs: Nub[] = [];
         // prevent loops
         if (! visited.includes(this.uid)) {
@@ -693,6 +693,19 @@ export abstract class Nub extends ComputeNode implements IObservable {
         return requiredNubs;
     }
 
+    /**
+     * Returns all Nubs whose results are required by the given one,
+     * following links. Used by Solveur.
+     */
+    public getRequiredNubsDeep(visited: string[] = []): Nub[] {
+        let requiredNubs: Nub[] = this.getRequiredNubs(visited);
+        for (const rn of requiredNubs) {
+            requiredNubs = requiredNubs.concat(rn.getRequiredNubsDeep(visited));
+        }
+        // @TODO deduplicate ?
+        return requiredNubs;
+    }
+
     /**
      * Returns all Nubs whose parameters or results are targetted
      * by the given one.
diff --git a/src/session.ts b/src/session.ts
index bc352c1866d9bd279f11b2f521bb1fe22c12ba58..9bb601eab6575f84aa884ddf933dbd55922a619b 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -66,6 +66,8 @@ import { JetParams } from "./devalaison/jet_params";
 import { Pente } from "./pente";
 import { PenteParams } from "./pente_params";
 import { Bief } from "./remous/bief";
+import { Solveur } from "./solveur/solveur";
+import { SolveurParams } from "./solveur/solveur_params";
 
 export class Session {
 
@@ -560,6 +562,13 @@ export class Session {
                 );
                 break;
 
+            case CalculatorType.Solveur:
+                // const nubToCalc: BiefRegime = params.getPropValue("nubToCalculate");
+                nub = new Solveur(
+                    new SolveurParams(undefined)
+                );
+                break;
+
             default:
                 throw new Error(
                     `Session.createNub() : type de module '${CalculatorType[calcType]}' non pris en charge`
@@ -602,7 +611,7 @@ export class Session {
      * @param includeValuesLinks if true, even Nubs targetting non-calculated non-modified parameters
      *      will be considered dependent @see jalhyd#98
      */
-    public getDependingNubs(uid: string, symbol?: string, includeValuesLinks: boolean = false) {
+    public getDependingNubs(uid: string, symbol?: string, includeValuesLinks: boolean = false): Nub[] {
         const dependingNubs: Nub[] = [];
         for (const n of this._nubs) {
             if (n.uid !== uid && n.resultDependsOnNub(uid, [], symbol, includeValuesLinks)) {
@@ -612,6 +621,20 @@ export class Session {
         return dependingNubs;
     }
 
+    /**
+     * Returns all Nubs depending on the result of at least one other Nub.
+     * Used by Solveur to find available "target" nubs to calculate.
+     */
+    public getDownstreamNubs(): Nub[] {
+        const downstreamNubs: Nub[] = [];
+        for (const n of this._nubs) {
+            if (n.getRequiredNubs().length > 0) {
+                downstreamNubs.push(n);
+            }
+        }
+        return downstreamNubs;
+    }
+
     /**
      * Returns a list of nub/symbol couples, that can be linked to the given
      * parameter, among all current nubs
diff --git a/src/solveur/solveur.ts b/src/solveur/solveur.ts
index 8c4a0e3f60f29a6a18011f866d51f4249db4d69d..a04c81d40027f2d7988e2943e068747bae00a8fb 100644
--- a/src/solveur/solveur.ts
+++ b/src/solveur/solveur.ts
@@ -1,6 +1,7 @@
 import { CalculatorType } from "../compute-node";
 import { Nub } from "../nub";
-import { ParamCalculability } from "../param/param-definition";
+import { ParamCalculability, ParamDefinition } from "../param/param-definition";
+import { ParamValueMode } from "../param/param-value-mode";
 import { Session } from "../session";
 import { Observer } from "../util/observer";
 import { Result } from "../util/result";
@@ -8,6 +9,26 @@ import { SolveurParams } from "./solveur_params";
 
 export class Solveur extends Nub implements Observer {
 
+    /**
+     * Finds all parameters whose value can be searched for by dichotomy, for
+     * a given value of calculated param of given Nub
+     * @param nub Nub calculated by Solveur
+     */
+    public static getDependingNubsSearchableParams(nub: Nub): ParamDefinition[] {
+        const searchableParams: ParamDefinition[] = [];
+        if (nub !== undefined) {
+            const upstreamNubs = nub.getRequiredNubsDeep();
+            for (const un of upstreamNubs) {
+                for (const p of un.parameterIterator) {
+                    if (! [ ParamValueMode.CALCUL, ParamValueMode.LINK ].includes(p.valueMode)) {
+                        searchableParams.push(p);
+                    }
+                }
+            }
+        }
+        return searchableParams;
+    }
+
     constructor(prms: SolveurParams, dbg: boolean = false)  {
         super(prms, dbg);
         this._calcType = CalculatorType.Solveur;
@@ -15,6 +36,8 @@ export class Solveur extends Nub implements Observer {
         this.prms.addObserver(this);
         // UID of Session Nub to calculate, the result of the which must be this.prms.Ytarget.singleValue
         this.properties.setPropValue("nubToCalculate", "");
+        // UID of Session Nub / symbol of source parameter to vary (the "searched" parameter)
+        this.properties.setPropValue("searchedParameter", "");
         // calculated param should always be pseudo-parameter "X" (the one whose value we're looking for)
         this._defaultCalculatedParam = prms.X;
         this.resetDefaultCalculatedParam();
@@ -27,16 +50,54 @@ export class Solveur extends Nub implements Observer {
     /** finds the Nub to calculate by its UID */
     public get nubToCalculate(): Nub {
         let nub: Nub;
-        const nubUID = this._props.getPropValue("nubToCalculate");
+        const nubUID: string = this._props.getPropValue("nubToCalculate");
         if (nubUID !== undefined && nubUID !== "") {
             nub = Session.getInstance().findNubByUid(nubUID);
             if (nub === undefined) {
-                throw new Error(`Solveur: cannot find Nub ${nubUID} in session`);
+                throw new Error(`Solveur.get nubToCalculate(): cannot find Nub ${nubUID} in session`);
             }
         }
         return nub;
     }
 
+    /** defines the Nub to calculate by setting property "nubToCalculate" to the UID of the given Nub */
+    public set nubToCalculate(n: Nub) {
+        this.properties.setPropValue("nubToCalculate", n.uid);
+    }
+
+    /** finds the source parameter whose value we're looking for, by its Nub UID / symbol */
+    public get searchedParameter(): ParamDefinition {
+        let p: ParamDefinition;
+        const nubUIDAndSymbol: string = this._props.getPropValue("searchedParameter");
+        if (nubUIDAndSymbol !== undefined && nubUIDAndSymbol !== "") {
+            const slashPos = nubUIDAndSymbol.indexOf("/");
+            const nubUID = nubUIDAndSymbol.substring(0, slashPos);
+            const paramSymbol = nubUIDAndSymbol.substring(slashPos + 1);
+            // console.log("(i) searched param Nub UID / symbol :", nubUID, paramSymbol);
+            if (nubUID) {
+                const nub: Nub = Session.getInstance().findNubByUid(nubUID);
+                if (nub === undefined) {
+                    throw new Error(`Solveur.get searchedParameter(): cannot find Nub ${nubUID} in session`);
+                }
+                if (paramSymbol) {
+                    p = nub.getParameter(paramSymbol);
+                    if (p === undefined) {
+                        throw new Error(`Solveur.get searchedParameter(): cannot find Parameter ${paramSymbol} in Nub`);
+                    }
+                }
+            }
+        }
+        return p;
+    }
+
+    /**
+     * defines the searched parameter by setting property "searchedParameter" to the UID of the
+     * parameter's Nub / the parameter's symbol
+     */
+    public set searchedParameter(p: ParamDefinition) {
+        this.properties.setPropValue("searchedParameter", p.nubUid + "/" + p.symbol);
+    }
+
     public CalcSerie(rInit?: number): Result {
         // affect initial value of X for Dichotomie search
         this.prms.X.singleValue = this.prms.Xinit.currentValue;
@@ -56,7 +117,7 @@ export class Solveur extends Nub implements Observer {
         // set the Y value we have to obtain
         this.prms.Y.v = this.prms.Ytarget.v;
         // set the current value of X, determined by Dichotomie, on the upstream Nub
-        this.prms.Xsource.singleValue = this.prms.X.v;
+        this.searchedParameter.singleValue = this.prms.X.v;
         // calculate Nubs chain
         const res = this.nubToCalculate.CalcSerie();
         return res;
@@ -71,16 +132,31 @@ export class Solveur extends Nub implements Observer {
 
     // interface Observer
     public update(sender: any, data: any): void {
-        // console.log("Solveur.update()", sender.constructor.name, data);
         if (data.action === "propertyChange") {
-            if (data.name === "nubToCalculate") {
+            if (data.name === "nubToCalculate" || data.name === "searchedParameter") {
                 const n = this.nubToCalculate;
-                if (n !== undefined) {
-                    if (! n.dependsOnNubResult(this.prms.Xsource.parentNub)) {
-                        throw new Error("Solveur.update(): Nub to calculate is not linked to result of X's parent Nub");
+                const p = this.searchedParameter;
+                if (n !== undefined && p !== undefined) {
+                    if (! n.dependsOnNubResult(p.parentNub)) {
+                        throw new Error(
+                            "Solveur.update(): Nub to calculate is not linked to result of searchedParameter parent Nub"
+                        );
                     }
-                    if (n.resultHasMultipleValues()) {
-                        throw new Error("Solveur.update(): Nub to calculate must not have multiple values");
+                }
+                if (data.name === "nubToCalculate") {
+                    if (n !== undefined) {
+                        if (n.resultHasMultipleValues()) {
+                            throw new Error("Solveur.update(): Nub to calculate must not have multiple values");
+                        }
+                    }
+                }
+                if (data.name === "searchedParameter") {
+                    if (p !== undefined) {
+                        if (p.valueMode !== ParamValueMode.SINGLE) {
+                            throw new Error("Solveur.update(): searched parameter X must be in SINGLE mode");
+                        }
+                        // update pseudo-parameter X
+                        this.prms.setX(p);
                     }
                 }
             }
diff --git a/src/solveur/solveur_params.ts b/src/solveur/solveur_params.ts
index d3f8a41009eaa25ef03b3e4a62f62d169ecc7e8c..dee786bd1e72e2a6d12ccf907f78e293b6b5659d 100644
--- a/src/solveur/solveur_params.ts
+++ b/src/solveur/solveur_params.ts
@@ -12,9 +12,6 @@ export class SolveurParams extends ParamsEquation implements IObservable {
     /** X : paramètre à faire varier par Dichotomie, dont la valeur sera reportée dans paramètre du Nub amont */
     private _X: ParamDefinition;
 
-    /** X : pointeur sur le paramètre du Nub amont */
-    private _Xsource: ParamDefinition;
-
     /** Y : pseudo-paramètre à calculer, pour la dichotomie (déclenchera en fait le calcul du Nub aval) */
     private _Y: ParamDefinition;
 
@@ -27,19 +24,17 @@ export class SolveurParams extends ParamsEquation implements IObservable {
     /** implémentation de IObservable par délégation */
     private _observable: Observable;
 
-    constructor(X?: ParamDefinition, rYtarget?: number, rXinit?: number) {
+    /**
+     * Nub to calculate and searched parameter must be set through Solveur properties,
+     * or .nubToCalculate() and .searchedParameter() setters
+     * @param rYtarget value we want to obtain for Y
+     * @param rXinit initial value f searched parameter; will be overwritten as soon
+     *               as Solveur's property "searchedParam" is updated
+     */
+    constructor(rYtarget?: number, rXinit?: number) {
         super();
         this._observable = new Observable();
-        let xInitVal = rXinit;
-        this._Xinit = new ParamDefinition(this, "Xinit", ParamDomainValue.ANY);
-        if (X !== undefined) {
-            // initial value for X : if not given, use X's singleValue
-            if (rXinit === undefined) {
-                xInitVal = X.singleValue;
-            }
-            X.singleValue = xInitVal;
-            this.X = X;
-        }
+        this._Xinit = new ParamDefinition(this, "Xinit", ParamDomainValue.ANY, undefined, rXinit);
         this._Ytarget = new ParamDefinition(this, "Ytarget", ParamDomainValue.ANY, undefined, rYtarget);
         this._Y = new ParamDefinition(this, "Y", ParamDomainValue.ANY);
 
@@ -52,9 +47,7 @@ export class SolveurParams extends ParamsEquation implements IObservable {
         return this._X;
     }
 
-    /** update parameter to vary; copies the parameter to _Xsource and updates pseudo-parameter _X */
-    public set X(X: ParamDefinition) {
-        this._Xsource = X;
+    public setX(X: ParamDefinition) {
         // copy of real X, to be used by Dichotomie() that will look for its value
         this._X = new ParamDefinition(this, "X", X.domain, X.unit, X.singleValue, undefined, false);
         // Update Xinit
@@ -71,10 +64,6 @@ export class SolveurParams extends ParamsEquation implements IObservable {
         }, this);
     }
 
-    public get Xsource(): ParamDefinition {
-        return this._Xsource;
-    }
-
     public get Y(): ParamDefinition {
         return this._Y;
     }