session.ts 30 KB
Newer Older
Dorchies David's avatar
lint    
Dorchies David committed
1
import { CalculatorType, ComputeNodeType } from "./compute-node";
2
import { LCMaterial } from "./lc-material";
3
import { LinkedValue } from "./linked-value";
Dorchies David's avatar
lint    
Dorchies David committed
4
import { Nub } from "./nub";
Mathias Chouet's avatar
Mathias Chouet committed
5
import { ParamDefinition } from "./param/param-definition";
Mathias Chouet's avatar
Mathias Chouet committed
6
import { Props } from "./props";
Dorchies David's avatar
lint    
Dorchies David committed
7

8
9
import { config } from "./config";

Dorchies David's avatar
lint    
Dorchies David committed
10
// Calculettes
Mathias Chouet's avatar
Mathias Chouet committed
11
12
import { YAXB } from "./axb";
import { YAXBParams } from "./axb_params";
13
14
15
import { ConduiteDistrib } from "./cond_distri";
import { LechaptCalmon } from "./lechaptcalmon";
import { MacroRugo } from "./macrorugo/macrorugo";
Dorchies David's avatar
Dorchies David committed
16
17
import { MacrorugoCompound } from "./macrorugo/macrorugo_compound";
import { MacrorugoCompoundParams } from "./macrorugo/macrorugo_compound_params";
18
19
20
21
import { PabChute } from "./pab/pab_chute";
import { PabDimension } from "./pab/pab_dimension";
import { PabNombre } from "./pab/pab_nombre";
import { PabPuissance } from "./pab/pab_puissance";
Dorchies David's avatar
lint    
Dorchies David committed
22
import { RegimeUniforme } from "./regime_uniforme";
23
import { CourbeRemous } from "./remous/remous";
24
import { SectionParametree } from "./section/section_parametree";
Mathias Chouet's avatar
Mathias Chouet committed
25
26
import { Solveur } from "./solveur/solveur";
import { SolveurParams } from "./solveur/solveur_params";
Dorchies David's avatar
lint    
Dorchies David committed
27
28

// Classes relatives aux sections
Mathias Chouet's avatar
Mathias Chouet committed
29
import { BiefParams, BiefRegime } from "./remous/bief_params";
30
31
32
33
import { cSnCirc } from "./section/section_circulaire";
import { cSnPuiss } from "./section/section_puissance";
import { cSnRectang } from "./section/section_rectang";
import { cSnTrapez } from "./section/section_trapez";
Dorchies David's avatar
lint    
Dorchies David committed
34
35
36
import { acSection } from "./section/section_type";

// Classes relatives aux structures
37
import { isNumeric } from "./base";
38
39
40
import { ConduiteDistribParams } from "./cond_distri_params";
import { LechaptCalmonParams } from "./lechaptcalmon_params";
import { MacrorugoParams } from "./macrorugo/macrorugo_params";
Mathias Chouet's avatar
Mathias Chouet committed
41
import { CloisonAval } from "./pab/cloison_aval";
42
import { CloisonsAvalParams } from "./pab/cloison_aval_params";
43
44
import { Cloisons } from "./pab/cloisons";
import { CloisonsParams } from "./pab/cloisons_params";
45
46
47
48
49
50
import { Pab } from "./pab/pab";
import { PabChuteParams } from "./pab/pab_chute_params";
import { PabDimensionParams } from "./pab/pab_dimensions_params";
import { PabNombreParams } from "./pab/pab_nombre_params";
import { PabParams } from "./pab/pab_params";
import { PabPuissanceParams } from "./pab/pab_puissance_params";
51
import { MethodeResolution } from "./remous/methode-resolution";
52
53
54
55
56
import { CourbeRemousParams } from "./remous/remous_params";
import { ParamsSectionCirc } from "./section/section_circulaire_params";
import { ParamsSectionPuiss } from "./section/section_puissance_params";
import { ParamsSectionRectang } from "./section/section_rectang_params";
import { ParamsSectionTrapez } from "./section/section_trapez_params";
57
import { SessionSettings } from "./session_settings";
58
59
import { Dever } from "./structure/dever";
import { DeverParams } from "./structure/dever_params";
60
import { CreateStructure } from "./structure/factory_structure";
61
62
import { ParallelStructure } from "./structure/parallel_structure";
import { ParallelStructureParams } from "./structure/parallel_structure_params";
63
import { LoiDebit, StructureType } from "./structure/structure_props";
64
65

