Skip to content
Snippets Groups Projects
session.ts 35.6 KiB
Newer Older
import { isNumeric } from "./base";
import { CalculatorType, SectionType } from "./compute-node";
import { config } from "./config";
import { LCMaterial } from "./lc-material";
import { LinkedValue } from "./linked-value";
David Dorchies's avatar
David Dorchies committed
import { Nub } from "./nub";
import { ParamDefinition } from "./param/param-definition";
import { Props } from "./props";
import { SessionSettings } from "./session_settings";
David Dorchies's avatar
David Dorchies committed
// Calculettes
import { Grille, GrilleProfile, GrilleType } from "./devalaison/grille";
import { GrilleParams } from "./devalaison/grille_params";
import { Jet } from "./devalaison/jet";
import { JetParams } from "./devalaison/jet_params";
import { ConcentrationBlocs } from "./macrorugo/concentration_blocs";
import { ConcentrationBlocsParams } from "./macrorugo/concentration_blocs_params";
import { MacroRugo } from "./macrorugo/macrorugo";
David Dorchies's avatar
David Dorchies committed
import { MacrorugoCompound } from "./macrorugo/macrorugo_compound";
import { MacrorugoCompoundParams } from "./macrorugo/macrorugo_compound_params";
import { MacrorugoParams } from "./macrorugo/macrorugo_params";
import { MRCInclination } from "./macrorugo/mrc-inclination";
import { SPP, SPPOperation } from "./math/spp";
import { SPPParams } from "./math/spp_params";
import { Trigo, TrigoOperation, TrigoUnit } from "./math/trigo";
import { TrigoParams } from "./math/trigo_params";
import { YAXB } from "./math/yaxb";
import { YAXBParams } from "./math/yaxb_params";
import { YAXN } from "./math/yaxn";
import { YAXNParams } from "./math/yaxn_params";
import { Bief } from "./open-channel/bief";
import { BiefParams, BiefRegime } from "./open-channel/bief_params";
import { MethodeResolution } from "./open-channel/methode-resolution";
import { Pente } from "./open-channel/pente";
import { PenteParams } from "./open-channel/pente_params";
import { RegimeUniforme } from "./open-channel/regime_uniforme";
import { CourbeRemous } from "./open-channel/remous";
import { CourbeRemousParams } from "./open-channel/remous_params";
import { cSnCirc } from "./open-channel/section/section_circulaire";
import { ParamsSectionCirc } from "./open-channel/section/section_circulaire_params";
import { SectionParametree } from "./open-channel/section/section_parametree";
import { cSnPuiss } from "./open-channel/section/section_puissance";
import { ParamsSectionPuiss } from "./open-channel/section/section_puissance_params";
import { cSnRectang } from "./open-channel/section/section_rectang";
import { ParamsSectionRectang } from "./open-channel/section/section_rectang_params";
import { cSnTrapez } from "./open-channel/section/section_trapez";
import { ParamsSectionTrapez } from "./open-channel/section/section_trapez_params";
import { acSection } from "./open-channel/section/section_type";
mathias.chouet's avatar
mathias.chouet committed
import { CloisonAval } from "./pab/cloison_aval";
import { CloisonsAvalParams } from "./pab/cloison_aval_params";
import { Cloisons } from "./pab/cloisons";
import { CloisonsParams } from "./pab/cloisons_params";
import { Pab } from "./pab/pab";
import { PabChute } from "./pab/pab_chute";
import { PabChuteParams } from "./pab/pab_chute_params";
import { PabDimension } from "./pab/pab_dimension";
import { PabDimensionParams } from "./pab/pab_dimensions_params";
import { PabNombre } from "./pab/pab_nombre";
import { PabNombreParams } from "./pab/pab_nombre_params";
import { PabParams } from "./pab/pab_params";
import { PabPuissance } from "./pab/pab_puissance";
import { PabPuissanceParams } from "./pab/pab_puissance_params";
import { ConduiteDistrib } from "./pipe_flow/cond_distri";
import { ConduiteDistribParams } from "./pipe_flow/cond_distri_params";
import { LechaptCalmon } from "./pipe_flow/lechaptcalmon";
import { LechaptCalmonParams } from "./pipe_flow/lechaptcalmon_params";
import { Solveur } from "./solveur/solveur";
import { SolveurParams } from "./solveur/solveur_params";
import { Dever } from "./structure/dever";
import { DeverParams } from "./structure/dever_params";
import { CreateStructure } from "./structure/factory_structure";
import { ParallelStructure } from "./structure/parallel_structure";
import { ParallelStructureParams } from "./structure/parallel_structure_params";
import { LoiDebit, StructureType } from "./structure/structure_props";
import { Par, ParType } from "./par/par";
import { ParParams } from "./par/par_params";
matcho's avatar
matcho committed
import { ParSimulation } from "./par/par_simulation";
import { ParSimulationParams } from "./par/par_simulation_params";
import { FishSpecies } from "./verification/fish_species";
import { Espece } from "./verification/espece";
import { EspeceParams } from "./verification/espece_params";
import { Verificateur } from "./verification/verificateur";
export class Session {
David Dorchies's avatar
David Dorchies committed

