import { isNumeric } from "./base"; import { CalculatorType, SectionType } from "./compute-node"; import { config } from "./config"; import { LCMaterial } from "./lc-material"; import { LinkedValue } from "./linked-value"; import { Nub } from "./nub"; import { ParamDefinition } from "./param/param-definition"; import { Props } from "./props"; import { SessionSettings } from "./session_settings"; // 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"; 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"; 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"; 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"; import { DivingJetSupport } from "./verification/diving-jet-support"; import { PreBarrage } from "./prebarrage/pre_barrage"; import { PreBarrageParams } from "./prebarrage/pre_barrage_params"; import { PbCloison } from "./prebarrage/pb_cloison"; import { PbBassin } from "./prebarrage/pb_bassin"; import { PbBassinParams } from "./prebarrage/pb_bassin_params"; export class Session { /** 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, divingJetSupported: DivingJetSupport }; public static getInstance(): Session { if (Session._instance === undefined) { Session._instance = new Session(); } return Session._instance; } /** * 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]]; } } } return res; } /** 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); return res; } /** * Adds an existing Nub to the session */ public registerNub(n: Nub) { if (this.uidAlreadyUsed(n.uid)) { n.setUid(Nub.nextUID); } this._nubs.push(n); } /** * Adds many existing Nubs to the session */ public registerNubs(nubs: Nub[]) { for (const n of nubs) { this.registerNub(n); } } /** * 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) { let i = 0; for (const n of this._nubs) { if (n.uid === sn.uid) { this._nubs.splice(i, 1); return; } i++; } throw new Error(`Session.deleteNub() : le Nub (uid ${sn.uid}) à supprimer n'a pas été trouvé`); } /** * 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 { const sess: any[] = []; // 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); } } } } for (const n of this._nubs) { 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 } { // return value const ret: { nubs: any[], hasErrors: boolean, settings: any } = { nubs: [], 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) => { 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; } // second pass for links 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; } return ret; } /** * 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 * @param register if false, new Nub will just be returned and won't be registered into the session */ 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; } } } return foundNub; } /** * 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 */ public createNub(params: Props, parentNub?: Nub, dbg: boolean = false): Nub { const calcType: CalculatorType = params.getPropValue("calcType"); let nub: Nub; let prms: any; switch (calcType) { 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; 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 ); nub = new LechaptCalmon(prms, dbg); break; case CalculatorType.SectionParametree: nub = new SectionParametree(undefined, dbg); break; case CalculatorType.RegimeUniforme: nub = new RegimeUniforme(undefined, dbg); break; 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 ); nub = new CourbeRemous(undefined, prms, MethodeResolution.EulerExplicite, dbg); break; 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; 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; case CalculatorType.Structure: const loiDebit: LoiDebit = params.getPropValue("loiDebit"); nub = CreateStructure(loiDebit, (parentNub as ParallelStructure), dbg); break; case CalculatorType.ParallelStructure: prms = new ParallelStructureParams( 0.5, // Q 102, // Z1 101.5 // Z2 ); nub = new ParallelStructure(prms, dbg); break; 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; 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; 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 0.13, // C 0.4, // D 0.4, // k 1 // Cd0 ), dbg ); break; case CalculatorType.PabChute: nub = new PabChute( new PabChuteParams( 2, // Z1 0.5, // Z2 1.5 // DH ), dbg ); break; case CalculatorType.PabNombre: nub = new PabNombre( new PabNombreParams( 6, // DHT 10, // N 0.6 // DH ), dbg ); break; case CalculatorType.Section: const nodeType: SectionType = params.getPropValue("nodeType"); nub = this.createSection(nodeType, dbg); break; case CalculatorType.Pab: nub = new Pab( new PabParams( 1.5, // Q 102, // Z1 99 // Z2 ), undefined, dbg ); break; case CalculatorType.CloisonAval: { prms = new CloisonsAvalParams( 0.5, // Q 102, // Z1 101.5, // Z2 0 // ZRAM ); nub = new CloisonAval(prms, dbg); break; } case CalculatorType.MacroRugoCompound: nub = new MacrorugoCompound( new MacrorugoCompoundParams( 13.1, // Z1 12.5, // ZRL 12.5, // ZRR 4, // B 3, // DH 0.05, // If 0.01, // Ks 0.13, // C 0.4, // D 0.4, // k 1 // Cd0 ), dbg ); break; case CalculatorType.Jet: nub = new Jet( new JetParams( 5, // V0 0.03, // S 30, // ZJ 29.2, // ZW 28.5, // ZF 3 // D ), dbg ); break; 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 2, // a 1.5, // c 0.5, // O 0.5, // Ob 0.1, // OEntH 4 // cIncl ), dbg ); break; case CalculatorType.Pente: nub = new Pente( new PenteParams( 101, // Z1 99.5, // Z2 10, // L 0.15 // I ), dbg ); 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; case CalculatorType.YAXB: nub = new YAXB( new YAXBParams( 10, // Y 2, // A 3, // X 4 // B ), dbg ); break; 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 ), dbg ); break; 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 ), dbg ); break; case CalculatorType.ParSimulation: nub = new ParSimulation( new ParSimulationParams( 0.25, // Q 10, // Z1 9, // Z2 0.2, // S 0.4, // P undefined, // Nb 9.242, // ZR1 undefined, // ZD1 8.222, // ZR2 undefined, // ZD2 0.6, // L 0.1, // a 1, // N 1 // M ), dbg ); break; case CalculatorType.PreBarrage: nub = new PreBarrage( new PreBarrageParams( 1, // Q 101, // Z1 100 // Z2 ), dbg ); 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 2.5, // VeMax 0.2, // YMinSB 0.3, // YMinPB 150, // PVMaxPrec 200 // PVMaxLim ) ); break; case CalculatorType.Verificateur: nub = new Verificateur(); break; case CalculatorType.PbBassin: nub = new PbBassin(new PbBassinParams( 10, // S 100 // ZF ), dbg); break; case CalculatorType.PbCloison: nub = new PbCloison(undefined, undefined); break; 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, nubs: Nub[] = this._nubs): boolean { let alreadyUsed = false; for (const n of nubs) { if (n.uid === uid) { alreadyUsed = true; break; } if (! alreadyUsed) { alreadyUsed = this.uidAlreadyUsed(uid, n.getChildren()); } } return alreadyUsed; } /** * 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 ): Nub[] { const dependingNubs: Nub[] = []; for (const n of this._nubs) { if ( n.uid !== uid && n.resultDependsOnNub(uid, [], symbol, includeValuesLinks, includeOtherDependencies) ) { dependingNubs.push(n); } } 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 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 * 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); } /* console.log("LINKABLE VALUES", res.map((lv) => { return `${lv.nub.uid}(${lv.nub.constructor.name})/${lv.symbol}`; })); */ return res; } /** * 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: { 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 ); return new cSnTrapez(prms, dbg); } case SectionType.SectionRectangle: { 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: { 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: { 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); } default: 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 * @param register if false, new Nub will just be returned and won't be registered into the session */ 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 let newNub; if (register) { newNub = this.createSessionNub(new Props(props)); } else { newNub = this.createNub(new Props(props)); } // try to keep the original ID 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) => { 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; } } }); } return res; } /** * 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) { res.hasErrors = true; } } } }); } return res; } }