// Dévalaison
Mathias Chouet's avatar
Mathias Chouet committed
66
import { Grille, GrilleProfile, GrilleType } from "./devalaison/grille";
Mathias Chouet's avatar
Mathias Chouet committed
67
import { GrilleParams } from "./devalaison/grille_params";
68
69
import { Jet } from "./devalaison/jet";
import { JetParams } from "./devalaison/jet_params";
Mathias Chouet's avatar
Mathias Chouet committed
70
71
import { Pente } from "./pente";
import { PenteParams } from "./pente_params";
Mathias Chouet's avatar
Mathias Chouet committed
72
import { Bief } from "./remous/bief";
73

74
export class Session {
Dorchies David's avatar
lint    
Dorchies David committed
75

76
    public static getInstance(): Session {
77
78
        if (Session._instance === undefined) {
            Session._instance = new Session();
Dorchies David's avatar
lint    
Dorchies David committed
79
        }
80
        return Session._instance;
Dorchies David's avatar
lint    
Dorchies David committed
81
    }
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    /**
     * 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
        // tslint:disable-next-line:forin
        for (const k in res) {
            if (!forceNumbers || !isNumeric(res[k])) {
                switch (k) {
                    case "calcType":
                        res[k] = CalculatorType[res[k]];
                        break;
                    case "nodeType":
                        res[k] = ComputeNodeType[res[k]];
                        break;
                    case "structureType":
                        res[k] = StructureType[res[k]];
                        break;
                    case "loiDebit":
                        res[k] = LoiDebit[res[k]];
                        break;
                    case "methodeResolution":
                        res[k] = MethodeResolution[res[k]];
                        break;
107
108
109
                    case "material":
                        res[k] = LCMaterial[res[k]];
                        break;
Mathias Chouet's avatar
Mathias Chouet committed
110
111
112
113
114
115
                    case "gridType":
                        res[k] = GrilleType[res[k]];
                        break;
                    case "gridProfile":
                        res[k] = GrilleProfile[res[k]];
                        break;
Mathias Chouet's avatar
Mathias Chouet committed
116
117
118
                    case "regime":
                        res[k] = BiefRegime[res[k]];
                        break;
119
                    // "varCalc" is not an enum
120
                    // "inclinedApron" is not an enum
121
122
123
124
125
126
                }
            }
        }
        return res;
    }

127
128
    /** instance pour le pattern singleton */
    private static _instance: Session;
129

130
131
132
    /** free documentation text, in Markdown format, to save into session file (optional) */
    public documentation = "";

133
134
    /** Nubs de la session */
    private _nubs: Nub[] = [];
135

136
    /**
137
     * crée un Nub et l'ajoute à la session
138
     * @param props propriétés du Nub (computeType, nodeType...)
139
     */
140
141
    public createSessionNub(p: Props, dbg: boolean = false): Nub {
        const res = this.createNub(p, undefined, dbg);
142
        this._nubs.push(res);
143
144
145
        return res;
    }

Mathias Chouet's avatar
Mathias Chouet committed
146
147
148
149
    /**
     * Adds an existing Nub to the session
     */
    public registerNub(n: Nub) {
150
151
152
        if (this.uidAlreadyUsed(n.uid)) {
            n.setUid(Nub.nextUID);
        }
Mathias Chouet's avatar
Mathias Chouet committed
153
154
155
        this._nubs.push(n);
    }

156
157
158
159
160
161
162
163
164
    /**
     * 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
165
166
167
168
169
170
171
    /**
     * Removes all Nubs from the Session
     */
    public clear() {
        this._nubs = [];
    }

172
173
174
175
176
177
178
    /**
     * Returns number of Nubs in the session
     */
    public getNumberOfNubs() {
        return this._nubs.length;
    }

179
180
181
182
183
    /** Accessor for Nubs list */
    public getAllNubs() {
        return this._nubs;
    }

Mathias Chouet's avatar
Mathias Chouet committed
184
    /**
185
186
     * Removes a Nub from the session; does not consider Structure nubs inside Calculator nubs
     * @param sn the Nub to remove from the session
Mathias Chouet's avatar
Mathias Chouet committed
187
188
     */
    public deleteNub(sn: Nub) {
Dorchies David's avatar
lint    
Dorchies David committed
189
        let i = 0;
190
        for (const n of this._nubs) {
Dorchies David's avatar
lint    
Dorchies David committed
191
            if (n.uid === sn.uid) {
192
                this._nubs.splice(i, 1);
Dorchies David's avatar
lint    
Dorchies David committed
193
194
195
196
                return;
            }
            i++;
        }
Mathias Chouet's avatar
Mathias Chouet committed
197
        throw new Error(`Session.deleteNub() : le Nub (uid ${sn.uid}) à supprimer n'a pas été trouvé`);
Dorchies David's avatar
lint    
Dorchies David committed
198
199
    }

200
201
202
203
204
    /**
     * 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
     */
205
    public serialise(options?: { [key: string]: {} }, settings?: { [key: string]: {} }): string {
206
        const sess: any[] = [];
207
208
209
210
211
212
213
214
215
        // session-wide settings
        let sessionSettings = {
            precision: SessionSettings.precision,
            maxIterations: SessionSettings.maxIterations
        };
        if (settings) {
            sessionSettings = {...sessionSettings, ...settings};
        }
        // nubs in session
216
        let ids: string[];
217
218
219
        if (options) {
            ids = Object.keys(options);
        }
220
        for (const n of this._nubs) {
221
            if (ids === undefined || ids.length === 0) {
222
                sess.push(n.objectRepresentation(undefined, ids));
223
            } else if (ids.includes(n.uid)) {
224
                sess.push(n.objectRepresentation(options[n.uid], ids));
225
226
            }
        }
Mathias Chouet's avatar
Mathias Chouet committed
227
228
229
        return JSON.stringify({
            header: {
                source: "jalhyd",
230
                format_version: config.serialisation.fileFormatVersion,
Mathias Chouet's avatar
Mathias Chouet committed
231
232
                created: (new Date()).toISOString()
            },
233
            settings: sessionSettings,
234
            documentation: this.documentation,
Mathias Chouet's avatar
Mathias Chouet committed
235
236
            session: sess
        });
237
238
239
240
241
242
    }

