diff --git a/karma.conf.js b/karma.conf.js index acf16b031749452acef1db26b55090289d491894..2824ad868af44bb9ed876aba089370511b739eb2 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,9 +15,10 @@ module.exports = function (config) { // list of files / patterns to load in the browser files: [ - { pattern: 'src/**/*.ts', included: false }, + { pattern: 'spec/test-main.js', included: true }, { pattern: 'spec/**/*.ts', included: false }, - 'spec/test-main.js' + { pattern: 'src/**/*.ts', included: false } + // { pattern: 'build/**/*.js', included: false } ], @@ -29,17 +30,29 @@ module.exports = function (config) { // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - '+(src|spec)**/*.ts': ['typescript'] + // '+(src|spec)/**/*.ts': ['typescript'] + '**/*.ts': ['typescript'] }, typescriptPreprocessor: { + // options passed to the typescript compiler options: { - // https://github.com/Microsoft/TypeScript/blob/b0584b58fa07ee8c06e6d6f0f1bce2d4c37c7640/lib/typescript.d.ts#L1573 + sourceMap: true, // (optional) Generates corresponding .map file. + // enum ScriptTarget { ES3 = 0, ES5 = 1, ES6 = 2, ES2015 = 2, Latest = 2 } - target: 1, - // https://github.com/Microsoft/TypeScript/blob/b0584b58fa07ee8c06e6d6f0f1bce2d4c37c7640/lib/typescript.d.ts#L1544 + target: 'ES5', // (optional) Specify ECMAScript target version: 'ES3' (default), or 'ES5' + // enum ModuleKind { None = 0, CommonJS = 1, AMD = 2, UMD = 3, System = 4, ES6 = 5, ES2015 = 5 } - module: 2 + module: 'amd', // (optional) Specify module code generation: 'commonjs' or 'amd' + + // noImplicitAny: true, // (optional) Warn on expressions and declarations with an implied 'any' type. + // noResolve: true, // (optional) Skip resolution and preprocessing. + // removeComments: true, // (optional) Do not emit comments to output. + // concatenateOutput: false // (optional) Concatenate and emit output to single file. By default true if module option is omited, otherwise false. + }, + // transforming the filenames + transformPath: function (path) { + return path.replace(/\.ts$/, '.js'); } }, @@ -60,6 +73,7 @@ module.exports = function (config) { // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, + // logLevel: config.LOG_DEBUG, // enable / disable watching file and executing tests whenever any file changes diff --git a/package.json b/package.json index df3591aa67d470bf8f121cb3a33da0fab5d7ca51..47299514a7146cbc821c50f35d2cfe70bc3d3f62 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "devDependencies": { "@types/jasmine": "^2.5.47", "jasmine-core": "^2.5.2", + "jasmine-node": "^1.14.5", "karma": "^1.3.0", "karma-chrome-launcher": "^2.0.0", "karma-jasmine": "^1.0.2", @@ -21,8 +22,10 @@ }, "scripts": { "build": "./node_modules/typescript/bin/tsc --p src/tsconfig.app.json", - "test": "./node_modules/typescript/bin/tsc --p spec/tsconfig.spec.json && ./node_modules/karma/bin/karma start", + "buildspec": "./node_modules/typescript/bin/tsc --p spec/tsconfig.spec.json", + "jasmine": "./node_modules/.bin/jasmine", + "karma": "./node_modules/typescript/bin/tsc --p spec/tsconfig.spec.json && ./node_modules/karma/bin/karma start", "lint": "./node_modules/tslint/bin/tslint", "viz": "tsviz -recursive src/ jalhyd_class_diagram.png" } -} +} \ No newline at end of file diff --git a/spec/base.spec.ts b/spec/base.spec.ts index 6986c540fcaf7116080775b4bad8b60db89abe1e..f9778fc3b829b489cf5c5dde62ba3099185ddd27 100644 --- a/spec/base.spec.ts +++ b/spec/base.spec.ts @@ -1,14 +1,31 @@ /// <reference path="../node_modules/@types/jasmine/index.d.ts" /> -import { nub, res } from "./nubtest"; +// import { nub, res } from "./nubtest"; +import { nub } from "./nubtest"; +import { Result } from "../src/base"; + +//var prec = 2; // The number of decimal points to check +var prec: number = 0.01; describe('Class Nub: ', () => { - beforeEach(() => { - res.vCalc = 3; - }); + // beforeEach(() => { + // res.vCalc = 3; + // }); describe('Calc(): ', () => { it('should return a result.vCalc equal to 3', () => { - expect(nub.Calc("C")).toEqual(res); + //let res = new Result(3); + // expect(nub.Calc("C")).toEqual(res); + expect(nub.Calc("C").isCloseTo(3, prec)); + }); + it('should return a result.vCalc equal to 1', () => { + // let res = new Result(1); + // expect(nub.Calc("A").vCalc).toBeCloseTo(res.vCalc, prec); + expect(nub.Calc("A").isCloseTo(1, prec)); + }); + it('should return a result.vCalc equal to 2', () => { + // let res = new Result(2); + // expect(nub.Calc("B").vCalc).toBeCloseTo(res.vCalc, prec); + expect(nub.Calc("B").isCloseTo(2, prec)); }); }); }); diff --git a/spec/dichotomie.spec.ts b/spec/dichotomie.spec.ts index a2c6d9b54c90955641ee9c64e39468d3eb20605d..003c2724416f92ebaa75de5b9a8b95e8ee9815c4 100644 --- a/spec/dichotomie.spec.ts +++ b/spec/dichotomie.spec.ts @@ -1,6 +1,7 @@ /// <reference path="../node_modules/@types/jasmine/index.d.ts" /> -import { nub, res } from "./nubtest"; +// import { nub, res } from "./nubtest"; +import { nub } from "./nubtest"; import { Dichotomie } from "../src/dichotomie" let dicho: Dichotomie = new Dichotomie(nub, "A"); @@ -8,7 +9,7 @@ let dicho: Dichotomie = new Dichotomie(nub, "A"); describe('Class Dichotomie: ', () => { describe('Dichotomie(3, 1E-6, 0): ', () => { it('should return a result close to 1', () => { - expect(dicho.Dichotomie(3, 1E-6, 0).vCalc).toBeCloseTo(1,1E-6); + expect(dicho.Dichotomie(3, 1E-6, 0).vCalc).toBeCloseTo(1, 1E-6); }); }); }); diff --git a/spec/nubtest.ts b/spec/nubtest.ts index ef81b541c26edea19746383808123783103995b3..cc19b41a8b04c2c76de6a2768808c08c37d734a5 100644 --- a/spec/nubtest.ts +++ b/spec/nubtest.ts @@ -1,15 +1,25 @@ -import { Nub, Result, IParametres } from "../src/base"; +import { Nub, Result, IParamsEquation } from "../src/base"; export class NubTest extends Nub { - constructor(v: IParametres) { + constructor(v: IParamsEquation) { super(v); this.sVarsEq = ["C"]; } Equation(): Result { - let res: Result = new Result(); - res.vCalc = this.v["A"] + this.v["B"]; - return res; + return new Result(this.v["A"] + this.v["B"]); } } -export let nub = new NubTest({ "A": 1, "B": 2, "C": null }); -export let res = new Result; \ No newline at end of file +export let nub = new NubTest({ "A": 1, "B": 2, "C": 3 }); +//export let res = new Result(0); + + +/** + * précision de calcul (nombre de décimales) + */ +export let precDigits = 3; + + +/** + * précision de calcul (max de abs(v-v')) + */ +export let precDist = Math.pow(10, -precDigits); diff --git a/spec/regime_uniforme_rect.spec.ts b/spec/regime_uniforme_rect.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..46ea5e328ddcdc43ee60b1f4cc02770101dea526 --- /dev/null +++ b/spec/regime_uniforme_rect.spec.ts @@ -0,0 +1,38 @@ +/// <reference path="../node_modules/@types/jasmine/index.d.ts" /> + +import { Result } from "../src/base"; +import { RegimeUniforme } from "../src/regime_uniforme"; +import { cSnRectang } from "../src/section/section_rectang"; +import { cParamsCanal } from "../src/section/section_type"; +import { precDigits, precDist } from "./nubtest"; + +describe('Class RegimeUniforme / section rectangulaire : ', () => { + // beforeAll(() => { + // }); + + describe('Calc(): ', () => { + it('fail', () => { + expect(false); + }); + + it('Strickler should be 30.619', () => { + let sect: cSnRectang; + let prmsCanal: cParamsCanal; + + // Ks=Strickler, Q=Débit, If=pente du font, précision, YB=hauteur de berge, YCL=Condition limite en cote à l'amont ou à l'aval + prmsCanal = new cParamsCanal(40, 1.2, 0.001, precDist, 1) + + // largeur de fond + sect = new cSnRectang(false, prmsCanal, 2.5); + sect.Y = 0.8; + + var ru = new RegimeUniforme(sect); + + //let res = new Result(30.619); + + // nom variable à calculer, caleur de Y + // expect(ru.Calc("Ks").vCalc).toEqual(res.vCalc); + expect(ru.Calc("Ks").vCalc).toBeCloseTo(30.619, precDigits); + }); + }); +}); diff --git a/spec/regime_uniforme_trapeze.spec.ts b/spec/regime_uniforme_trapeze.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..46c1dd544039dbe3c3e67c0f8349bda82a80ac1a --- /dev/null +++ b/spec/regime_uniforme_trapeze.spec.ts @@ -0,0 +1,30 @@ +/// <reference path="../node_modules/@types/jasmine/index.d.ts" /> + +import { Result } from "../src/base"; +import { RegimeUniforme } from "../src/regime_uniforme"; +import { cSnTrapez } from "../src/section/section_trapez"; +import { cParamsCanal } from "../src/section/section_type"; +import { precDist } from "./nubtest"; + +describe('Class RegimeUniforme / section trapèze: ', () => { + beforeAll(() => { + }); + + describe('Calc(): ', () => { + it('LargeurAuFond should be 9.393', () => { + let sect: cSnTrapez; + let paramCnl: cParamsCanal; + // Ks=Strickler, Q=Débit, If=pente du font, précision, YB=hauteur de berge, YCL=Condition limite en cote à l'amont ou à l'aval + paramCnl = new cParamsCanal(40, 1.2, 0.001, 0.001, 1) + // largeur de fond, fruit + sect = new cSnTrapez(false, paramCnl, 0, 0.56); + + var ru: RegimeUniforme; + ru = new RegimeUniforme(sect); + + // let res = new Result(1.515); + // expect(sect.Calc("q").vCalc).toEqual(res.vCalc); + expect(ru.Calc("q").isCloseTo(9.393, precDist)); + }); + }); +}); diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json new file mode 100644 index 0000000000000000000000000000000000000000..0fb3c6b2c9961bc8a76f6b07699501d45bce7b90 --- /dev/null +++ b/spec/support/jasmine.json @@ -0,0 +1,11 @@ +{ + "spec_dir": "build/spec", + "spec_files": [ + "**/*[sS]pec.js" + ], + "helpers": [ + "helpers/**/*.js" + ], + "stopSpecOnExpectationFailure": false, + "random": false +} \ No newline at end of file diff --git a/spec/test-main.js b/spec/test-main.js index f0c8158df2311f09f8af93b0ef58848116a2dbbf..441e4ba26e8d4d7ac0ed403dd8878e2a41f8517e 100644 --- a/spec/test-main.js +++ b/spec/test-main.js @@ -1,8 +1,10 @@ var TEST_REGEXP = /(spec|test)\.js$/i; var allTestFiles = []; +//console.log('files ' + Object.keys(window.__karma__.files)); + // Get a list of all the test files to include -Object.keys(window.__karma__.files).forEach(function(file) { +Object.keys(window.__karma__.files).forEach(function (file) { if (TEST_REGEXP.test(file)) { // Normalize paths to RequireJS module names. // If you require sub-dependencies of test files to be loaded as-is (requiring file extension) diff --git a/src/base.ts b/src/base.ts index cb9e20eb161e535ef2df116d24937c7cb4dfad5d..39c8b2f2ad2cd0b93501bf5be876034aaa83d1f3 100644 --- a/src/base.ts +++ b/src/base.ts @@ -1,15 +1,51 @@ - +import { Dichotomie } from "./dichotomie" /** * Résultat de calcul comprenant la valeur du résultat et des calculs annexes (flag, calculs intermédiaires...) */ +// export class Result { +// /** Valeur calculée */ +// public vCalc: number; +// /** Variables intermédiaires, flags d'erreur */ +// public extraVar: {}; + +// constructor() { +// this.extraVar = {}; +// } +// } + + export class Result { /** Valeur calculée */ - public vCalc: number; + private _vCalc: number; + /** Variables intermédiaires, flags d'erreur */ - public extraVar: {}; + public extraVar: {}; + + constructor(v: number) { + this._vCalc = v + this.extraVar = {} + }; + + get vCalc() { return this._vCalc; } + + /** + * teste la proximité de la valeur avec une autre + * @param v valeur à tester + * @param dist distance max avec la valeur à tester + * @return true si abs( this - valeur test ) <= dist + */ + isCloseTo(v: number, dist: number): boolean { + // console.log('this ' + this._vCalc); + // console.log('v ' + v); + // console.log('dist ' + dist); + // console.log('abs ' + Math.abs(this._vCalc - v)); + // console.log('res ' + (Math.abs(this._vCalc - v) <= dist)); + return Math.abs(this._vCalc - v) <= dist; + } } + /** * Série de valeurs à calculer définie par le nom de la variable à sérier et le vecteur de valeur */ @@ -23,9 +59,11 @@ export class Serie { } } - -export interface IParametres { - [key: string]: number; +/** + * liste des valeurs des variables + */ +export interface IParamsEquation { + [key: string]: number; // map : array of numbers with string keys } @@ -38,14 +76,14 @@ export abstract class Debug { /** * @param DBG Flag de débuggage */ - constructor(private DBG: boolean) {} + constructor(private DBG: boolean) { } /** * Affiche un message dans la console si le flag this.DBG est à true * @param s Message à afficher dans la console */ protected debug(s: any) { - if(this.DBG) console.log(s); + if (this.DBG) console.log(s); } } @@ -55,13 +93,13 @@ export abstract class Debug { */ export abstract class Nub extends Debug { /// Nom des variables calculées par la méthode Equation - private _varsEq: string[]; + private _varsEq: string[] = []; - public v: IParametres; + public v: IParamsEquation; - constructor(parametres: IParametres) { + constructor(paramsEq: IParamsEquation) { super(false); - this.v = parametres; + this.v = paramsEq; } @@ -73,14 +111,17 @@ export abstract class Nub extends Debug { /** * Calcul d'une équation quelque soit l'inconnue à calculer + * @param sVarCalc nom de la variable à calculer + * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie + * @param rPrec précision de calcul */ - Calc(sVarCalc: string): Result { - for(let sVarEq of this._varsEq) { - if(sVarCalc == sVarEq) { + Calc(sVarCalc: string, rInit: number = 0, rPrec: number = 0.001): Result { + for (let sVarEq of this._varsEq) { + if (sVarCalc == sVarEq) { return this.Equation(sVarCalc); - } + } } - return this.Solve(sVarCalc); + return this.Solve(sVarCalc, rInit, rPrec); } @@ -88,7 +129,8 @@ export abstract class Nub extends Debug { /** @todo faire une boucle pour appeler this.Calc avec chaque valeur de serie.values * */ - let results = [new (Result)]; + // let results = [new (Result)]; + let results = [new Result(0)]; return results; } @@ -107,10 +149,13 @@ export abstract class Nub extends Debug { /** * Résoud l'équation par une méthode numérique + * @param sVarCalc nom de la variable à calculer + * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie + * @param rPrec précision de calcul */ - Solve(sVarCalc: string): Result { - let res: Result; - /** @todo Résolution par méthode numérique (dichotomie...) */ - return res; + Solve(sVarCalc: string, rInit: number, rPrec: number): Result { + let dicho: Dichotomie = new Dichotomie(this, sVarCalc); + var target = this.v[this._varsEq[0]]; + return dicho.Dichotomie(target, rPrec, rInit); } } diff --git a/src/dichotomie.ts b/src/dichotomie.ts index e14f5c713bffbf796ac0469272f6c95f9e2267ac..76c14528519e1fecff78e2c93f84ed10221f5a39 100644 --- a/src/dichotomie.ts +++ b/src/dichotomie.ts @@ -1,6 +1,7 @@ import { Debug, Nub, Result } from "./base"; -export class Dichotomie extends Debug { +//export class Dichotomie extends Debug { +export class Dichotomie { /** Pas de parcours de l'intervalle pour initialisation dichotomie */ readonly IDEFINT = 100; /** Nombre d'itérations maximum de la dichotomie */ @@ -13,7 +14,7 @@ export class Dichotomie extends Debug { * @param sVarCalc Nom de la variable à calculer */ constructor(private nub: Nub, private sVarCalc: string) { - super(false); + // super(false); } /** Valeur inconnue à rechercher */ @@ -48,6 +49,7 @@ export class Dichotomie extends Debug { return this.nub.Equation(this.nub.sVarsEq[0]); } + private debug(s) { } /** * Calcul à l'ouvrage @@ -117,7 +119,7 @@ export class Dichotomie extends Debug { // Gestion de l'absence de solution dans l'intervalle de recherche if (nIter >= this.IDEFINT) { this.debug("nIter >= this.IDEFINT"); - + if (v2 < rTarget && v1 < rTarget) { // Cote de l'eau trop basse pour passer le débit il faut ouvrir un autre ouvrage this.vX = XmaxInit; @@ -154,8 +156,9 @@ export class Dichotomie extends Debug { res.extraVar["flag"] = -1; // la valeur cible n'est pas dans l'intervalle de recherche return res; } - res = new Result(); - res.vCalc = X; - return res; + // res = new Result(); + // res.vCalc = X; + // return res; + return new Result(X); } } \ No newline at end of file diff --git a/src/lechaptcalmon.ts b/src/lechaptcalmon.ts index 17dd57bcdfe8dacccc738752ae2f67580452b60e..d6a40bc12f026b9c40026bf53eca922db22e4b2a 100644 --- a/src/lechaptcalmon.ts +++ b/src/lechaptcalmon.ts @@ -1,9 +1,8 @@ -import { Nub, Result, IParametres } from "./base"; +import { Nub, Result, IParamsEquation } from "./base"; - -interface IParamLechaptCalmon extends IParametres { +interface IParamLechaptCalmon extends IParamsEquation { /** Débit */ - Q: number; + Q: number; /** Diamètre */ D: number; /** Perte de charge */ @@ -32,22 +31,28 @@ class LechaptCalmon extends Nub { } Equation(sVarCalc: string): Result { - let res: Result; + let v: number; switch (sVarCalc) { case "Q": - res.vCalc = Math.pow((((this.v.J * Math.pow(this.v.D, this.v.N)) / this.v.L) * (1000 / this.v.Lg)), 1 / this.v.M); + v = Math.pow((((this.v.J * Math.pow(this.v.D, this.v.N)) / this.v.L) * (1000 / this.v.Lg)), 1 / this.v.M); break; + case "D": - res.vCalc = Math.pow((((this.v.L * Math.pow(this.v.Q, this.v.M)) / this.v.J) * (this.v.Lg / 1000)), 1 / this.v.N); + v = Math.pow((((this.v.L * Math.pow(this.v.Q, this.v.M)) / this.v.J) * (this.v.Lg / 1000)), 1 / this.v.N); break + case "J": - res.vCalc = ((this.v.L * Math.pow(this.v.Q, this.v.M)) / Math.pow(this.v.D, this.v.N)) * (this.v.Lg / 1000); + v = ((this.v.L * Math.pow(this.v.Q, this.v.M)) / Math.pow(this.v.D, this.v.N)) * (this.v.Lg / 1000); break; + case "Lg": - res.vCalc = ((this.v.J * Math.pow(this.v.D, this.v.N)) / (this.v.L * Math.pow(this.v.Q, this.v.M))) * 1000; + v = ((this.v.J * Math.pow(this.v.D, this.v.N)) / (this.v.L * Math.pow(this.v.Q, this.v.M))) * 1000; + + default: + throw "invalid variable name " + sVarCalc; } - return res; + return new Result(v); } } \ No newline at end of file diff --git a/src/regime_uniforme.ts b/src/regime_uniforme.ts new file mode 100644 index 0000000000000000000000000000000000000000..d29015f01415dc7f25d398b5f21beb3acc85265f --- /dev/null +++ b/src/regime_uniforme.ts @@ -0,0 +1,65 @@ +import { Nub, Result, IParamsEquation } from "./base"; +import { acSection, cParamsCanal } from "./section/section_type"; + + + +export class RegimeUniforme extends Nub { + private Sn: acSection; ///< Objet section + // private oP: cParamsCanal; ///< Objet paramètres de section + + // constructor(s: acSection, pCanal: cParamsCanal) { + constructor(s: acSection) { + let paramsEq: { [key: string]: number } = {}; + // params = {}; + super(paramsEq); + + this.Sn = s; + //this.oP = pCanal; + + this.AddVarEq("Q"); + this.AddVarEq("D"); + this.AddVarEq("J"); + this.AddVarEq("Lg"); + this.AddVarEq("nu"); + } + + /** + * Calcul du débit en régime uniforme. + * @return Débit en régime uniforme + */ + Calc_Qn() { + this.Sn.Reset(true); + if (this.Sn.oP.If <= 0) { + var Qn = 0; // ? false bool + //this.oLog.Add('h_normale_pente_neg_nul',true); + } else { + this.debug(this.Sn); + Qn = this.Sn.oP.Ks * Math.pow(this.Sn.Calc('R', this.Sn.Y), 2 / 3) * this.Sn.Calc('S', this.Sn.Y) * Math.sqrt(this.Sn.oP.If); + } + return Qn; + } + + Equation(sVarCalc: string): Result { + let v: number; + + switch (sVarCalc) { + case 'Y': + v = this.Sn.Calc('Yn'); + break; + + case 'Q': + v = this.Calc_Qn(); + break; + + // default: + // var oDicho = new cDichotomie(this.oLog, this, 'Calc_Qn'); + // v = oDicho.calculer(this.v['Q'], this.precision, rInit); + // break; + + default: + throw "invalid variable name " + sVarCalc; + } + + return new Result(v); + } +} \ No newline at end of file diff --git a/src/section/log.ts b/src/section/log.ts new file mode 100644 index 0000000000000000000000000000000000000000..a86d67c10c8e95a3e6786eaaf10dadebc1a01029 --- /dev/null +++ b/src/section/log.ts @@ -0,0 +1,23 @@ + +export class cLog { + + public txt; + + constructor() { + this.txt = ''; + } + + Add(sTxt,bErr=false) { + // peut on mettre des balises ? + this.txt += '<li'; + if(bErr) {this.txt += ' class="hyd_erreur"';} + this.txt += '>'+sTxt+'</li>'; + } + Result() { + if(this.txt!='') { + return this.txt; + } else { + return ''; + } + } +} \ No newline at end of file diff --git a/src/section/newton.ts b/src/section/newton.ts new file mode 100644 index 0000000000000000000000000000000000000000..89c39377092e67a1adf34a9fc2d8134367a2f04f --- /dev/null +++ b/src/section/newton.ts @@ -0,0 +1,110 @@ +import { cParamsCanal } from "./section_type" + +export abstract class acNewton { + protected rTol; + protected Dx; + private iCpt = 0; + private iCptMax = 50; + private rRelax = 1; /// Coefficient de relaxation + private rFnPrec = 0; /// Mémorisation du Fn précédent pour détecter le changement de signe + private iOscil = 0; /// Nombre de changement de signe de Delta + private oLog; + /** + * Constructeur de la classe + * @param $oSn Section sur laquelle on fait le calcul + * @param $oP Paramètres supplémentaires (Débit, précision...) + */ + constructor(oP: cParamsCanal) { + this.rTol = oP.Prec; + this.Dx = oP.Prec / 10; + } + /** + * Calcul de la fonction f(x) dont on cherche le zéro. + * @param $rX x + * @return Calcul de la fonction + */ + abstract CalcFn(rX); + /** + * Calcul de la dérivée f'(x) (peut être redéfini pour calcul analytique) + * @param $rX x + * @return Calcul de la fonction + */ + protected CalcDer($x) { + //~ spip_log('Newton:CalcDer $rX='.$x,'hydraulic.'._LOG_DEBUG); + return (this.CalcFn($x + this.Dx) - this.CalcFn($x - this.Dx)) / (2 * this.Dx); + } + /** + * Test d'égalité à une tolérance près + * @param $rFn x + * @return True si égal, False sinon + */ + private FuzzyEqual($rFn) { + return (Math.abs($rFn) < this.rTol); + } + /** + * Fonction récursive de calcul de la suite du Newton + * @param $rX x + * @return Solution du zéro de la fonction + */ + XOR(a, b) { + return (a || b) && !(a && b); + } + + public Newton(rX) { + this.iCpt++; + var rFn = this.CalcFn(rX); + if (this.FuzzyEqual(rFn) || this.iCpt >= this.iCptMax) { + return rX; + } + else { + var rDer = this.CalcDer(rX); + //~ echo(' - f\' = '.$rDer); + if (rDer != 0) { + if (this.XOR(rFn < 0, this.rFnPrec < 0)) { + this.iOscil++; + if (this.rRelax > 1) { + // Sur une forte relaxation, au changement de signe on réinitialise + this.rRelax = 1; + } + else if (this.iOscil > 2) { + // On est dans le cas d'une oscillation autour de la solution + // On réduit le coefficient de relaxation + this.rRelax = this.rRelax * 0.5; + } + } + this.rFnPrec = rFn; + var Delta = rFn / rDer; + //2^8 = 2E8 ? + while (Math.abs(Delta * this.rRelax) < this.rTol && rFn > 10 * this.rTol && this.rRelax < 2E8) { + // On augmente le coefficicient de relaxation s'il est trop petit + this.rRelax = this.rRelax * 2; + } + var rRelax = this.rRelax; + while (rX - Delta * rRelax <= 0 && rRelax > 1E-4) { + // On diminue le coeficient de relaxation si on passe en négatif + rRelax = rRelax * 0.5; // Mais on ne le mémorise pas pour les itérations suivantes + } + rX = rX - Delta * rRelax; + //this.rDelta = Delta; ??? + if (rX < 0) { rX = this.rTol; } // Aucune valeur recherchée ne peut être négative ou nulle + return this.Newton(rX); + } + else { + // Echec de la résolution + return false; + } + } + } + /** + * Pour savoir si le Newton a convergé + * @return true si oui, false sinon + */ + public HasConverged() { + if (this.iCpt >= this.iCptMax) { + return false; + } + else { + return true; + } + } +} \ No newline at end of file diff --git a/src/section/section.config.json b/src/section/section.config.json new file mode 100644 index 0000000000000000000000000000000000000000..fb68b9af6bd2a3825f2f78bdf8ce48ecc8b035fa --- /dev/null +++ b/src/section/section.config.json @@ -0,0 +1,83 @@ +{ + "saisies":[ + { + "id":"fs_section", + "name":"Type de section", + "fields":[{ + "type":"select", + "name": "Choix du type de section", + "value": 1, + + "select":[ + { + "id":1, + "name":"Trapézoïdale", + "definition":[ + { + "id":"Lf", + "name":"Largeur au fond ", + "unit":"m", + "value":2.5, + "type":"input" + }, + { + "id":"F", + "name":"Fruit des berges", + "unit":"m/m", + "value":0.56, + "type":"input" + } + ] + }, + { + "id":2, + "name":"Rectangulaire", + "definition":[ + { + "id":"Lf", + "name":"Largeur au fond", + "unit":"m", + "value":2.5, + "type":"input" + } + ] + }, + { + "id":3, + "name":"Circulaire", + "definition":[ + { + "id":"D", + "name":"Diamètre", + "unit":"m", + "value":2, + "type":"input" + } + ] + }, + { + "id":4, + "name":"Parabolique", + "definition":[ + { + "id":"K", + "name":"Coefficient", + "unit":"", + "value":0.5, + "type":"input" + }, + { + "id":"LB", + "name":"Largeur au niveau des berges", + "unit":"", + "value":0.56, + "type":"input" + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/section/section_circulaire.ts b/src/section/section_circulaire.ts new file mode 100644 index 0000000000000000000000000000000000000000..214ff218a91d400d41e83636a72d220874c76e5f --- /dev/null +++ b/src/section/section_circulaire.ts @@ -0,0 +1,151 @@ +import { acSection } from "./section_type"; + +/** + * Calculs de la section circulaire + */ +export class cSnCirc extends acSection { + + public D; /// Diamètre du cercle + private Alpha; /// Angle de la surface libre par rapport au fond + protected nbDessinPoints = 50; + + constructor(oLog, oP, D) { + super(oLog, oP); + this.D = D; + if (oP.YB > D) { oP.YB = D; } // On place la berge au sommet du cercle + } + /** + * Calcul de l'angle Alpha de la surface libre par rapport au fond. + * @return Alpha + */ + Calc_Alpha() { + if (this.Y > this.oP.YB) { + var rY = this.oP.YB; + } + else { + rY = this.Y; + } + if (rY <= 0) { + return 0; + } + else if (rY > this.D) { + return Math.PI; + } + else { + var alpha = Math.acos(1. - rY / (this.D / 2.)); + if (alpha > Math.PI) { + return Math.PI; + } + else { + return alpha; + } + } + } + + /** + * Calcul de dérivée de l'angle Alpha de la surface libre par rapport au fond. + * @return dAlpha + */ + Calc_dAlpha() { + if (this.Y <= 0 || this.Y >= this.D || this.Y > this.oP.YB) { + return 0; + } + else { + return 2. / this.D / Math.sqrt(1. - Math.pow(1. - 2. * this.Y / this.D, 2)); + } + } + + /** + * Calcul de la largeur au miroir. + * @return B + */ + Calc_B() { + if (this.Y > this.oP.YB) { + return super.Calc_B_Debordement(); + } + else { + return this.D * Math.sin(this.Calc('Alpha')); + } + } + + /** + * Calcul du périmètre mouillé. + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return B + */ + Calc_P($rY = 0) { + if (this.Y > this.oP.YB && !this.bSnFermee) { + // On n'ajoute pas le périmètre dans le cas d'une fente de Preissmann + return this.CalcGeo('P') + super.Calc_P_Debordement(this.Y - this.oP.YB); + } + else { + return this.D * this.Calc('Alpha'); + } + } + + /** + * Calcul de la surface mouillée. + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return S + */ + Calc_S($rY = 0) { + if (this.Y > this.oP.YB) { + return this.CalcGeo('S') + super.Calc_S_Debordement(this.Y - this.oP.YB); + } + else { + return Math.pow(this.D, 2) / 4 * (this.Calc('Alpha') - Math.sin(this.Calc('Alpha')) * Math.cos(this.Calc('Alpha'))); + } + } + + + /** + * Calcul de dérivée du périmètre hydraulique par rapport au tirant d'eau. + * @return dP + */ + Calc_dP() { + if (this.Y > this.oP.YB && !this.bSnFermee) { + return super.Calc_dP_Debordement(); + } + else { + return this.D * this.Calc('dAlpha'); + } + } + /** + * Calcul de dérivée de la largeur au miroir par rapport au tirant d'eau. + * @return dB + */ + Calc_dB() { + if (this.Y > this.oP.YB) { + return super.Calc_dB_Debordement(); + } + else { + return this.D * this.Calc('dAlpha') * Math.cos(this.Calc('Alpha')); + } + } + /** + * Calcul de la distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return S x Yg + */ + Calc_SYg($rY = 0) { + var SYg = Math.sin(this.Calc('Alpha')) - Math.pow(Math.sin(this.Calc('Alpha')), 3) / 3 - this.Calc('Alpha') * Math.cos(this.Calc('Alpha')); + SYg = Math.pow(this.D, 3) / 8 * SYg; + return SYg; + } + /** + * Calcul de la dérivée de la distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return S x Yg + */ + Calc_dSYg($rY = 0) { + var cos = Math.cos(this.Calc('Alpha')); + var sin = Math.sin(this.Calc('Alpha')); + var SYg = this.Calc('dAlpha') * cos; + SYg += - this.Calc('dAlpha') * cos * Math.pow(sin, 2); + SYg += - this.Calc('dAlpha') * cos + this.Calc('Alpha') * this.Calc('dAlpha') * sin; + SYg = 3 * Math.pow(this.D, 3) / 8 * SYg; + return SYg; + } +} \ No newline at end of file diff --git a/src/section/section_puissance.ts b/src/section/section_puissance.ts new file mode 100644 index 0000000000000000000000000000000000000000..004869fec28960993ebf33ef2e6d24fae9255e68 --- /dev/null +++ b/src/section/section_puissance.ts @@ -0,0 +1,97 @@ +import { acSection } from "./section_type"; + +/** + * Calculs de la section parabolique ou "puissance" + */ +export class cSnPuiss extends acSection { + public k; /// Coefficient de forme compris entre 0 et 1 + //$LargeurBerge => La largeur des berges est déjà présente dans acSection + protected nbDessinPoints = 50; + + constructor(oLog, oP, rk, LargeurBerge) { + super(oLog, oP); + this.k = rk; + this.LargeurBerge = LargeurBerge; + } + /** + * Calcul de Lambda (mais on garde la routine Alpha commune avec la section circulaire) + * @return Lambda + */ + Calc_Alpha() { + return this.LargeurBerge / Math.pow(this.oP.YB, this.k); + } + /** + * Calcul de la largeur au miroir. + * @return B + */ + Calc_B() { + if (this.Y >= this.oP.YB) { + return this.LargeurBerge; + } + else { + return this.Calc('Alpha') * Math.pow(this.Y, this.k); + } + } + /** + * Calcul du périmètre mouillé. + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return B + */ + Calc_P($rY = 0) { + var n = 100; /// Le nombre de partie pour le calcul de l'intégrale + var Lambda2 = Math.pow(this.Calc('Alpha'), 2); + var P = 0; /// Le périmètre à calculer + var Previous = 0; + for (var i = 1; i <= n; i++) { + var Current = Math.pow(this.Y * i / n, this.k) / 2; + P += Math.sqrt(Math.pow(n, -2) + Lambda2 * Math.pow(Current - Previous, 2)); + Previous = Current; + } + P *= 2; + return P; + } + + /** + * Calcul de la surface mouillée. + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return S + */ + Calc_S($rY = 0) { + return this.Calc('Alpha') * Math.pow(this.Y, this.k + 1) / (this.k + 1); + } + + /** + * Calcul de dérivée du périmètre hydraulique par rapport au tirant d'eau. + * @return dP + */ + Calc_dP() { + return 2 * Math.sqrt(1 + Math.pow(this.k * this.Calc('Alpha') / 2, 2) * Math.pow(this.Y, 2 * (this.k - 1))); + } + + /** + * Calcul de dérivée de la largeur au miroir par rapport au tirant d'eau. + * @return dB + */ + Calc_dB() { + return this.Calc('Alpha') * this.k * Math.pow(this.Y, this.k - 1); + } + /** + * Calcul de la distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return S x Yg + */ + Calc_SYg($rY = 0) { + return this.Calc('Alpha') * Math.pow(this.Y, this.k + 2) / ((this.k + 1) * (this.k + 2)); + } + /** + * Calcul de la dérivée distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @param $rY Uniquement présent car la méthode parent a cet argument + * @return S x Yg + */ + Calc_dSYg($rY = 0) { + var SYg = this.Calc('dAlpha') * Math.pow(this.Y, this.k + 2) + this.Calc('Alpha') * Math.pow(this.Y, this.k + 1) * (this.k + 2); + return SYg / ((this.k + 1) * (this.k + 2)); + } +} \ No newline at end of file diff --git a/src/section/section_rectang.ts b/src/section/section_rectang.ts new file mode 100644 index 0000000000000000000000000000000000000000..4187cace903d2f18b621caf5a500bb3dcac025d3 --- /dev/null +++ b/src/section/section_rectang.ts @@ -0,0 +1,43 @@ +import { acSection } from "./section_type"; + +/** + * Calculs de la section rectangulaire + */ +export class cSnRectang extends acSection { + constructor(oLog, oP, LargeurFond) { + super(oLog, oP); + this.LargeurBerge = LargeurFond; + } + /** + * Calcul du périmètre mouillé + * @param $rY Uniquement présent car la méthode parent à cet argument + * @return Périmètre mouillé (m) + */ + Calc_P($rY = 0) { + return this.LargeurBerge + super.Calc_P_Debordement(this.Y); + } + + Calc_dP() { + return super.Calc_dP_Debordement(); + } + + Calc_B() { + return super.Calc_B_Debordement(); + } + + Calc_dB() { + return super.Calc_dB_Debordement(); + } + + Calc_S() { + return super.Calc_S_Debordement(this.Y); + } + + /** + * Calcul du tirant d'eau conjugué avec la formule analytique pour la section rectangulaire + * @return tirant d'eau conjugué + */ + CalcYco() { + return this.Y * (Math.sqrt(1 + 8 * Math.pow(this.Calc('Fr'), 2)) - 1) / 2; + } +} \ No newline at end of file diff --git a/src/section/section_trapez.ts b/src/section/section_trapez.ts new file mode 100644 index 0000000000000000000000000000000000000000..4dc736f8c69795914ac17ee15312b07c8019c4a3 --- /dev/null +++ b/src/section/section_trapez.ts @@ -0,0 +1,114 @@ +import { acSection } from "./section_type"; + +/** + * Calculs de la section trapézoïdale + */ +export class cSnTrapez extends acSection { + public LargeurFond; /// Largeur au fond + public Fruit; /// Fruit des berges + constructor(oLog, oP, LargeurFond, Fruit) { + super(oLog, oP); + this.LargeurFond = LargeurFond; + this.Fruit = Fruit; + } + + Calc_B(bBerge = false) { + if (!bBerge && this.Y > this.oP.YB) { + return this.LargeurBerge; + } + else { + return this.LargeurFond + 2 * this.Fruit * this.Y; + } + } + + /** + * Calcul du périmètre mouillé + * @param $rY Uniquement présent car la méthode parent à cet argument + * @return Périmètre mouillé (m) + */ + Calc_P($rY = 0) { + if (this.Y > this.oP.YB) { + var P = this.CalcGeo('P') + super.Calc_P_Debordement(this.Y - this.oP.YB); + } + else { + P = this.LargeurFond + 2 * Math.sqrt(1 + Math.pow(this.Fruit, 2)) * this.Y; + } + //~ spip_log('Trapez->CalcP(rY='.$this->rY.')='.$P,'hydraulic.'._LOG_DEBUG); + return P; + } + + /** + * Calcul de la surface mouillée + * @param $rY Uniquement présent car la méthode parent à cet argument + * @return Surface mouillée (m2) + */ + Calc_S($rY = 0) { + if (this.Y > this.oP.YB) { + var S = this.CalcGeo('S') + super.Calc_S_Debordement(this.Y - this.oP.YB); + } + else { + S = this.Y * (this.LargeurFond + this.Fruit * this.Y); + } + //~ spip_log('Trapez->CalcS(rY='.$this->rY.')='.$S,'hydraulic.'._LOG_DEBUG); + return S; + } + + /** + * Calcul de dérivée de la surface hydraulique par rapport au tirant d'eau. + * @return dS + */ + Calc_dS() { + if (this.Y > this.oP.YB) { + return super.Calc_dS(); + } + else { + return this.LargeurFond + 2 * this.Fruit * this.Y; + } + } + + /** + * Calcul de dérivée du périmètre hydraulique par rapport au tirant d'eau. + * @return dP + */ + Calc_dP() { + if (this.Y > this.oP.YB) { + return super.Calc_dP_Debordement(); + } + else { + return 2 * Math.sqrt(1 + this.Fruit * this.Fruit); + } + } + + /** + * Calcul de dérivée de la largeur au miroir par rapport au tirant d'eau. + * @return dB + */ + Calc_dB() { + if (this.Y > this.oP.YB) { + return super.Calc_dB_Debordement(); + } + else { + return 2 * this.LargeurFond * this.Fruit; + } + } + /** + * Calcul de la distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @param $rY Uniquement présent car la méthode parent à cet argument + * @return S x Yg + */ + Calc_SYg($rY = 0) { + return (this.LargeurFond / 2 + this.Fruit * this.Y / 3) * Math.pow(this.Y, 2); + } + /** + * Calcul de la dérivée de la distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @param $rY Uniquement présent car la méthode parent à cet argument + * @return S x Yg + */ + Calc_dSYg($rY = 0) { + var SYg = this.Fruit / 3 * Math.pow(this.Y, 2); + SYg += (this.LargeurFond / 2 + this.Fruit * this.Y / 3) * 2 * this.Y; + return SYg; + } +} \ No newline at end of file diff --git a/src/section/section_type.ts b/src/section/section_type.ts new file mode 100644 index 0000000000000000000000000000000000000000..deb89b2e437dbe8c9f500a4af2082bf8df0b5c60 --- /dev/null +++ b/src/section/section_type.ts @@ -0,0 +1,756 @@ +import { acNewton } from "./newton"; +import { cLog } from "./log" +import { Debug } from "../base" +/** + * Calcul de la hauteur critique + */ +export class cHautCritique extends acNewton { + private Sn; + private oP; + /** + * Constructeur de la classe + * @param $oSn Section sur laquelle on fait le calcul + * @param $oP Paramètres supplémentaires (Débit, précision...) + */ + constructor(Sn: acSection, oP: cParamsCanal) { + super(oP); + this.Sn = Sn; + this.oP = oP; + + } + /** + * Calcul de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcFn($rX) { + // Calcul de la fonction + if (this.Sn.Calc('S', $rX) != 0) { + var Fn = (Math.pow(this.oP.Q, 2) * this.Sn.Calc('B', $rX) / Math.pow(this.Sn.Calc('S', $rX), 3) / this.oP.G - 1); + } + else { + Fn = Infinity; + } + return Fn; + } + /** + * Calcul analytique de la dérivée de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcDer($rX) { + if (this.Sn.Calc('S') != 0) { + // L'initialisation à partir de $rX a été faite lors de l'appel à CalcFn + var Der = (this.Sn.Calc('dB') * this.Sn.Calc('S') - 3 * this.Sn.Calc('B') * this.Sn.Calc('B')); + Der = Math.pow(this.oP.Q, 2) / this.oP.G * Der / Math.pow(this.Sn.Calc('S'), 4); + } + else { + Der = Infinity; + } + //spip_log('cHautCritique:CalcDer('.$rX.')='.$rDer,'hydraulic.'._LOG_DEBUG); + return Der; + } +} +/** + * Calcul de la hauteur normale + */ +export class cHautNormale extends acNewton { + private Sn; + private Q; + private Ks; + private If; + private G; + /** + * Constructeur de la classe + * @param $oSn Section sur laquelle on fait le calcul + * @param $oP Paramètres supplémentaires (Débit, précision...) + */ + constructor(Sn: acSection, oP: cParamsCanal) { + super(oP); + this.Sn = Sn; + this.Q = oP.Q; + this.Ks = oP.Ks; + this.If = oP.If; + this.G = oP.G; + } + /** + * Calcul de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcFn($rX) { + // Calcul de la fonction + var Fn = (this.Q - this.Ks * Math.pow(this.Sn.Calc('R', $rX), 2 / 3) * this.Sn.Calc('S', $rX) * Math.sqrt(this.If)); + return Fn; + } + /** + * Calcul analytique de la dérivée de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcDer($rX) { + // L'initialisation a été faite lors de l'appel à CalcFn + var Der = 2 / 3 * this.Sn.Calc('dR') * Math.pow(this.Sn.Calc('R'), -1 / 3) * this.Sn.Calc('S'); + Der = Der + Math.pow(this.Sn.Calc('R'), 2 / 3) * this.Sn.Calc('B'); + Der = Der * -this.Ks * Math.sqrt(this.If); + //spip_log('cHautNormale:CalcDer('.$rX.')='.$rDer,'hydraulic.'._LOG_DEBUG); + return Der; + } +} +/** + * Calcul de la hauteur correspondante (charge égale) + */ +export class cHautCorrespondante extends acNewton { + private Y; // Tirant d'eau connu + private rS2; // 1/S^2 associé au tirant d'eau connu + private Sn; // Section contenant les données de la section avec la hauteur à calculer + private rQ2G; // Constante de gravité + /** + * Constructeur de la classe + * @param $oSn Section sur laquelle on fait le calcul + * @param $oP Paramètres supplémentaires (Débit, précision...) + */ + constructor(Sn: acSection, oP: cParamsCanal) { + super(oP); + this.Y = Sn.Y; + this.rS2 = Math.pow(Sn.Calc('S'), -2); + this.Sn = Sn; + this.rQ2G = Math.pow(oP.Q, 2) / (2 * oP.G); + } + /** + * Calcul de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcFn($rX) { + // Calcul de la fonction + var Fn = this.Y - $rX + (this.rS2 - Math.pow(this.Sn.Calc('S', $rX), -2)) * this.rQ2G; + //~ spip_log('cHautCorrespondante:CalcFn('.$rX.')='.$rFn,'hydraulic.'._LOG_DEBUG); + return Fn; + } + /** + * Calcul analytique de la dérivée de la fonction dont on protected function cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcDer($rX) { + // L'initialisation a été faite lors de l'appel à CalcFn + if (this.Sn.Calc('S') != 0) { + var Der = -1 + 2 * this.rQ2G * this.Sn.Calc('B') / Math.pow(this.Sn.Calc('S'), 3); + } + else { + Der = Infinity; + } + //~ spip_log('cHautCorrespondante:CalcDer('.$rX.')='.$rDer,'hydraulic.'._LOG_DEBUG); + return Der; + } +} +/** + * Calcul de la hauteur conjuguée (Impulsion égale) + */ +export class cHautConjuguee extends acNewton { + /** Tirant d'eau connu */ + private Y; + /** 1/S^2 associé au tirant d'eau connu */ + private rS2; + /** Section contenant les données de la section avec la hauteur à calculer */ + private Sn; + /** Constante de gravité */ + private G; + /** Carré du débit */ + private rQ2; + /** Surface hydraulique associée au tirant d'eau connu */ + private rS; + /** SYg associée au tirant d'eau connu */ + private rSYg; + /** + * Constructeur de la classe + * @param $oSn Section sur laquelle on fait le calcul + * @param $oP Paramètres supplémentaires (Débit, précision...) + */ + constructor($oSn: acSection, $oP: cParamsCanal) { + super($oP); + this.Y = $oSn.Y; + this.rQ2 = Math.pow($oP.Q, 2); + this.Sn = $oSn; + this.G = $oP.G; + this.rS = $oSn.Calc('S'); + this.rSYg = $oSn.Calc('SYg'); + } + /** + * Calcul de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcFn($rX) { + // Réinitialisation des paramètres hydrauliques de oSn avec l'appel $this->oSn->Calc('S',$rX) + if (this.rS > 0 && this.Sn.Calc('S', $rX) > 0) { + var Fn = this.rQ2 * (1 / this.rS - 1 / this.Sn.Calc('S')); + Fn = Fn + this.G * (this.rSYg - this.Sn.Calc('SYg')); + } + else { + Fn = -Infinity; + } + //~ spip_log('cHautConjuguee:CalcFn('.$rX.')='.$rFn,'hydraulic.'._LOG_DEBUG); + return Fn; + } + /** + * Calcul analytique de la dérivée de la fonction dont on cherche le zéro + * @param $rX Variable dont dépend la fonction + */ + CalcDer($rX) { + // L'initialisation a été faite lors de l'appel à CalcFn + if (this.rS > 0 && this.Sn.Calc('S') > 0) { + var Der = this.rQ2 * this.Sn.Calc('dS') * Math.pow(this.Sn.Calc('S'), -2); + Der = Der - this.G * this.Sn.Calc('dSYg', $rX); + } + else { + Der = -Infinity; + } + //~ spip_log('cHautConjuguee:CalcDer('.$rX.')='.$rDer,'hydraulic.'._LOG_DEBUG); + return Der; + } +} + +/** + * Gestion des Paramètres du canal (hors section) + */ +export class cParamsCanal { + public YCL; /// Condition limite en cote à l'amont ou à l'aval + public Ks; /// Strickler + public Q; /// Débit + public Long; /// Longueur du bief + public If; /// Pente du fond + public Dx; /// Pas d'espace (positif en partant de l'aval, négatif en partant de l'amont) + public Prec; /// Précision de calcul et d'affichage + public G = 9.81;/// Constante de gravité + public iPrec; /// Précision en nombre de décimales + public YB; /// Hauteur de berge + public Resolution; /// Méthode de résolution "Euler" ou "RK4" + constructor($rKs, $rQ, $rIf, $rPrec, $rYB, $rYCL = 0, $rDx = 0, $rLong = 0, $sResolution = '') { + this.Resolution = $sResolution; + this.YCL = $rYCL; + this.Ks = $rKs; + this.Q = $rQ; + this.Long = $rLong; + this.If = $rIf; + this.Dx = $rDx; + this.Prec = $rPrec; + this.YB = $rYB; + this.iPrec = -Math.log($rPrec) / Math.log(10); + } +} + +/** + * Gestion commune pour les différents types de section. + * Comprend les formules pour la section rectangulaire pour gérer les débordements + */ +export abstract class acSection extends Debug { + + public Y; /// Tirant d'eau + public HautCritique; /// Tirant d'eau critique + public HautNormale; /// Tirant d'eau normal + public oP: cParamsCanal; /// Paramètres du système canal (classe oParam) + protected oLog: cLog; /// Pour l'affichage du journal de calcul + public LargeurBerge; /// largeur au débordement + protected bSnFermee = false; /// true si la section est fermée (fente de Preissmann) + /** + * Tableau contenant les données dépendantes du tirant d'eau $this->rY. + * + * Les clés du tableau peuvent être : + * - S : la surface hydraulique + * - P : le périmètre hydraulique + * - R : le rayon hydraulique + * - B : la largeur au miroir + * - J : la perte de charge + * - Fr : le nombre de Froude + * - dP : la dérivée de P par rapport Y + * - dR : la dérivée de R par rapport Y + * - dB : la dérivée de B par rapport Y + */ + private arCalc = {}; + protected calcGeo = {}; /// Données ne dépendant pas de la cote de l'eau + private Y_old; /// Mémorisation du tirant d'eau pour calcul intermédiaire + private Calc_old = {}; /// Mémorisation des données hydrauliques pour calcul intermédiaire + /** + * Nombre de points nécessaires pour le dessin de la section (hors point de berge) + * Valeur de 1 par défaut pour les sections rectangulaires et trapézoïdales + */ + protected nbDessinPoints = 1; + /** + * Construction de la classe. + * Calcul des hauteurs normale et critique + */ + constructor(oLog, oP, dbg = false) { + super(dbg); + this.oP = oP; + this.oLog = oLog; + this.CalcGeo['B']; + } + /** + * Efface toutes les données calculées pour forcer le recalcul + * @param $bGeo Réinitialise les données de géométrie aussi + */ + Reset(bGeo = true) { + this.arCalc = {}; + if (bGeo) { + this.calcGeo = {}; + } + } + /** + * Mémorise les données hydraulique en cours ou les restitue + * @param bMem true pour mémorisation, false pour restitution + */ + Swap(bMem) { + if (bMem) { + this.Y_old = this.Y; + this.Calc_old = this.arCalc; + } + else { + this.Y = this.Y_old; + this.arCalc = this.Calc_old; + this.Calc_old = {}; + } + } + + /** + * Calcul des données à la section + * @param $sDonnee Clé de la donnée à calculer (voir $this->$arCalc) + * @param $bRecalc Pour forcer le recalcul de la donnée + * @return la donnée calculée + */ + Calc(sDonnee, rY: number = undefined) { + if (rY != undefined && rY != this.Y) { + this.Y = rY; + // On efface toutes les données dépendantes de Y pour forcer le calcul + this.Reset(false); + } + // | or || ??? + if (this.arCalc[sDonnee] == undefined) { + // La donnée a besoin d'être calculée + switch (sDonnee) { + case 'I-J': // Variation linéaire de l'énergie spécifique (I-J) en m/m + this.arCalc[sDonnee] = this.oP.If - this.Calc('J'); + break; + case 'Yn': // Hauteur normale + return this.Calc_Yn(); + default: + var methode = 'Calc_' + sDonnee; + this.arCalc[sDonnee] = this[methode](); + } + } + //this.debug(sDonnee + ' ' + this.arCalc[sDonnee]); + return this.arCalc[sDonnee]; + } + + /** + * Calcul des données uniquement dépendantes de la géométrie de la section + * @param $sDonnee Clé de la donnée à calculer (voir $this->$arCalcGeo) + * @param $rY Hauteur d'eau + * @return la donnée calculée + */ + CalcGeo(sDonnee) { + this.debug("in CalcGeo"); + if (sDonnee != 'B' && !this.CalcGeo['B']) { + // Si la largeur aux berges n'a pas encore été calculée, on commence par ça + this.CalcGeo('B'); + } + if (!this.CalcGeo[sDonnee]) { + // La donnée a besoin d'être calculée + this.Swap(true); // On mémorise les données hydrauliques en cours + this.Reset(false); + this.Y = this.oP.YB; + switch (sDonnee) { + case 'B': // Largeur aux berges + this.CalcGeo[sDonnee] = this.Calc_B(); + if (this.calcGeo[sDonnee] < this.oP.YB / 100) { + // Section fermée + this.bSnFermee = true; + // On propose une fente de Preissmann égale à 1/100 de la hauteur des berges + this.CalcGeo[sDonnee] = this.oP.YB / 100; + } + this.LargeurBerge = this.CalcGeo[sDonnee]; + break; + default: + /*var methode = 'Calc_'+sDonnee + '()'; + this.CalcGeo[sDonnee] = eval(methode);*/ + var methode = 'Calc_' + sDonnee; + this.CalcGeo[sDonnee] = this[methode](); + this.debug("methodecalcgeo " + this[methode]()); + } + //~ spip_log('CalcGeo('.$sDCalcGeonnee.',rY='.$this->oP->rYB.')='.$this->arCalcGeo[$sDonnee],'hydraulic.'._LOG_DEBUG); + this.Swap(false); // On restitue les données hydrauliques en cours + } + this.debug('calcgeo ' + sDonnee + ' ' + this.CalcGeo[sDonnee]); + + return this.CalcGeo[sDonnee]; + } + + /** + * Calcul de la surface hydraulique. + * @return La surface hydraulique + */ + abstract Calc_S(); + + + Calc_dS() { + return this.Calc('B'); // largeur au miroir + } + + /** + * calcul de la surface hydraulique en cas de débordement + * @param Y hauteur d'eau au dela de la berge + **/ + Calc_S_Debordement(Y: number) { + return Y * this.LargeurBerge; + } + + /** + * Calcul de la dérivée surface hydraulique. + * @return La dérivée de la surface hydraulique + */ + //abstract Calc_dS(); + + /** + * Calcul de la dérivée surface hydraulique en cas de débordement + * @return La dérivée de la surface hydraulique en cas de débordement + */ + Calc_dS_Debordement() { + return this.LargeurBerge; + } + + /** + * Calcul du périmètre hydraulique. + * @return Le périmètre hydraulique + */ + abstract Calc_P(); + + /** + * Calcul du périmètre hydraulique en cas de débordement + * @param Y hauteur d'eau au dela de la berge + */ + Calc_P_Debordement(Y: number) { + return 2 * Y; + } + + /** + * Calcul de dérivée du périmètre hydraulique par rapport au tirant d'eau. + * @return dP + */ + abstract Calc_dP(); + + /** + * Calcul de dérivée du périmètre hydraulique par rapport au tirant d'eau en cas de débordement + * @return la dérivée du périmètre hydraulique par rapport au tirant d'eau en cas de débordement + */ + Calc_dP_Debordement() { + return 2; + } + + /** + * Calcul du rayon hydraulique. + * @return Le rayon hydraulique + */ + Calc_R() { + this.debug("in calc_R") + if (this.Calc('P') != 0) { + return this.Calc('S') / this.Calc('P'); + } + else { + return Infinity; + } + } + /** + * Calcul de dérivée du rayon hydraulique par rapport au tirant d'eau. + * @return dR + */ + Calc_dR() { + if (this.Calc('P') != 0) { + return (this.Calc('B') * this.Calc('P') - this.Calc('S') * this.Calc('dP') / Math.pow(this.Calc('P'), 2)); + } + else { + return 0; + } + } + + /** + * Calcul de la largeur au miroir. + * @return La largeur au miroir + */ + abstract Calc_B(); + + + /** + * Calcul de la largeur au miroir en cas de débordement + * @return La largeur au miroir en cas de débordement + */ + Calc_B_Debordement() { + return this.LargeurBerge; + } + + /** + * Calcul de dérivée de la largeur au miroir par rapport au tirant d'eau. + * @return dB + */ + abstract Calc_dB(); + + /** + * Calcul de dérivée de la largeur au miroir par rapport au tirant d'eau en cas de débordement + * @return la dérivée de la largeur au miroir par rapport au tirant d'eau en cas de débordement + */ + Calc_dB_Debordement() { + return 0; + } + + /** + * Calcul de la perte de charge par la formule de Manning-Strickler. + * @return La perte de charge + */ + Calc_J() { + if (this.Calc('R') != 0) { + return Math.pow(this.Calc('V') / this.oP.Ks, 2) / Math.pow(this.Calc('R'), 4 / 3); + } + else { + return Infinity; + } + } + /** + * Calcul du nombre de Froude. + * @return Le nombre de Froude + */ + Calc_Fr() { + if (this.Calc('S') != 0) { + return this.oP.Q / this.Calc('S') * Math.sqrt(this.Calc('B') / this.Calc('S') / this.oP.G); + } + else { + return Infinity; + } + } + /** + * Calcul de dy/dx + */ + Calc_dYdX(Y) { + // L'appel à Calc('J') avec Y en paramètre réinitialise toutes les données dépendantes de la ligne d'eau + return - (this.oP.If - this.Calc('J', Y) / (1 - Math.pow(this.Calc('Fr', Y), 2))); + } + + XOR(a, b) { + return (a || b) && !(a && b); + } + + /** + * Calcul du point suivant de la courbe de remous par la méthode Euler explicite. + * @return Tirant d'eau + */ + Calc_Y_Euler(Y) { + // L'appel à Calc('J') avec Y en paramètre réinitialise toutes les données dépendantes de la ligne d'eau + var Y2 = Y + this.oP.Dx * this.Calc_dYdX(Y); + if (this.XOR(this.oP.Dx > 0, !(Y2 < this.HautCritique))) { + return false; + } else { + return Y2; + } + } + /** + * Calcul du point suivant de la courbe de remous par la méthode RK4. + * @return Tirant d'eau + */ + Calc_Y_RK4(Y) { + // L'appel à Calc('J') avec Y en paramètre réinitialise toutes les données dépendantes de la ligne d'eau + var Dx = this.oP.Dx; + var k1 = this.Calc_dYdX(Y); + if (this.XOR(Dx > 0, !(Y + Dx / 2 * k1 < this.HautCritique))) { return false; } + var k2 = this.Calc_dYdX(Y + Dx / 2 * k1); + if (this.XOR(Dx > 0, !(Y + Dx / 2 * k2 < this.HautCritique))) { return false; } + var k3 = this.Calc_dYdX(Y + Dx / 2 * k2); + if (this.XOR(Dx > 0, !(Y + Dx / 2 * k3 < this.HautCritique))) { return false; } + var k4 = this.Calc_dYdX(Y + Dx * k3); + if (this.XOR(Dx > 0, !(Y + Dx / 6 * (k1 + 2 * (k2 + k3) + k4) < this.HautCritique))) { return false; } + return Y + Dx / 6 * (k1 + 2 * (k2 + k3) + k4); + } + /** + * Calcul du point suivant d'une courbe de remous + * @return Tirant d'eau + */ + Calc_Y($rY) { + var funcCalcY = 'Calc_Y_' + this.oP.Resolution; + var methods = Object.getOwnPropertyNames(this).filter(function (p) { + return typeof this[p] === 'function'; + }); + for (var m of methods) { + if (funcCalcY == m) { + return this[funcCalcY]($rY); + } + else { + return false; + } + } + } + + /** + * Calcul de la vitesse moyenne. + * @return Vitesse moyenne + */ + Calc_V() { + if (this.Calc('S') != 0) { + return this.oP.Q / this.Calc('S'); + } + else { + return Infinity; + } + } + /** + * Calcul de la charge spécifique. + * @return Charge spécifique + */ + Calc_Hs() { + return this.Y + Math.pow(this.Calc('V'), 2) / (2 * this.oP.G); + } + /** + * Calcul de la charge spécifique critique. + * @return Charge spécifique critique + */ + Calc_Hsc() { + this.Swap(true); // On mémorise les données hydrauliques en cours + // On calcule la charge avec la hauteur critique + var Hsc = this.Calc('Hs', this.CalcGeo('Yc')); + // On restitue les données initiales + this.Swap(false); + return Hsc; + } + /** + * Calcul du tirant d'eau critique. + * @return tirant d'eau critique + */ + Calc_Yc() { + this.debug("in calcYc"); + var hautCritique = new cHautCritique(this, this.oP); + /*if(!this.HautCritique == hautCritique.Newton(this.oP.YB) || !hautCritique.HasConverged()) { + //traduction de code de langue: + //this.oLog.Add(_T('hydraulic:h_critique')+' : '+_T('hydraulic:newton_non_convergence'),true); + }*/ + this.HautCritique = hautCritique.Newton(this.oP.YB); + return this.HautCritique; + } + /** + * Calcul du tirant d'eau normal. + * @return tirant d'eau normal + */ + Calc_Yn() { + this.debug("in calc_Yn"); + if (this.oP.If <= 0) { + this.HautNormale = false; + //this.oLog.Add(_T('hydraulic:h_normale_pente_neg_nul'),true); + } else { + var oHautNormale = new cHautNormale(this, this.oP); + //if(!this.HautNormale == oHautNormale.Newton(this.CalcGeo('Yc')) || !oHautNormale.HasConverged()) { + //this.oLog.Add(_T('hydraulic:h_normale').' : '._T('hydraulic:newton_non_convergence'),true); + this.HautNormale = oHautNormale.Newton(this.CalcGeo('Yc')); + this.debug("hautnormale" + this.HautNormale); + // } + } + return this.HautNormale; + } + /** + * Calcul du tirant d'eau fluvial. + * @return tirant d'eau fluvial + */ + Calc_Yf() { + if (this.Y > this.CalcGeo('Yc')) { + return this.Y; + } + else { + var oHautCorrespondante = new cHautCorrespondante(this, this.oP); + return oHautCorrespondante.Newton(this.Calc('Yc') * 2); + } + } + /** + * Calcul du tirant d'eau torrentiel. + * @return tirant d'eau torrentiel + */ + Calc_Yt() { + if (this.Y < this.CalcGeo('Yc')) { + return this.Y; + } + else { + var oHautCorrespondante = new cHautCorrespondante(this, this.oP); + return oHautCorrespondante.Newton(this.CalcGeo('Yc') / 2); + } + } + /** + * Calcul du tirant d'eau conjugué. + * @return tirant d'eau conjugué + */ + Calc_Yco() { + var oHautConj = new cHautConjuguee(this, this.oP); + // Choisir une valeur initiale du bon côté de la courbe + if (this.Calc('Fr') < 1) { + // Ecoulement fluvial, on cherche la conjuguée à partir du tirant d'eau torrentiel + var Y0 = this.Calc('Yt'); + } + else { + // Ecoulement torrentiel, on cherche la conjuguée à partir du tirant d'eau fluvial + Y0 = this.Calc('Yf'); + } + /* if(!Yco = oHautConj->Newton(Y0) || !oHautConj.HasConverged()) { + //$this->oLog->Add(_T('hydraulic:h_conjuguee').' : '._T('hydraulic:newton_non_convergence'),true); + } + return Yco;*/ // c quoi Yco ? + } + /** + * Calcul de la contrainte de cisaillement. + * @return contrainte de cisaillement + */ + Calc_Tau0() { + return 1000 * this.oP.G * this.Calc('R') * this.Calc('J'); + } + /** + * Calcul de la distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @return S x Yg + */ + Calc_SYg($rY) { + return Math.pow($rY, 2) * this.LargeurBerge / 2; + } + /** + * Calcul de la dérivée distance du centre de gravité de la section à la surface libre + * multiplié par la surface hydraulique + * @return S x Yg + */ + Calc_dSYg($rY) { + return $rY * this.LargeurBerge; + } + /** + * Calcul de l'impulsion hydraulique. + * @return Impulsion hydraulique + */ + Calc_Imp() { + return 1000 * (this.oP.Q * this.Calc('V') + this.oP.G * this.Calc('SYg')); + } + /** + * Calcul de l'angle Alpha entre la surface libre et le fond pour les sections circulaires. + * @return Angle Alpha pour une section circulaire, 0 sinon. + */ + Calc_Alpha() { + return 0; + } + /** + * Calcul de la dérivée de l'angle Alpha entre la surface libre et le fond pour les sections circulaires. + * @return Dérivée de l'angle Alpha pour une section circulaire, 0 sinon. + */ + Calc_dAlpha() { + return 0; + } + /** + * Fournit les coordonnées des points d'une demi section pour le dessin + * @return tableau de couples de coordonnées (x,y) + */ + /*DessinCoordonnees() { + var Pas = this.oP.YB / this.nbDessinPoints; + var Points = new Array(); + this.Swap(true); // On mémorise les données hydrauliques en cours + for(var Y=0; Y<this.oP.YB+Pas/2; Y=Y+Pas) { + //Y boolean or what ? + Points['x'][] = this.Calc('B',Y)/2; + Points['y'][] = Y; + } + // On restitue les données initiales + this.Swap(false); + return Points; + }*/ + +} + diff --git a/src/tsconfig.app.json b/src/tsconfig.app.json index b66f5dea9bddb60494f5d16e9ce6f7ce7de5eeb1..37d0e791fd2733723c0555bcae2f8d85adbc4dc7 100644 --- a/src/tsconfig.app.json +++ b/src/tsconfig.app.json @@ -1,10 +1,11 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "types": [] + "types": [], + "removeComments": false }, "include": [ "../src/**/*.ts" ], "exclude": [] -} +} \ No newline at end of file