    /** correspondance entre les noms des propriétés et les enum associés */
    public static enumFromProperty: any = {
        loiDebit: LoiDebit,
        methodeResolution: MethodeResolution,
        material: LCMaterial,
        gridProfile: GrilleProfile,
        gridType: GrilleType,
        regime: BiefRegime,
        trigoOperation: TrigoOperation,
        trigoUnit: TrigoUnit,
        sppOperation: SPPOperation,
        nodeType: SectionType,
        calcType: CalculatorType,
        structureType: StructureType,
        inclinedApron: MRCInclination,
        parType: ParType,
        species: FishSpecies
    public static getInstance(): Session {
        if (Session._instance === undefined) {
            Session._instance = new Session();
David Dorchies's avatar
David Dorchies committed
        }
        return Session._instance;
David Dorchies's avatar
David Dorchies committed
    }
    /**
     * Returns a copy of given map, inverting enum keys and values
     */
    public static invertEnumKeysAndValuesInProperties(stringProps: any, forceNumbers: boolean = false) {
        const res = JSON.parse(JSON.stringify(stringProps)); // clone
        for (const k in res) {
            if (!forceNumbers || !isNumeric(res[k])) {
                if (Object.keys(Session.enumFromProperty).includes(k)) {
                    const enumClass = Session.enumFromProperty[k];
                    res[k] = enumClass[res[k]];
    /** instance pour le pattern singleton */
    private static _instance: Session;
    /** free documentation text, in Markdown format, to save into session file (optional) */
    public documentation = "";

    /** Nubs de la session */
    private _nubs: Nub[] = [];
     * crée un Nub et l'ajoute à la session
     * @param props propriétés du Nub (computeType, nodeType...)
    public createSessionNub(p: Props, dbg: boolean = false): Nub {
        const res = this.createNub(p, undefined, dbg);
        this._nubs.push(res);
mathias.chouet's avatar
mathias.chouet committed
    /**
     * Adds an existing Nub to the session
     */
    public registerNub(n: Nub) {
        if (this.uidAlreadyUsed(n.uid)) {
            n.setUid(Nub.nextUID);
        }
mathias.chouet's avatar
mathias.chouet committed
        this._nubs.push(n);
    }

    /**
     * Adds many existing Nubs to the session
     */
    public registerNubs(nubs: Nub[]) {
        for (const n of nubs) {
            this.registerNub(n);
        }
    }

mathias.chouet's avatar
mathias.chouet committed
    /**
     * Removes all Nubs from the Session
     */
    public clear() {
        this._nubs = [];
    }

    /**
     * Returns number of Nubs in the session
     */
    public getNumberOfNubs() {
        return this._nubs.length;
    }

    /** Accessor for Nubs list */
    public getAllNubs() {
        return this._nubs;
    }

     * Removes a Nub from the session; does not consider Structure nubs inside Calculator nubs
     * @param sn the Nub to remove from the session
     */
    public deleteNub(sn: Nub) {
David Dorchies's avatar
David Dorchies committed
        let i = 0;
        for (const n of this._nubs) {
David Dorchies's avatar
David Dorchies committed
            if (n.uid === sn.uid) {
                this._nubs.splice(i, 1);
David Dorchies's avatar
David Dorchies committed
                return;
            }
            i++;
        }
        throw new Error(`Session.deleteNub() : le Nub (uid ${sn.uid}) à supprimer n'a pas été trouvé`);
David Dorchies's avatar
David Dorchies committed
    }

    /**
     * Returns a JSON representation of (a part of) the current session
     * @param options an object having Nub uids as keys, with extra data object as values;
     *      if empty or undefined, all Nubs are serialised
     * @param settings app preferences to store in the session file (decimals, precision…)
    public serialise(options?: { [key: string]: {} }, settings?: { [key: string]: {} }): string {
        // session-wide settings
        let sessionSettings = {
            precision: SessionSettings.precision,
            maxIterations: SessionSettings.maxIterations
        };
        if (settings) {
            sessionSettings = {...sessionSettings, ...settings};
        }
        // nubs in session
        let ids: string[];
        let idsWithChildren: string[];
        if (options) {
            ids = Object.keys(options);
            idsWithChildren = [...ids];
            // add ids of children
            for (const n of this._nubs) {
                if (ids.includes(n.uid)) {
                    for (const c of n.getChildren()) {
                        idsWithChildren.push(c.uid);
                    }
                }
            }
            if (ids === undefined || ids.length === 0) {
                sess.push(n.objectRepresentation(undefined, ids));
            } else if (ids.includes(n.uid)) {
                sess.push(n.objectRepresentation(options[n.uid], idsWithChildren));
        return JSON.stringify({
            header: {
                source: "jalhyd",
                format_version: config.serialisation.fileFormatVersion,
                created: (new Date()).toISOString()
            },
            settings: sessionSettings,
            documentation: this.documentation,
            session: sess
        });
    }

    /**
     * Loads (a part of) a session from a JSON representation
     * @param serialised JSON data
     * @param uids unserialise only the Nubs havin the given UIDs
    public unserialise(serialised: string, uids?: string[]): { nubs: any[], hasErrors: boolean, settings: any } {
        const ret: { nubs: any[], hasErrors: boolean, settings: any } = {
            hasErrors: false,
            settings: {}
        // unserialise to object
        const data = JSON.parse(serialised);
        // settings
        if (data.settings) {
            ret.settings = data.settings;
            if (data.settings.precision !== undefined) {
                SessionSettings.precision = data.settings.precision;
            }
            if (data.settings.maxIterations !== undefined) {
                SessionSettings.maxIterations = data.settings.maxIterations;
            }
        }
        // nubs
        if (data.session && Array.isArray(data.session)) {
            data.session.forEach((e: any) => {
David Dorchies's avatar
David Dorchies committed
                if (!uids || uids.length === 0 || uids.includes(e.uid)) {
                    const nubPointer = this.createNubFromObjectRepresentation(e);
                    ret.nubs.push(nubPointer);
                    // forward errors
                    if (nubPointer.hasErrors) {
                        ret.hasErrors = true;
                    }
        // concatenate doc
        if (data.documentation !== undefined && data.documentation !== "") {
            this.documentation += `\n\n` + data.documentation;
        const flRes = this.fixLinks(serialised, uids);
        // forward errors
        if (flRes.hasErrors) {
            ret.hasErrors = true;
        }
        // second pass for Solveurs
        const fsRes = this.fixSolveurs(serialised, uids);
        // forward errors
        if (fsRes.hasErrors) {
            ret.hasErrors = true;
        }
     * Creates a Nub from a JSON representation and adds it to the current session; returns
     * a pointer to the Nub and its JSON metadata
     * @param serialised JSON representation of a single Nub
mathias.chouet's avatar
mathias.chouet committed
     * @param register if false, new Nub will just be returned and won't be registered into the session
mathias.chouet's avatar
mathias.chouet committed
    public unserialiseSingleNub(serialised: string, register: boolean = true): { nub: Nub, meta: any } {
        return this.createNubFromObjectRepresentation(JSON.parse(serialised), register);
    }

    /**
     * Returns the Nub identified by uid if any
     */
    public findNubByUid(uid: string): Nub {
        let foundNub: Nub;
        outerLoop:
        for (const n of this._nubs) {
            if (n.uid === uid) {
                foundNub = n;
            }
            for (const s of n.getChildren()) {
                if (s.uid === uid) {
                    foundNub = s;
                    break outerLoop;
                }
            }
David Dorchies's avatar
David Dorchies committed
    }

     * Crée un Nub à partir d'une description (Props)
     * @param params propriétés à partir desquelles on détermine la classe du Nub à créer
     *      - calcType: type de Nub
     *      - nodeType: pour un Nub contenant une section
     *      - loiDebit: pour un Nub de type Structure (calcType doit être CalculatorType.Structure)
     *    Si d'autres propriétés sont fournies, elle écraseront les éventuelles propriétés par défaut
     *    définies dans le constructeur du Nub créé
     * @param dbg activer débogage
mathias.chouet's avatar
mathias.chouet committed
    public createNub(params: Props, parentNub?: Nub, dbg: boolean = false): Nub {
        const calcType: CalculatorType = params.getPropValue("calcType");

        let nub: Nub;
mathias.chouet's avatar
mathias.chouet committed
        let prms: any;
        switch (calcType) {
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.ConduiteDistributrice:
                prms = new ConduiteDistribParams(
                    3, // débit Q
                    1.2, // diamètre D
                    0.6, // perte de charge J
                    100, // Longueur de la conduite Lg
                    1e-6, // Viscosité dynamique Nu
                );
                nub = new ConduiteDistrib(prms, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.LechaptCalmon:
                prms = new LechaptCalmonParams(
                    3, // débit
                    1.2, // diamètre
                    0.6, /// perte de charge
                    100, // longueur du toyo
                    1.863, // paramètre L du matériau
                    2, // paramètre M du matériau
                    5.33, // paramètre N du matériau
                    0 // Ks Perte de charge singulière
David Dorchies's avatar
David Dorchies committed
                );
                nub = new LechaptCalmon(prms, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.SectionParametree:
                nub = new SectionParametree(undefined, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.RegimeUniforme:
                nub = new RegimeUniforme(undefined, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.CourbeRemous:
                prms = new CourbeRemousParams(
                    100.25, // Z1 = cote de l'eau amont
                    100.4,  // Z2 = cote de l'eau aval
                    100.1,  // ZF1 = cote de fond amont
                    100,    // ZF2 = cote de fond aval
                    100,    // Long = Longueur du bief
                    5,      // Dx = Pas d'espace
David Dorchies's avatar
David Dorchies committed
                );
                nub = new CourbeRemous(undefined, prms, MethodeResolution.EulerExplicite, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.PabDimensions:
                prms = new PabDimensionParams(
                    2,      // Longueur L
                    1,      // Largeur W
                    0.5,    // Tirant d'eau Y
                    2       // Volume V
                );
                nub = new PabDimension(prms, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.PabPuissance:
                prms = new PabPuissanceParams(
                    0.3,      // Chute entre bassins DH (m)
                    0.1,      // Débit Q (m3/s)
                    0.5,    // Volume V (m3)
                    588.6   // Puissance dissipée PV (W/m3)
                );
                nub = new PabPuissance(prms, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.Structure:
                const loiDebit: LoiDebit = params.getPropValue("loiDebit");
                nub = CreateStructure(loiDebit, (parentNub as ParallelStructure));
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.ParallelStructure:
                prms = new ParallelStructureParams(
                    0.5, // Q
                    102, // Z1
                    101.5 // Z2
                );
                nub = new ParallelStructure(prms, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.Dever:
                const deverPrms = new DeverParams(
                    0.5, // Q
                    102, // Z1
                    10,  // BR : largeur du cours d'eau
                    99   // ZR : cote du lit du cours d'eau
                );
                nub = new Dever(deverPrms, dbg);
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.Cloisons:
                nub = new Cloisons(
                    new CloisonsParams(
                        1.5,      // Débit total (m3/s)
                        102,    // Cote de l'eau amont (m)
                        10,     // Longueur des bassins (m)
                        1,      // Largeur des bassins (m)
                        1,      // Profondeur moyenne (m)
                        0.5     // Hauteur de chute (m)
                    ), dbg
                );
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.MacroRugo:
                nub = new MacroRugo(
                    new MacrorugoParams(
                        12.5,   // ZF1
                        6,      // L
                        1,      // B
                        0.05,   // If
                        1.57,   // Q
                        0.6,    // h
                        0.01,   // Ks
David Dorchies's avatar
David Dorchies committed
                        0.13,   // C
David Dorchies's avatar
David Dorchies committed
                    ), dbg
                );
                break;
David Dorchies's avatar
David Dorchies committed

David Dorchies's avatar
David Dorchies committed
            case CalculatorType.PabChute:
                nub = new PabChute(
                    new PabChuteParams(
                        2,      // Z1
                        0.5,    // Z2
                        1.5     // DH
                    ), dbg
                );
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.PabNombre:
                nub = new PabNombre(
                    new PabNombreParams(
                        6,     // DHT
                        10,    // N
                        0.6    // DH
                    ), dbg
                );
                break;
David Dorchies's avatar
David Dorchies committed
            case CalculatorType.Section:
                const nodeType: SectionType = params.getPropValue("nodeType");
David Dorchies's avatar
David Dorchies committed
                nub = this.createSection(nodeType, dbg);
                break;
mathias.chouet's avatar
mathias.chouet committed

            case CalculatorType.Pab:
                nub = new Pab(
                    new PabParams(
                        1.5,    // Q
                        102,    // Z1
                        99      // Z2
                    ), undefined, dbg
mathias.chouet's avatar
mathias.chouet committed
            case CalculatorType.CloisonAval: {
                    prms = new CloisonsAvalParams(
David Dorchies's avatar
David Dorchies committed
                        0.5, // Q
                        102, // Z1
                        101.5, // Z2
                        0 // ZRAM
David Dorchies's avatar
David Dorchies committed
                    );
                    nub = new CloisonAval(prms, dbg);
                    break;
                }

David Dorchies's avatar
David Dorchies committed
            case CalculatorType.MacroRugoCompound:
                nub = new MacrorugoCompound(
                    new MacrorugoCompoundParams(
                        13.1,   // Z1
                        12.5,   // ZRL
                        12.5,   // ZRR
David Dorchies's avatar
David Dorchies committed
                        3,      // DH
                        0.05,   // If
                        0.01,   // Ks
David Dorchies's avatar
David Dorchies committed
                        0.13,   // C
            case CalculatorType.Jet:
            case CalculatorType.Grille:
                nub = new Grille(
                    new GrilleParams(
                        10,         // QMax
                        100,        // CRad
                        101.5,      // CEau
                        101.5,      // CSomGrille
                        2,          // B
                        72,         // Beta
                        90,         // Alpha
                        20,         // b
                        20,         // p
                        20,         // e
                        0.5,        // O
            case CalculatorType.Pente:
                nub = new Pente(
                    new PenteParams(
                        101,        // Z1
                        99.5,       // Z2
                        10,         // L
                        0.15        // I
                    )
                );
                break;

            case CalculatorType.Bief:
                nub = new Bief(
                    undefined,
                    new BiefParams(
                        100.25, // Z1 = cote de l'eau amont
                        100.4,  // Z2 = cote de l'eau aval
                        100.1,  // ZF1 = cote de fond amont
                        100,    // ZF2 = cote de fond aval
                        100,    // Long = Longueur du bief
                        5,      // Dx = Pas d'espace
                    ),
                    dbg
                );
                break;

            case CalculatorType.Solveur:
                nub = new Solveur(
                    new SolveurParams(undefined)
                );
                break;

mathias.chouet's avatar
mathias.chouet committed
            case CalculatorType.YAXB:
                nub = new YAXB(
                    new YAXBParams(
                        10,     // Y
                        2,      // A
                        3,      // X
                        4       // B
                    ),
                    dbg
                );
                break;

mathias.chouet's avatar
mathias.chouet committed
            case CalculatorType.Trigo:
                nub = new Trigo(
                    new TrigoParams(
                        0.985,  // Y
                        10      // X
                    ),
                    dbg
                );
                break;

            case CalculatorType.SPP:
                nub = new SPP(
                    new SPPParams(
                        1  // Y
                    ),
                    dbg
                );
                break;

            case CalculatorType.YAXN:
                nub = new YAXN(
                    new YAXNParams(
                        1,  // A
                        1,  // X
                        1   // B
                    ),
                    dbg
                );
                break;

            case CalculatorType.ConcentrationBlocs:
                nub = new ConcentrationBlocs(
                    new ConcentrationBlocsParams(
                        0.128, // Concentration de blocs
                        5,     // Nombre de motifs
                        4.9,   // Largeur de la passe
                        0.35   // Diamètre des plots
            case CalculatorType.Par:
                nub = new Par(
                    new ParParams(
                        0.25,   // Q
                        10,     // Z1
                        9,      // Z2
                        0.64,   // ha
                        0.2,    // S
                        0.4,    // P
                        0.6,    // L
                        0.1,    // a
                        1,      // N
                        1       // M
                    )
                );
                break;

matcho's avatar
matcho committed
            case CalculatorType.ParSimulation:
                nub = new ParSimulation(
                    new ParSimulationParams(
                        0.25,       // Q
                        10,         // Z1
                        9,          // Z2
                        0.2,        // S
                        0.4,        // P
                        undefined,  // Nb
matcho's avatar
matcho committed
                        undefined,  // ZD1
matcho's avatar
matcho committed
                        undefined,  // ZD2
                        0.6,        // L
                        0.1,        // a
                        1,          // N
                        1           // M
                    )
                );
                break;

            case CalculatorType.Espece:
                nub = new Espece(
                    // default params are those for SPECIES_1 (Salmons and trouts)
                    new EspeceParams(
                        0.35,   // DHMaxS
                        0.35,   // DHMaxP
                        0.3,    // BMin
                        1,      // PMinS
                        1,      // PMinP
                        2.5,    // LMinS
                        2.5,    // LMinP
                        0.3,    // HMin
                        0.4,    // YMin
                        0.2,    // YMinSB
                        0.3,    // YMinPB
                        200     // PVMax
                    )
                );
                break;

            case CalculatorType.Verificateur:
                nub = new Verificateur();
David Dorchies's avatar
David Dorchies committed
            default:
                throw new Error(
                    `Session.createNub() : type de module '${CalculatorType[calcType]}' non pris en charge`
                );

        // propagate properties
        try {
            nub.properties = params;
        } catch (e) {
            // loading Solveur properties when unserialising a session might fail because target
            // Nub / param do not exist yet; silent fail in this case, and Solveur.fixTargets()
            // might fix it later
            if (! (nub instanceof Solveur)) {
                throw e;
            }
        }

        return nub;
     * Returns true if given uid is already used by a Nub in this session,
     * or a Structure nub inside one of them
     */
    public uidAlreadyUsed(uid: string): boolean {
        let alreadyUsed = false;
        outerLoop:
        for (const n of this._nubs) {
            if (n.uid === uid) {
                alreadyUsed = true;
                break outerLoop;
            }
            for (const s of n.getChildren()) {
                if (s.uid === uid) {
                    alreadyUsed = true;
                    break outerLoop;
     * Returns all Nubs depending on the given one (parameter or result),
     * without following links (1st level only)
     * @param uid UID of the Nub that underwent a change
     * @param symbol symbol of the parameter whose value change triggered this method; if specified,
     *      Nubs targetting this symbol will be considered dependent
     * @param includeValuesLinks if true, even Nubs targetting non-calculated non-modified parameters
     *      will be considered dependent @see jalhyd#98
     * @param includeOtherDependencies if true, will be considered dependent
     *      - Solveur Nubs having given Nub either as X or as Ytarget's parent Nub
     *      - Verificateur Nubs having given Nub either as selected Custom Species or Pass to check
    public getDependingNubs(
        uid: string,
        symbol?: string,
        includeValuesLinks: boolean = false,
        includeOtherDependencies: boolean = false
        const dependingNubs: Nub[] = [];
        for (const n of this._nubs) {
                && n.resultDependsOnNub(uid, [], symbol, includeValuesLinks, includeOtherDependencies)
    /**
     * 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 all Nubs that do not depend on the result of any other Nub
     * (includes single Nubs).
     */
    public getUpstreamNubs(): Nub[] {
        const upstreamNubs: Nub[] = [];
        for (const n of this._nubs) {
            if (n.getRequiredNubs().length === 0) {
                upstreamNubs.push(n);
            }
        }
        return upstreamNubs;
    }

    /**
     * Returns all upstream Nubs that have at least one declared extra result.
     * Used by Solveur to find available "target" nubs to calculate.
     */
    public getUpstreamNubsHavingExtraResults() {
        const unher: Nub[] = [];
        for (const n of this.getUpstreamNubs()) {
            if (n.resultsFamilies && Object.keys(n.resultsFamilies).length > 0) {
                unher.push(n);
            }
        }
        return unher;
    }

     * Returns a list of nub/symbol couples, that can be linked to the given
mathias.chouet's avatar
mathias.chouet committed
     * parameter, among 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);
        }
mathias.chouet's avatar
mathias.chouet committed
        /* console.log("LINKABLE VALUES", res.map((lv) => {
            return `${lv.nub.uid}(${lv.nub.constructor.name})/${lv.symbol}`;
        })); */
    /**
     * Crée un Nub de type Section
     * @param nt SectionType
     * @param dbg activer débogage
     */
    public createSection(nt: SectionType, dbg: boolean = false): acSection {
        switch (nt) {
            case SectionType.SectionTrapeze: {
David Dorchies's avatar
David Dorchies committed
                const prms = new ParamsSectionTrapez(2.5, // largeur de fond
                    0.56, // fruit
                    0.8, // tirant d'eau
                    40, //  Ks=Strickler
                    1.2,  //  Q=Débit
                    0.001, //  If=pente du fond
                    1, // YB= hauteur de berge
                );
David Dorchies's avatar
David Dorchies committed
                return new cSnTrapez(prms, dbg);
            }
            case SectionType.SectionRectangle: {
David Dorchies's avatar
David Dorchies committed
                const prms = new ParamsSectionRectang(0.8, // tirant d'eau
                    2.5, // largeur de fond
                    40, //  Ks=Strickler
                    1.2, // Q=Débit
                    0.001, // If=pente du fond
                    1 // YB=hauteur de berge
                );
                return new cSnRectang(prms, dbg);
            }
            case SectionType.SectionCercle: {
David Dorchies's avatar
David Dorchies committed
                const prms = new ParamsSectionCirc(2, // diamètre
                    0.8, // tirant d'eau
                    40, //  Ks=Strickler
                    1.2,  //  Q=Débit
                    0.001, //  If=pente du fond
                    1, // YB= hauteur de berge
                );
                return new cSnCirc(prms, dbg);
            }
            case SectionType.SectionPuissance: {
David Dorchies's avatar
David Dorchies committed
                const prms = new ParamsSectionPuiss(0.5, // coefficient
                    0.8, // tirant d'eau
                    4, // largeur de berge
                    40, //  Ks=Strickler
                    1.2,  //  Q=Débit
                    0.001, //  If=pente du fond
                    1, // YB= hauteur de berge
                );
                return new cSnPuiss(prms, dbg);
            }
                throw new Error(`type de section ${SectionType[nt]} non pris en charge`);

    /**
     * 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
mathias.chouet's avatar
mathias.chouet committed
     * @param register if false, new Nub will just be returned and won't be registered into the session
mathias.chouet's avatar
mathias.chouet committed
    private createNubFromObjectRepresentation(obj: any, register: boolean = true)
        : { nub: Nub, meta: any, hasErrors: boolean } {

        // return value;
        const nubPointer: { nub: Nub, meta: any, hasErrors: boolean } = {
            nub: undefined,
            meta: undefined,
            hasErrors: false
        };
        // decode properties
        const props = Session.invertEnumKeysAndValuesInProperties(obj.props, true);
        // create the Nub
mathias.chouet's avatar
mathias.chouet committed
        let newNub;
        if (register) {
            newNub = this.createSessionNub(new Props(props));
mathias.chouet's avatar
mathias.chouet committed
        } else {
            newNub = this.createNub(new Props(props));
mathias.chouet's avatar
mathias.chouet committed
        }
        // try to keep the original ID
David Dorchies's avatar
David Dorchies committed
        if (!this.uidAlreadyUsed(obj.uid)) {
            newNub.setUid(obj.uid);
        }
        const res = newNub.loadObjectRepresentation(obj);
        nubPointer.nub = newNub;
        // forward errors
        if (res.hasErrors) {
            nubPointer.hasErrors = true;
        }
        // add metadata (used by GUI, for ex.)
        if (obj.meta) {
            nubPointer.meta = obj.meta;
        }
        return nubPointer;
    }

    /**
     * Asks all loaded Nubs to relink any parameter that has a wrong target
     */
    private fixLinks(serialised: string, uids?: string[]): { hasErrors: boolean } {
        // return value
        const res = {
            hasErrors: false
        };
        const data = JSON.parse(serialised);
        if (data.session && Array.isArray(data.session)) {
            // find each corresponding Nub in the session
            data.session.forEach((e: any) => {
David Dorchies's avatar
David Dorchies committed
                if (!uids || uids.length === 0 || uids.includes(e.uid)) {
                    const nub = this.findNubByUid(e.uid);
                    // find linked parameters
                    const ret = nub.fixLinks(e);
                    // forwardErrors
                    if (ret.hasErrors) {
                        res.hasErrors = true;
                    }

    /**
     * Asks every loaded Solveur to reconnect to its nubToCalculate / searchedParameter
     */
    private fixSolveurs(serialised: string, uids?: string[]): { hasErrors: boolean } {
        // return value
        const res = {
            hasErrors: false
        };
        const data = JSON.parse(serialised);
        if (data.session && Array.isArray(data.session)) {
            // find each corresponding Nub in the session
            data.session.forEach((e: any) => {
                if (!uids || uids.length === 0 || uids.includes(e.uid)) {
                    const nub = this.findNubByUid(e.uid);
                    if (nub instanceof Solveur) {
                        // find targetted nubToCalculate / searchedParam
                        const ret = nub.fixTargets(e);
                        // forwardErrors
                        if (ret.hasErrors) {