    /**
     * Loads (a part of) a session from a JSON representation
     * @param serialised JSON data
     */
243
    public unserialise(serialised: string, uids?: string[]): { nubs: any[], hasErrors: boolean, settings: any } {
244
        // return value
245
        const ret: { nubs: any[], hasErrors: boolean, settings: any } = {
246
            nubs: [],
247
248
            hasErrors: false,
            settings: {}
249
        };
250
251
        // unserialise to object
        const data = JSON.parse(serialised);
252
253
        // settings
        if (data.settings) {
254
            ret.settings = data.settings;
255
256
257
258
259
260
261
262
            if (data.settings.precision !== undefined) {
                SessionSettings.precision = data.settings.precision;
            }
            if (data.settings.maxIterations !== undefined) {
                SessionSettings.maxIterations = data.settings.maxIterations;
            }
        }
        // nubs
263
264
        if (data.session && Array.isArray(data.session)) {
            data.session.forEach((e: any) => {
Dorchies David's avatar
Dorchies David committed
265
                if (!uids || uids.length === 0 || uids.includes(e.uid)) {
266
                    const nubPointer = this.createNubFromObjectRepresentation(e);
267
268
269
270
271
                    ret.nubs.push(nubPointer);
                    // forward errors
                    if (nubPointer.hasErrors) {
                        ret.hasErrors = true;
                    }
272
273
274
                }
            });
        }
275
276
277
        // concatenate doc
        if (data.documentation !== undefined && data.documentation !== "") {
            this.documentation += `\n\n` + data.documentation;
278
        }
279
280

        // second pass for links
281
282
283
284
285
        const flRes = this.fixLinks(serialised, uids);
        // forward errors
        if (flRes.hasErrors) {
            ret.hasErrors = true;
        }
286
287
288
289
290
291
        // second pass for Solveurs
        const fsRes = this.fixSolveurs(serialised, uids);
        // forward errors
        if (fsRes.hasErrors) {
            ret.hasErrors = true;
        }
292

293
        return ret;
294
295
296
    }

    /**
297
     * Creates a Nub from a JSON representation and adds it to the current session; returns
298
299
     * a pointer to the Nub and its JSON metadata
     * @param serialised JSON representation of a single Nub
Mathias Chouet's avatar
Mathias Chouet committed
300
     * @param register if false, new Nub will just be returned and won't be registered into the session
301
     */
Mathias Chouet's avatar
Mathias Chouet committed
302
303
    public unserialiseSingleNub(serialised: string, register: boolean = true): { nub: Nub, meta: any } {
        return this.createNubFromObjectRepresentation(JSON.parse(serialised), register);
304
305
306
307
308
    }

    /**
     * Returns the Nub identified by uid if any
     */
309
    public findNubByUid(uid: string): Nub {
310
311
312
313
314
315
        let foundNub: Nub;
        outerLoop:
        for (const n of this._nubs) {
            if (n.uid === uid) {
                foundNub = n;
            }
316
317
318
319
320
321
            for (const s of n.getChildren()) {
                if (s.uid === uid) {
                    foundNub = s;
                    break outerLoop;
                }
            }
322
323
        }
        return foundNub;
Dorchies David's avatar
lint    
Dorchies David committed
324
325
    }

326
    /**
327
     * Crée un Nub à partir d'une description (Props)
328
     * @param params paramètres supplémentaires spécifiques
329
330
     *        - calcType: type de Nub
     *        - nodeType: sous type de Nub
331
     * @param dbg activer débogage
332
     */
Mathias Chouet's avatar
Mathias Chouet committed
333
    public createNub(params: Props, parentNub?: Nub, dbg: boolean = false): Nub {
334
335
        const calcType: CalculatorType = params.getPropValue("calcType");

Mathias Chouet's avatar
Mathias Chouet committed
336
        let nub: Nub;
Mathias Chouet's avatar
tslint    
Mathias Chouet committed
337
        let prms: any;
Mathias Chouet's avatar
Mathias Chouet committed
338

339
        switch (calcType) {
Dorchies David's avatar
Dorchies David committed
340
341
342
343
344
345
346
347
348
349
            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;
350

Dorchies David's avatar
Dorchies David committed
351
352
353
354
355
356
357
358
359
360
361
362
            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
                );
                nub = new LechaptCalmon(prms, dbg);
                break;
363

Dorchies David's avatar
Dorchies David committed
364
365
366
            case CalculatorType.SectionParametree:
                nub = new SectionParametree(undefined, dbg);
                break;
367

Dorchies David's avatar
Dorchies David committed
368
369
370
            case CalculatorType.RegimeUniforme:
                nub = new RegimeUniforme(undefined, dbg);
                break;
371

Dorchies David's avatar
Dorchies David committed
372
373
            case CalculatorType.CourbeRemous:
                prms = new CourbeRemousParams(
374
375
376
377
378
379
                    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
Dorchies David's avatar
Dorchies David committed
380
381
382
                );
                nub = new CourbeRemous(undefined, prms, MethodeResolution.EulerExplicite, dbg);
                break;
383

Dorchies David's avatar
Dorchies David committed
384
385
386
387
388
389
390
391
392
            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;
393

Dorchies David's avatar
Dorchies David committed
394
395
396
397
398
399
400
401
402
            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;
403

Dorchies David's avatar
Dorchies David committed
404
405
406
407
            case CalculatorType.Structure:
                const loiDebit: LoiDebit = params.getPropValue("loiDebit");
                nub = CreateStructure(loiDebit, (parentNub as ParallelStructure));
                break;
408

Dorchies David's avatar
Dorchies David committed
409
410
411
412
413
414
415
416
            case CalculatorType.ParallelStructure:
                prms = new ParallelStructureParams(
                    0.5, // Q
                    102, // Z1
                    101.5 // Z2
                );
                nub = new ParallelStructure(prms, dbg);
                break;
417

Dorchies David's avatar
Dorchies David committed
418
419
420
421
422
423
424
425
426
            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;
427

Dorchies David's avatar
Dorchies David committed
428
429
430
431
432
433
434
435
436
437
438
439
            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;
440

Dorchies David's avatar
Dorchies David committed
441
442
443
444
445
446
447
448
449
450
            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
Dorchies David's avatar
Dorchies David committed
451
                        0.13,   // C
452
453
                        0.4,    // D
                        0.4,    // k
454
                        1.2     // Cd0
Dorchies David's avatar
Dorchies David committed
455
456
457
                    ), dbg
                );
                break;
Dorchies David's avatar
Dorchies David committed
458

Dorchies David's avatar
Dorchies David committed
459
460
461
462
463
464
465
466
467
            case CalculatorType.PabChute:
                nub = new PabChute(
                    new PabChuteParams(
                        2,      // Z1
                        0.5,    // Z2
                        1.5     // DH
                    ), dbg
                );
                break;
468

Dorchies David's avatar
Dorchies David committed
469
470
471
472
473
474
475
476
477
            case CalculatorType.PabNombre:
                nub = new PabNombre(
                    new PabNombreParams(
                        6,     // DHT
                        10,    // N
                        0.6    // DH
                    ), dbg
                );
                break;
478

Dorchies David's avatar
Dorchies David committed
479
480
481
482
            case CalculatorType.Section:
                const nodeType: ComputeNodeType = params.getPropValue("nodeType");
                nub = this.createSection(nodeType, dbg);
                break;
Mathias Chouet's avatar
Mathias Chouet committed
483

484
485
486
487
488
489
            case CalculatorType.Pab:
                nub = new Pab(
                    new PabParams(
                        1.5,    // Q
                        102,    // Z1
                        99      // Z2
490
                    ), undefined, dbg
491
492
493
                );
                break;

Mathias Chouet's avatar
Mathias Chouet committed
494
            case CalculatorType.CloisonAval: {
495
                    prms = new CloisonsAvalParams(
Dorchies David's avatar
Dorchies David committed
496
497
                        0.5, // Q
                        102, // Z1
498
499
                        101.5, // Z2
                        0 // ZRAM
Dorchies David's avatar
Dorchies David committed
500
501
502
503
504
                    );
                    nub = new CloisonAval(prms, dbg);
                    break;
                }

Dorchies David's avatar
Dorchies David committed
505
506
507
508
            case CalculatorType.MacroRugoCompound:
                nub = new MacrorugoCompound(
                    new MacrorugoCompoundParams(
                        13.1,   // Z1
509
510
                        12.5,   // ZRL
                        12.5,   // ZRR
511
                        4,      // B
Dorchies David's avatar
Dorchies David committed
512
513
514
                        3,      // DH
                        0.05,   // If
                        0.01,   // Ks
Dorchies David's avatar
Dorchies David committed
515
                        0.13,   // C
516
517
                        0.4,    // D
                        0.4,    // k
518
                        1.2     // Cd0
Dorchies David's avatar
Dorchies David committed
519
520
521
                    )
                );
                break;
522

Mathias Chouet's avatar
Mathias Chouet committed
523
            case CalculatorType.Jet:
524
525
526
527
528
529
530
531
532
                nub = new Jet(
                    new JetParams(
                        5,      // V0
                        0.03,   // S
                        2,      // H
                        3       // D
                    )
                );
                break;
533

Mathias Chouet's avatar
Mathias Chouet committed
534
            case CalculatorType.Grille:
Mathias Chouet's avatar
Mathias Chouet committed
535
536
537
538
539
540
541
542
543
544
545
546
547
                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
548
549
                        0.1,        // OEntH
                        4           // cIncl
Mathias Chouet's avatar
Mathias Chouet committed
550
551
552
553
                    )
                );
                break;

Mathias Chouet's avatar
Mathias Chouet committed
554
555
556
557
558
559
560
561
562
563
564
            case CalculatorType.Pente:
                nub = new Pente(
                    new PenteParams(
                        101,        // Z1
                        99.5,       // Z2
                        10,         // L
                        0.15        // I
                    )
                );
                break;

Mathias Chouet's avatar
Mathias Chouet committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
            case CalculatorType.Bief:
                const regime: BiefRegime = params.getPropValue("regime");
                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
                    ),
                    regime,
                    dbg
                );
                break;

582
583
584
585
586
587
588
            case CalculatorType.Solveur:
                // const nubToCalc: BiefRegime = params.getPropValue("nubToCalculate");
                nub = new Solveur(
                    new SolveurParams(undefined)
                );
                break;

Mathias Chouet's avatar
Mathias Chouet committed
589
590
591
592
593
594
595
596
597
598
599
600
            case CalculatorType.YAXB:
                nub = new YAXB(
                    new YAXBParams(
                        10,     // Y
                        2,      // A
                        3,      // X
                        4       // B
                    ),
                    dbg
                );
                break;

Dorchies David's avatar
Dorchies David committed
601
602
603
604
            default:
                throw new Error(
                    `Session.createNub() : type de module '${CalculatorType[calcType]}' non pris en charge`
                );
605
        }
Mathias Chouet's avatar
Mathias Chouet committed
606
607

        // propagate properties
608
609
610
611
612
613
614
615
616
617
        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;
            }
        }
Mathias Chouet's avatar
Mathias Chouet committed
618
619

        return nub;
620
621
    }

622
    /**
623
624
     * Returns true if given uid is already used by a Nub in this session,
     * or a Structure nub inside one of them
625
626
627
628
629
630
631
632
633
     */
    public uidAlreadyUsed(uid: string): boolean {
        let alreadyUsed = false;
        outerLoop:
        for (const n of this._nubs) {
            if (n.uid === uid) {
                alreadyUsed = true;
                break outerLoop;
            }
634
635
636
637
            for (const s of n.getChildren()) {
                if (s.uid === uid) {
                    alreadyUsed = true;
                    break outerLoop;
638
639
                }
            }
640
641
642
643
        }
        return alreadyUsed;
    }

644
    /**
645
646
     * Returns all Nubs depending on the given one (parameter or result),
     * without following links (1st level only)
647
648
649
650
     * @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
651
652
     * @param includeSolveurDependencies if true, Solveur Nubs having given Nub either as X or as Ytarget's
     *      parent Nub, will be considered dependent
653
     */
654
655
656
657
658
659
    public getDependingNubs(
        uid: string,
        symbol?: string,
        includeValuesLinks: boolean = false,
        includeSolveurDependencies: boolean = false
    ): Nub[] {
660
661
        const dependingNubs: Nub[] = [];
        for (const n of this._nubs) {
662
663
664
665
            if (
                n.uid !== uid
                && n.resultDependsOnNub(uid, [], symbol, includeValuesLinks, includeSolveurDependencies)
            ) {
666
667
668
669
670
671
                dependingNubs.push(n);
            }
        }
        return dependingNubs;
    }

672
673
674
675
676
677
678
679
680
681
682
683
684
685
    /**
     * 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;
    }

686
    /**
687
     * Returns a list of nub/symbol couples, that can be linked to the given
Mathias Chouet's avatar
Mathias Chouet committed
688
     * parameter, among all current nubs
689
690
691
692
693
694
695
696
     * @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
697
698
699
        /* console.log("LINKABLE VALUES", res.map((lv) => {
            return `${lv.nub.uid}(${lv.nub.constructor.name})/${lv.symbol}`;
        })); */
700
701
702
        return res;
    }

703
704
705
706
707
    /**
     * Crée un Nub de type Section
     * @param nt ComputeNodeType
     * @param dbg activer débogage
     */
Mathias Chouet's avatar
Mathias Chouet committed
708
    public createSection(nt: ComputeNodeType, dbg: boolean = false): acSection {
709
710
        switch (nt) {
            case ComputeNodeType.None: // pour les paramètres communs, n'importe quelle section convient
Mathias Chouet's avatar
Mathias Chouet committed
711
            case ComputeNodeType.SectionTrapeze: {
Dorchies David's avatar
Dorchies David committed
712
713
714
715
716
717
718
719
                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
                );
720

Dorchies David's avatar
Dorchies David committed
721
722
                return new cSnTrapez(prms, dbg);
            }
723

Mathias Chouet's avatar
Mathias Chouet committed
724
            case ComputeNodeType.SectionRectangle: {
Dorchies David's avatar
Dorchies David committed
725
726
727
728
729
730
731
732
733
                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);
            }
734

Mathias Chouet's avatar
Mathias Chouet committed
735
            case ComputeNodeType.SectionCercle: {
Dorchies David's avatar
Dorchies David committed
736
737
738
739
740
741
742
743
744
                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);
            }
745

Mathias Chouet's avatar
Mathias Chouet committed
746
            case ComputeNodeType.SectionPuissance: {
Dorchies David's avatar
Dorchies David committed
747
748
749
750
751
752
753
754
755
756
                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);
            }
757
758
759
760
761

            default:
                throw new Error(`type de section ${ComputeNodeType[nt]} non pris en charge`);
        }
    }
Mathias Chouet's avatar
Mathias Chouet committed
762
763
764
765
766

    /**
     * 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
767
     * @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
768
     */
Mathias Chouet's avatar
Mathias Chouet committed
769
770
771
    private createNubFromObjectRepresentation(obj: any, register: boolean = true)
        : { nub: Nub, meta: any, hasErrors: boolean } {

772
773
774
775
776
777
        // return value;
        const nubPointer: { nub: Nub, meta: any, hasErrors: boolean } = {
            nub: undefined,
            meta: undefined,
            hasErrors: false
        };
778
779
        // decode properties
        const props = Session.invertEnumKeysAndValuesInProperties(obj.props, true);
Mathias Chouet's avatar
Mathias Chouet committed
780
        // create the Nub
Mathias Chouet's avatar
Mathias Chouet committed
781
782
        let newNub;
        if (register) {
783
            newNub = this.createSessionNub(new Props(props));
Mathias Chouet's avatar
Mathias Chouet committed
784
        } else {
785
            newNub = this.createNub(new Props(props));
Mathias Chouet's avatar
Mathias Chouet committed
786
        }
Mathias Chouet's avatar
Mathias Chouet committed
787
        // try to keep the original ID
Dorchies David's avatar
Dorchies David committed
788
        if (!this.uidAlreadyUsed(obj.uid)) {
Mathias Chouet's avatar
Mathias Chouet committed
789
790
            newNub.setUid(obj.uid);
        }
791
        const res = newNub.loadObjectRepresentation(obj);
Mathias Chouet's avatar
Mathias Chouet committed
792
        nubPointer.nub = newNub;
793
794
795
796
        // forward errors
        if (res.hasErrors) {
            nubPointer.hasErrors = true;
        }
Mathias Chouet's avatar
Mathias Chouet committed
797
798
799
800
801
802
803
804
805
806
        // 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
     */
807
808
809
810
811
    private fixLinks(serialised: string, uids?: string[]): { hasErrors: boolean } {
        // return value
        const res = {
            hasErrors: false
        };
Mathias Chouet's avatar
Mathias Chouet committed
812
813
        const data = JSON.parse(serialised);
        if (data.session && Array.isArray(data.session)) {
814
            // find each corresponding Nub in the session
Mathias Chouet's avatar
Mathias Chouet committed
815
            data.session.forEach((e: any) => {
Dorchies David's avatar
Dorchies David committed
816
                if (!uids || uids.length === 0 || uids.includes(e.uid)) {
Mathias Chouet's avatar
Mathias Chouet committed
817
818
                    const nub = this.findNubByUid(e.uid);
                    // find linked parameters
819
820
821
822
823
                    const ret = nub.fixLinks(e);
                    // forwardErrors
                    if (ret.hasErrors) {
                        res.hasErrors = true;
                    }
Mathias Chouet's avatar
Mathias Chouet committed
824
825
826
                }
            });
        }
827
        return res;
Mathias Chouet's avatar
Mathias Chouet committed
828
    }
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856

    /**
     * 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;
    }
Dorchies David's avatar
lint    
Dorchies David committed
857
}