diff --git a/DEVELOPERS.md b/DEVELOPERS.md index 9fedf8a7d73b4148023f358bb573708494cc3c39..c72be28a51340cf8f920f16de824ab971a84f314 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -348,6 +348,12 @@ describe("Class Addition: ", () => { }); ``` +#### fuzzy tests + +Fuzzy tests are automatically conducted on all Nub types, unless it is explicitly stated by adding a CalculatorType to `nubsNotTested` array in `spec/fuzzing.spec.ts`. + +For proper fuzzy testing on Nubs containing properties driven by an Enum, see "Further considerations for adding more complex modules" / "properties" below. + ### Expose classes Add exports in `index.ts` for the new classes: @@ -429,6 +435,14 @@ public Equation(sVarCalc: string): Result { } ``` +Also, to take advantage of typing a getter should be added to the parent's class, to return children with the correct type. Example with `Verificateur`: + +```typescript +public get children(): Espece[] { + return this._children as Espece[]; +} +``` + ## How to set up a new hydraulic structure equation @TODO diff --git a/package-lock.json b/package-lock.json index 4bd64c451af9abf2b2cd88d6dfc753237b245390..b7ca9d33ae09894833dbe38ac6e084cc7c4a936f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,14 +13,20 @@ "@babel/highlight": "^7.8.3" } }, + "@babel/helper-validator-identifier": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", + "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", + "dev": true + }, "@babel/highlight": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", - "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", "dev": true, "requires": { + "@babel/helper-validator-identifier": "^7.9.0", "chalk": "^2.0.0", - "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, @@ -36,21 +42,15 @@ "dev": true }, "@types/jasmine": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.9.tgz", - "integrity": "sha512-KNL2Fq6GRmty2j6+ZmueT/Z/dkctLNH+5DFoGHNDtcgt7yME9NZd8x2p81Yuea1Xux/qAryDd3zVLUoKpDz1TA==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.10.tgz", + "integrity": "sha512-3F8qpwBAiVc5+HPJeXJpbrl+XjawGmciN5LgiO7Gv1pl1RHtjoMNqZpqEksaPJW05ViKe8snYInRs6xB25Xdew==", "dev": true }, "@types/node": { - "version": "13.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz", - "integrity": "sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==", + "version": "13.11.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.1.tgz", + "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==", "dev": true }, "accepts": { @@ -130,15 +130,6 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, - "backbone": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz", - "integrity": "sha512-RLmDrRXkVdouTg38jcgHhyQ/2zjg7a8E6sz2zxfz21Hh17xDJYUHBZimVIt5fUyS8vbfpeSmTL3gUjTEvUV3qQ==", - "dev": true, - "requires": { - "underscore": ">=1.8.3" - } - }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -195,12 +186,6 @@ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -612,12 +597,6 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, "eventemitter3": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", @@ -689,15 +668,15 @@ } }, "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, "follow-redirects": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", - "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", "dev": true, "requires": { "debug": "^3.0.0" @@ -780,9 +759,9 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -812,15 +791,30 @@ "dev": true }, "handlebars": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz", - "integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==", + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "dev": true, "requires": { + "minimist": "^1.2.5", "neo-async": "^2.6.0", - "optimist": "^0.6.1", "source-map": "^0.6.1", - "uglify-js": "^3.1.4" + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } } }, "has-binary2": { @@ -992,13 +986,10 @@ "dev": true }, "isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", - "dev": true, - "requires": { - "buffer-alloc": "^1.2.0" - } + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.6.tgz", + "integrity": "sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==", + "dev": true }, "isexe": { "version": "2.0.0", @@ -1265,12 +1256,11 @@ } }, "karma": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz", - "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-5.0.1.tgz", + "integrity": "sha512-xrDGtZ0mykEQjx1BUHOP1ITi39MDsCGocmSvLJWHxUQpxuKwxk3ZUrC6HI2VWh1plLC6+7cA3B19m12yzO/FRw==", "dev": true, "requires": { - "bluebird": "^3.3.0", "body-parser": "^1.16.1", "braces": "^3.0.2", "chokidar": "^3.0.0", @@ -1282,20 +1272,19 @@ "glob": "^7.1.1", "graceful-fs": "^4.1.2", "http-proxy": "^1.13.0", - "isbinaryfile": "^3.0.0", + "isbinaryfile": "^4.0.2", "lodash": "^4.17.14", "log4js": "^4.0.0", "mime": "^2.3.1", "minimatch": "^3.0.2", - "optimist": "^0.6.1", "qjobs": "^1.1.4", "range-parser": "^1.2.0", "rimraf": "^2.6.0", - "safe-buffer": "^5.0.1", "socket.io": "2.1.1", "source-map": "^0.6.1", "tmp": "0.0.33", - "useragent": "2.3.0" + "ua-parser-js": "0.7.21", + "yargs": "^15.3.1" }, "dependencies": { "rimraf": { @@ -1306,6 +1295,35 @@ "requires": { "glob": "^7.1.3" } + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + } + }, + "yargs-parser": { + "version": "18.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.2.tgz", + "integrity": "sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, @@ -1328,9 +1346,9 @@ } }, "karma-jasmine-html-reporter": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.2.tgz", - "integrity": "sha512-ILBPsXqQ3eomq+oaQsM311/jxsypw5/d0LnZXj26XkfThwq7jZ55A2CFSKJVA5VekbbOGvMyv7d3juZj0SeTxA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.3.tgz", + "integrity": "sha512-ci0VrjuCaFj+9d1tYlTE3KIPUCp0rz874zWWU3JgCMqGIyw5ke+BXWFPOAGAqUdCJcrMwneyvp1zFXA74MiPUA==", "dev": true }, "lcid": { @@ -1399,16 +1417,6 @@ } } }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, "lunr": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", @@ -1422,9 +1430,9 @@ "dev": true }, "marked": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz", - "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz", + "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==", "dev": true }, "media-typer": { @@ -1478,12 +1486,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, "mkdirp": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", @@ -1689,9 +1691,9 @@ } }, "picomatch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, "pify": { @@ -1706,12 +1708,6 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", @@ -1958,9 +1954,9 @@ } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safer-buffer": { @@ -2292,9 +2288,9 @@ "dev": true }, "tslint": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.0.tgz", - "integrity": "sha512-fXjYd/61vU6da04E505OZQGb2VCN2Mq3doeWcOIryuG+eqdmFUXTYVwdhnbEu2k46LNLgUYt9bI5icQze/j0bQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.1.tgz", + "integrity": "sha512-kd6AQ/IgPRpLn6g5TozqzPdGNZ0q0jtXW4//hRcj10qLYBaa3mTUU2y2MCG+RXZm8Zx+KZi0eA+YCrMyNlF4UA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2305,7 +2301,7 @@ "glob": "^7.1.1", "js-yaml": "^3.13.1", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", + "mkdirp": "^0.5.3", "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.10.0", @@ -2313,18 +2309,18 @@ }, "dependencies": { "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } } } @@ -2349,22 +2345,21 @@ } }, "typedoc": { - "version": "0.16.11", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.16.11.tgz", - "integrity": "sha512-YEa5i0/n0yYmLJISJ5+po6seYfJQJ5lQYcHCPF9ffTF92DB/TAZO/QrazX5skPHNPtmlIht5FdTXCM2kC7jQFQ==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.17.4.tgz", + "integrity": "sha512-4Lotef1l6lNU5Fulpux809WPlF9CkmcXfv5QFyanrjYlxMFxSdARRdsy8Jv1OU3z0vjR4JsvUQT0YpiPqztcOA==", "dev": true, "requires": { - "@types/minimatch": "3.0.3", "fs-extra": "^8.1.0", - "handlebars": "^4.7.2", - "highlight.js": "^9.17.1", + "handlebars": "^4.7.6", + "highlight.js": "^9.18.1", "lodash": "^4.17.15", - "marked": "^0.8.0", + "lunr": "^2.3.8", + "marked": "0.8.2", "minimatch": "^3.0.0", "progress": "^2.0.3", "shelljs": "^0.8.3", - "typedoc-default-themes": "^0.7.2", - "typescript": "3.7.x" + "typedoc-default-themes": "^0.10.0" }, "dependencies": { "fs-extra": { @@ -2381,15 +2376,12 @@ } }, "typedoc-default-themes": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.7.2.tgz", - "integrity": "sha512-fiFKlFO6VTqjcno8w6WpTsbCgXmfPHVjnLfYkmByZE7moaz+E2DSpAT+oHtDHv7E0BM5kAhPrHJELP2J2Y2T9A==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.1.tgz", + "integrity": "sha512-SuqAQI0CkwhqSJ2kaVTgl37cWs733uy9UGUqwtcds8pkFK8oRF4rZmCq+FXTGIb9hIUOu40rf5Kojg0Ha6akeg==", "dev": true, "requires": { - "backbone": "^1.4.0", - "jquery": "^3.4.1", - "lunr": "^2.3.8", - "underscore": "^1.9.1" + "lunr": "^2.3.8" } }, "typescript": { @@ -2398,15 +2390,20 @@ "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", "dev": true }, + "ua-parser-js": { + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", + "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==", + "dev": true + }, "uglify-js": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.0.tgz", - "integrity": "sha512-ugNSTT8ierCsDHso2jkBHXYrU8Y5/fY2ZUprfrJUiD7YpuFvV4jODLFmb3h4btQjqr5Nh4TX4XtgDfCU1WdioQ==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.0.tgz", + "integrity": "sha512-j5wNQBWaql8gr06dOUrfaohHlscboQZ9B8sNsoK5o4sBjm7Ht9dxSbrMXyktQpA16Acaij8AcoozteaPYZON0g==", "dev": true, "optional": true, "requires": { - "commander": "~2.20.3", - "source-map": "~0.6.1" + "commander": "~2.20.3" } }, "ultron": { @@ -2433,16 +2430,6 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, - "useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", - "dev": true, - "requires": { - "lru-cache": "4.1.x", - "tmp": "0.0.x" - } - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2486,12 +2473,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -2545,14 +2526,6 @@ "async-limiter": "~1.0.0", "safe-buffer": "~5.1.0", "ultron": "~1.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "xmlhttprequest-ssl": { @@ -2567,12 +2540,6 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, "yargs": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", diff --git a/package.json b/package.json index a9623252c76aff82013b866ac514afa9b739896b..1f450cc9ff78c14a1762803a7d0f68187ec6c33f 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,8 @@ "base-64": "^0.1.0" }, "devDependencies": { - "@types/jasmine": "^3.5.9", - "@types/node": "^13.9.1", + "@types/jasmine": "^3.5.10", + "@types/node": "^13.11.1", "buffer": "^5.5.0", "find": "^0.3.0", "jasmine": "^3.5.0", @@ -52,7 +52,7 @@ "karma": "^4.4.1", "karma-chrome-launcher": "^3.1.0", "karma-jasmine": "^3.1.1", - "karma-jasmine-html-reporter": "^1.5.2", + "karma-jasmine-html-reporter": "^1.5.3", "replace-in-file": "^5.0.2", "requirejs": "^2.3.6", "rimraf": "^3.0.2", diff --git a/spec/fuzzing.spec.ts b/spec/fuzzing.spec.ts index ae16bcca44b38c6cd335c4d78453853a95619b2a..c7ef1746cc42e93ec008fc03ebcce5ca9e69a589 100644 --- a/spec/fuzzing.spec.ts +++ b/spec/fuzzing.spec.ts @@ -40,7 +40,9 @@ const nubsNotTested: CalculatorType[] = [ CalculatorType.Section, CalculatorType.CloisonAval, CalculatorType.Solveur, - CalculatorType.YAXN + CalculatorType.YAXN, + CalculatorType.Verificateur, + CalculatorType.Espece ]; const nubsWithStructures: CalculatorType[] = [ diff --git a/spec/verificateur/verificateur.spec.ts b/spec/verificateur/verificateur.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..331394b6d3823713c34fa6bcc5f14e95e52bc902 --- /dev/null +++ b/spec/verificateur/verificateur.spec.ts @@ -0,0 +1,533 @@ +import { Session } from "../../src/session"; +import { Verificateur } from "../../src/verification/verificateur"; +import { Pab } from "../../src/pab/pab"; +import { Props } from "../../src/props"; +import { CalculatorType } from "../../src/compute-node"; +import { CloisonAval } from "../../src/pab/cloison_aval"; +import { FishSpecies } from "../../src/verification/fish_species"; +import { StructureJetTypeStrict } from "../../src/structure/structure"; +import { ParSimulation } from "../../src/par/par_simulation"; +import { MacroRugo } from "../../src/macrorugo/macrorugo"; +import { MacrorugoCompound } from "../../src/macrorugo/macrorugo_compound"; +import { MRCInclination, MessageCode, ParType } from "../../src/index"; +import { StructureWeirSubmergedLarinier } from "../../src/structure/structure_weir_submerged_larinier"; +import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params"; + +function createPab(): Pab { + const pab = Session.getInstance().createSessionNub( + new Props({ calcType: CalculatorType.Pab }) + ) as Pab; + const dw = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.CloisonAval }) + ) as CloisonAval; + dw.addChild(Session.getInstance().createNub( + new Props({ + calcType: CalculatorType.Structure, + loiDebit: dw.getDefaultLoiDebit() + }) + )); + pab.downWall = dw + return pab; +} + +function loadExamplePab(): Pab { + const sess = `{"header":{"source":"jalhyd","format_version":"1.3","created":"2020-04-03T07:34:45.155Z"},"settings":{"precision":1e-7,"maxIterations":100,"displayPrecision":3},"documentation":"","session":[{"uid":"Y3k4bj","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"ampiN3","props":{"calcType":"Cloisons"},"children":[{"uid":"Yzgxa2","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":28.085},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":27.413},{"symbol":"ZRAM","mode":"SINGLE","value":27.526},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"c3RmMz","props":{"calcType":"Cloisons"},"children":[{"uid":"dmwyem","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.858},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":27.186},{"symbol":"ZRAM","mode":"SINGLE","value":27.299},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"cTlydj","props":{"calcType":"Cloisons"},"children":[{"uid":"cWQ5aX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.631},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":26.959},{"symbol":"ZRAM","mode":"SINGLE","value":27.072},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"emRkMX","props":{"calcType":"Cloisons"},"children":[{"uid":"aG1xbj","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.404},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":26.731},{"symbol":"ZRAM","mode":"SINGLE","value":26.845},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"eG9hdT","props":{"calcType":"Cloisons"},"children":[{"uid":"M3Z5ZX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.177},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":26.504},{"symbol":"ZRAM","mode":"SINGLE","value":26.618},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":1.8},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":28.778}],"downWall":{"uid":"bWExN2","props":{"calcType":"CloisonAval"},"children":[{"uid":"bm0zcD","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":26.95},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":26.391}]}}]}`; + Session.getInstance().clear(); + Session.getInstance().unserialise(sess); + const p = Session.getInstance().findNubByUid("Y3k4bj") as Pab; + return p; +} + +function createPar(): ParSimulation { + const par = Session.getInstance().createSessionNub( + new Props({ calcType: CalculatorType.ParSimulation }) + ) as ParSimulation; + return par; +} + +function createMR(): MacroRugo { + const mr = Session.getInstance().createSessionNub( + new Props({ calcType: CalculatorType.MacroRugo }) + ) as MacroRugo; + return mr; +} + +function createMRC(): MacrorugoCompound { + const mrc = Session.getInstance().createSessionNub( + new Props({ calcType: CalculatorType.MacroRugoCompound }) + ) as MacrorugoCompound; + mrc.inclinedApron = MRCInclination.INCLINED; + return mrc; +} + +fdescribe("vérificateur de franchissement −", () => { + + describe("PAB −", () => { + + it("0 espèces", () => { + // contexte + Session.getInstance().clear(); + const pab = createPab(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(0); + }); + + it("Surface, 1 espèce prédéfinie", () => { + // contexte + Session.getInstance().clear(); + const pab = createPab(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.pabJetType = StructureJetTypeStrict.SURFACE; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); + + it("Plongeant, 1 espèce prédéfinie", () => { + // contexte + Session.getInstance().clear(); + const pab = createPab(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.pabJetType = StructureJetTypeStrict.PLONGEANT; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); + + // wrong jet types + it("Type de jets", () => { + // contexte + const pab = loadExamplePab(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.pabJetType = StructureJetTypeStrict.PLONGEANT; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(6); // 5 cloisons + 1 downwall + expect(res.log.messages[2].code).toBe(MessageCode.ERROR_VERIF_PAB_JETS); + expect(res.log.messages[5].code).toBe(MessageCode.ERROR_VERIF_PAB_JETS_DW); + }); + + // falls on Cloison / downwall + it("Chute trop importante", () => { + // contexte + const pab = loadExamplePab(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.pabJetType = StructureJetTypeStrict.SURFACE; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_9a]); // 0.25 < 0.27 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(6); // 5 cloisons + 1 downwall + expect(res.log.messages[2].code).toBe(MessageCode.ERROR_VERIF_PAB_DHMAX); + expect(res.log.messages[5].code).toBe(MessageCode.ERROR_VERIF_PAB_DHMAX_DW); + }); + + // weirs and slots witdh + it("Largeur des fentes et échancrures trop faible (surface)", () => { + // contexte + const pab = loadExamplePab(); + pab.children[2].structures[0].getParameter("L").singleValue = 0.35; // Fente noyée (Larinier 1992) + pab.children[4].structures[0] = new StructureWeirSubmergedLarinier( // Échancrure (Villemonte 1957) + pab.children[4].structures[0].prms as RectangularStructureParams + ); + pab.children[4].structures[0].getParameter("L").singleValue = 0.35; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.pabJetType = StructureJetTypeStrict.SURFACE; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_3b]); // 0.35 < 0.4 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(2); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAB_BMIN); + expect(res.log.messages[1].code).toBe(MessageCode.ERROR_VERIF_PAB_BMIN); + }); + + // basins depth @TODO comment on fait pour faire des bassins moins profonds dans une Pab ? + /* fit("Profondeur des bassins insuffisante", () => { + }); */ + + // depth < 2x fall @TODO comment on fait pour faire des chutes plus importantes dans une Pab ? + /* it("Profondeur des bassins < 2* la chute (plongeant)", () => { + }); */ + + // head on weirs @TODO comment on fait une Pab à jets plongeants ? + /* fit("Charge trop faible sur échancrures (plongeant)", () => { + }); */ + + // basins length + it("Longueur de bassin trop faible", () => { + // contexte + const pab = loadExamplePab(); + pab.children[1].prms.LB.singleValue = 2.25; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.pabJetType = StructureJetTypeStrict.SURFACE; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); // 2.25 < 2.5 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAB_LMIN); + }); + + }); + + describe("PAR −", () => { + + it("1 espèce prédéfinie", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_2]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); + + // downstream fall + it("Chute en pied de passe", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.prms.Z2.singleValue = 7; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_2]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAR_DH); + }); + + // species groups 3a, 3b, 7b are discouraged + it("Espèce non recommandées", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_3a]); + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_7b]); + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_3b]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(3); + expect(res.log.messages[0].code).toBe(MessageCode.WARNING_VERIF_PAR_SPECIES_GROUP); + expect(res.log.messages[1].code).toBe(MessageCode.WARNING_VERIF_PAR_SPECIES_GROUP); + expect(res.log.messages[2].code).toBe(MessageCode.WARNING_VERIF_PAR_SPECIES_GROUP); + }); + + // water level, plane & fatou + it("Tirant d'eau insuffisant (plane)", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.parType = ParType.PLANE; + par.calculatedParam = par.prms.Z1; + par.prms.Q.singleValue = 0.05; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); // 0.297 < 0.3 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAR_YMIN); + }); + + it("Tirant d'eau insuffisant (fatou)", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.parType = ParType.FATOU; + par.calculatedParam = par.prms.Z1; + par.prms.Q.singleValue = 0.05; + par.prms.Nb.singleValue = undefined; + par.prms.ZR1.singleValue = undefined; + par.prms.ZR2.singleValue = undefined; + par.prms.P.singleValue = undefined; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_4b]); // 0.175 < 0.2 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAR_YMIN); + }); + + // water level, superactive & chevron + it("Tirant d'eau insuffisant (superactive)", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.parType = ParType.SUPERACTIVE; + par.calculatedParam = par.prms.Z1; + par.prms.Q.singleValue = 0.1; + par.prms.S.singleValue = 0.15; + par.prms.Nb.singleValue = undefined; + par.prms.ZR1.singleValue = undefined; + par.prms.ZR2.singleValue = undefined; + par.prms.P.singleValue = undefined; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_4b]); // 0.158 < 0.2 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAR_YMIN); + }); + + it("Tirant d'eau insuffisant (chevron)", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.parType = ParType.CHEVRON; + par.calculatedParam = par.prms.Z1; + par.prms.Q.singleValue = 0.1; + par.prms.S.singleValue = 0.15; + par.prms.Nb.singleValue = undefined; + par.prms.ZR1.singleValue = undefined; + par.prms.ZR2.singleValue = undefined; + par.prms.P.singleValue = undefined; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_4b]); // 0.129 < 0.2 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAR_YMIN); + }); + + // slopes + it("Pente trop élevée (plane)", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.parType = ParType.PLANE; + par.prms.S.singleValue = 0.21; // > 0.2 + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(0); + // expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_PAR_YMIN); + }); + }); + + describe("MacroRugo −", () => { + + it("1 espèce prédéfinie", () => { + // contexte + Session.getInstance().clear(); + const mr = createMR(); + mr.prms.B.singleValue = 2.218; // 2 patterns + // vérificateur + const v = new Verificateur(); + v.nubToVerify = mr; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_3b]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); + + // speed + it("Vitesse trop élevée", () => { + // contexte + Session.getInstance().clear(); + const mr = createMR(); + mr.prms.B.singleValue = 2.218; // 2 patterns + // vérificateur + const v = new Verificateur(); + v.nubToVerify = mr; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); // 2.533 > 2.50 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_MR_VMAX); + }); + + // water level + it("Tirant d'eau trop faible", () => { + // contexte + Session.getInstance().clear(); + const mr = createMR(); + mr.prms.B.singleValue = 2.218; // 2 patterns + mr.prms.Y.singleValue = 0.3; + // vérificateur + const v = new Verificateur(); + v.nubToVerify = mr; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); // 0.3 < 0.4 + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_MR_YMIN); + }); + }); + + describe("MacroRugoCompound −", () => { + + it("1 espèce prédéfinie", () => { + // contexte + Session.getInstance().clear(); + const mrc = createMRC(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = mrc; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_4a]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); + + // at least one apron OK, but not all @TODO problème de vitesse, régler le cas MR Vitesse d'abord + /* fit("1 radier OK, mais pas tous", () => { + // contexte + Session.getInstance().clear(); + const mrc = createMRC(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = mrc; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_4a]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); */ + + // no apron OK @TODO problème de vitesse, régler le cas MR Vitesse d'abord + /* it("Aucun radier OK", () => { + // contexte + Session.getInstance().clear(); + const mrc = createMRC(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = mrc; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_4a]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(true); + expect(res.vCalc).toBe(1); + expect(res.log.messages.length).toBe(0); + }); */ + }); + + describe("cas d'erreur −", () => { + + it("instanciation directe de SPECIES_CUSTOM", () => { + // contexte + Session.getInstance().clear(); + const pab = createPab(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = pab; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_CUSTOM]); + // résultat + expect(() => { + v.CalcSerie(); + }).toThrow(); + }); + + // species / pass combination that has no preset + it("PAR, espèce non gérée", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_9b]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_NO_PRESET); + }); + + // pass with errors + it("PAR, erreur fatale", () => { + // contexte + Session.getInstance().clear(); + const par = createPar(); + par.prms.Nb.singleValue = 123; // wrong number of baffles + // vérificateur + const v = new Verificateur(); + v.nubToVerify = par; + v.speciesList.push(FishSpecies[FishSpecies.SPECIES_1]); + // résultat + const res = v.CalcSerie(); + expect(res.ok).toBe(false); + expect(res.vCalc).toBe(0); + expect(res.log.messages.length).toBe(1); + expect(res.log.messages[0].code).toBe(MessageCode.ERROR_VERIF_ERRORS_IN_PASS); + }); + + }); + +}); diff --git a/src/compute-node.ts b/src/compute-node.ts index fcbdb03441a7abe7740efc4b379d32e58ae8e217..497cbf6eb1c8e48fc9219a223cdc31f5eda58e4c 100644 --- a/src/compute-node.ts +++ b/src/compute-node.ts @@ -37,7 +37,9 @@ export enum CalculatorType { YAXN, // Y = A.X^N ConcentrationBlocs, Par, // Passe à ralentisseurs, calage - ParSimulation // Passe à ralentisseurs, simulation + ParSimulation, // Passe à ralentisseurs, simulation + Espece, // Critères de vérification pour une espèce de poissons + Verificateur // Vérificateur de contraintes sur une passe pour une ou plusieurs espèces } /** types de sections */ diff --git a/src/fish_pass.ts b/src/fish_pass.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f17f46dc3e0028a487a7fdb1400222a0230fcd4 --- /dev/null +++ b/src/fish_pass.ts @@ -0,0 +1,7 @@ +import { Nub } from "./nub"; + +/** + * An intermediate class for all fish passes (Pab, Par, MacroRugo[Compound]…), + * just for the sake of typing + */ +export abstract class FishPass extends Nub { } diff --git a/src/index.ts b/src/index.ts index 2df502bc04e6b33ff3774a7b5c1e9bb5f3cff1d2..34877b9fbbef397349b4246410920e391ec63320 100644 --- a/src/index.ts +++ b/src/index.ts @@ -86,3 +86,8 @@ export * from "./par/par"; export * from "./par/par_params"; export * from "./par/par_simulation"; export * from "./par/par_simulation_params"; +export * from "./verification/espece"; +export * from "./verification/espece_params"; +export * from "./verification/verificateur"; +export * from "./verification/verificateur_params"; +export * from "./fish_pass"; diff --git a/src/macrorugo/macrorugo.ts b/src/macrorugo/macrorugo.ts index 1a5b13a8c80d4a725c6746ea41f1bd0141aef537..9f37d46e04ac0b61de1370b58a6bd14bad7c280d 100644 --- a/src/macrorugo/macrorugo.ts +++ b/src/macrorugo/macrorugo.ts @@ -1,7 +1,6 @@ import { CalculatorType } from "../compute-node"; import { Dichotomie } from "../dichotomie"; import { MacrorugoCompound } from "../index"; -import { Nub } from "../nub"; import { ParamCalculability, ParamFamily } from "../param/param-definition"; import { ParamValueMode } from "../param/param-value-mode"; import { SessionSettings } from "../session_settings"; @@ -9,6 +8,7 @@ import { Message, MessageCode } from "../util/message"; import { Result } from "../util/result"; import { MacrorugoParams } from "./macrorugo_params"; import { MRCInclination } from "./mrc-inclination"; +import { FishPass } from "../fish_pass"; export enum MacroRugoFlowType { EMERGENT, @@ -16,7 +16,7 @@ export enum MacroRugoFlowType { SUBMERGED } -export class MacroRugo extends Nub { +export class MacroRugo extends FishPass { private static readonly g = 9.81; diff --git a/src/pab/pab.ts b/src/pab/pab.ts index acf358ce32337598218b30f7a3ea1cd626ab0ac2..dcebbdb83dc6aa3005fb70956528fbbab6a0fa39 100644 --- a/src/pab/pab.ts +++ b/src/pab/pab.ts @@ -16,8 +16,9 @@ import { CloisonAval } from "./cloison_aval"; import { CloisonsAvalParams } from "./cloison_aval_params"; import { Cloisons } from "./cloisons"; import { PabParams } from "./pab_params"; +import { FishPass } from "../fish_pass"; -export class Pab extends Nub { +export class Pab extends FishPass { /** * paramètres castés au bon type diff --git a/src/par/par.ts b/src/par/par.ts index 8e6281645777a0afd536a4a65f47f3f91c0c5b79..0011196dca8cb4ad907a6b5646b4db0c98a056c9 100644 --- a/src/par/par.ts +++ b/src/par/par.ts @@ -1,5 +1,4 @@ import { CalculatorType } from "../compute-node"; -import { Nub } from "../nub"; import { ParamCalculability } from "../param/param-definition"; import { Observer } from "../util/observer"; import { Result } from "../util/result"; @@ -12,6 +11,7 @@ import { ParTypeChevron } from "./par_type_chevron"; import { Message, MessageCode } from "../util/message"; import { ResultElement } from "../util/resultelement"; import { isLowerThan, isGreaterThan } from "../base"; +import { FishPass } from "../fish_pass"; /** Type de Passe à Ralentisseurs */ export enum ParType { @@ -21,7 +21,7 @@ export enum ParType { CHEVRON } -export class Par extends Nub implements Observer { +export class Par extends FishPass implements Observer { protected parCalc: ParTypeAbstract; diff --git a/src/session.ts b/src/session.ts index 0163f2005972439b9c15ad12f5988305c540e6b3..8473bddd4228705cf2b3ba750593d0cdbe09ac3f 100644 --- a/src/session.ts +++ b/src/session.ts @@ -76,6 +76,12 @@ import { Par, ParType } from "./par/par"; import { ParParams } from "./par/par_params"; import { ParSimulation } from "./par/par_simulation"; import { ParSimulationParams } from "./par/par_simulation_params"; +import { FishSpecies } from "./verification/fish_species"; +import { StructureJetTypeStrict } from "./structure/structure"; +import { Espece } from "./verification/espece"; +import { EspeceParams } from "./verification/espece_params"; +import { Verificateur } from "./verification/verificateur"; +import { VerificateurParams } from "./verification/verificateur_params"; export class Session { @@ -94,7 +100,10 @@ export class Session { calcType: CalculatorType, structureType: StructureType, inclinedApron: MRCInclination, - parType: ParType + parType: ParType, + species: FishSpecies, + pabJetType: StructureJetTypeStrict, + }; public static getInstance(): Session { @@ -690,6 +699,27 @@ export class Session { ); break; + case CalculatorType.Espece: + nub = new Espece( + // default params are those for SPECIES_1 (Salmons and trouts) + new EspeceParams( + 0.35, // DHMax + 0.3, // BMIn + 1, // PMin + 2.5, // LMin + 0.3, // HMin + 0.4, // YMin + 2.5, // VMax + 0.2, // YMinSB + 0.3 // YMinPB + ) + ); + break; + + case CalculatorType.Verificateur: + nub = new Verificateur(new VerificateurParams()); + break; + default: throw new Error( `Session.createNub() : type de module '${CalculatorType[calcType]}' non pris en charge` diff --git a/src/solveur/solveur.ts b/src/solveur/solveur.ts index 8fd138a899b8f5f151163cb102182958a0f4f838..2f83fc85d1a5e62bd12620c1942105121fdb54a3 100644 --- a/src/solveur/solveur.ts +++ b/src/solveur/solveur.ts @@ -39,6 +39,7 @@ export class Solveur extends Nub implements Observer { constructor(prms: SolveurParams, dbg: boolean = false) { super(prms, dbg); this._calcType = CalculatorType.Solveur; + this._childrenType = "Espece" this._props.addObserver(this); this.prms.addObserver(this); // UID of Session Nub to calculate, the result of the which must be this.prms.Ytarget.singleValue diff --git a/src/structure/structure.ts b/src/structure/structure.ts index ad090a6e2c9b59fb9ebcdeeb1d8b999f78c09882..26249151dea9648e9af8344bcd74ee698220838f 100644 --- a/src/structure/structure.ts +++ b/src/structure/structure.ts @@ -33,12 +33,21 @@ export enum StructureFlowRegime { NULL } -/** - * Type de jet : Sans objet (orifice), plongeant, de surface - */ +/** Type de jet : Sans objet (orifice), plongeant, de surface */ export enum StructureJetType { + /** Plongeant */ + PLONGEANT, + /** De surface */ + SURFACE, /** Sans objet (orifice) */ - SO, + SO +} +/** + * Type de jet, sans l'option "Sans objet" + * @WARNING clodo trick: synchroniser les valeurs avec StructureJetType ! + * @TODO faire hériter StructureJetType de cet enum lorsque ce sera possible dans TypeScript + */ +export enum StructureJetTypeStrict { /** Plongeant */ PLONGEANT, /** De surface */ @@ -90,18 +99,18 @@ export abstract class Structure extends ChildNub { super.setProperties(props); } - get isZDVcalculable(): boolean { + public get isZDVcalculable(): boolean { return this._isZDVcalculable; } /** * paramètres castés au bon type */ - get prms(): StructureParams { + public get prms(): StructureParams { return this._prms as StructureParams; } - get W(): number { + public get W(): number { if (this.prms.W.visible) { return this.prms.W.v; } else { @@ -109,6 +118,10 @@ export abstract class Structure extends ChildNub { } } + public get loiDebit(): LoiDebit { + return this._loiDebit; + } + /** * Returns the nth visible parameter (used in nghyd/PabTable) */ diff --git a/src/util/message.ts b/src/util/message.ts index dbc2ffab79d3d90b3fe7c32315087d2f400aa9ef..b20bc4a7efc2f652cd759340ce4031df54cd0802 100644 --- a/src/util/message.ts +++ b/src/util/message.ts @@ -96,18 +96,6 @@ export enum MessageCode { /** Les valeurs de %var_ZR% et %var_ZD% ne correspondent pas : soit %var_ZR% devrait valoir %expectedZR%, soit %var_ZD% devrait valoir %expectedZD% */ ERROR_PAR_ZR_ZD_MISMATCH, - /** - * Passe à ralentisseurs: la valeur donnée de P est plus de 10% plus petite / plus de 5% - * plus grande que la valeur standard %stdP% - */ - ERROR_PAR_P_DEVIATES_MORE_THAN_10_5_PCT, - - /** La valeur %val% de Q* sort de l'intervalle de validité [ %min%, %max% ] donné par les abaques */ - ERROR_PAR_QSTAR_OUT_OF_RANGE, - - /** La valeur %val% de ha sort de l'intervalle de validité [ %min%, %max% ] donné par les abaques */ - ERROR_PAR_HA_OUT_OF_RANGE, - /** * Something failed in certain steps (but not all), when calculating upstream Nubs with varying parameter */ @@ -204,6 +192,63 @@ export enum MessageCode { /** Solveur : interdiction de faire varier des paramètres dans le Nub calculé */ ERROR_SOLVEUR_NO_VARIATED_PARAMS_ALLOWED, + /** Vérificateur : la passe à vérifier contient des erreurs */ + ERROR_VERIF_ERRORS_IN_PASS, + + /** Vérificateur, passe à macrorugosités : vitesse max. %V% trop élevée (maximum: %maxV%) */ + ERROR_VERIF_MR_VMAX, + + /** Vérificateur, passe à macrorugosités : tirant d'eau %Y% insuffisant (minimum: %minY%) */ + ERROR_VERIF_MR_YMIN, + + /** Vérificateur, passe à macrorugosités complexe : au moins un radier doit être franchissable */ + ERROR_VERIF_MRC_AT_LEAST_ONE_APRON, + + /** Vérificateur, passe à macrorugosités complexe : vitesse max. %V% trop élevée (maximum: %maxV%) dans le radier %N% */ + ERROR_VERIF_MRC_VMAX_APRON_N, + + /** Vérificateur, passe à macrorugosités complexe : tirant d'eau %Y% insuffisant (minimum: %minY%) dans le radier %N% */ + ERROR_VERIF_MRC_YMIN_APRON_N, + + /** Vérificateur : aucun jeu de contraintes pour le couple espèce / type de passe */ + ERROR_VERIF_NO_PRESET, + + /** Vérificateur, passe à bassins : chute %DH% trop importante (maximum: %maxDH%) dans la cloison %N% */ + ERROR_VERIF_PAB_DHMAX, + + /** Vérificateur, passe à bassins : chute %DH% trop importante (maximum: %maxDH%) dans la cloison aval */ + ERROR_VERIF_PAB_DHMAX_DW, + + /** Vérificateur, passe à bassins : largeur de l'échancrure ou de la fente %L% insuffisante (minimum: %minB%) dans la cloison %NC%, ouvrage %NS% */ + ERROR_VERIF_PAB_BMIN, + + /** Vérificateur, passe à bassins : au moins un jet de type %required% requis, jets de type %forbidden% interdits, dans la cloison %N% */ + ERROR_VERIF_PAB_JETS, + + /** Vérificateur, passe à bassins : au moins un jet de type %required% requis, jets de type %forbidden% interdits, dans la cloison aval */ + ERROR_VERIF_PAB_JETS_DW, + + /** Vérificateur, passe à bassins : longueur de bassin %LB% insuffisante (minimum: %minLB%) dans la cloison %N% */ + ERROR_VERIF_PAB_LMIN, + + /** Vérificateur, passe à bassins : charge sur l'échancrure %h1% insuffisante (minimum: %minH%) dans la cloison %NC%, ouvrage %NS% */ + ERROR_VERIF_PAB_HMIN, + + /** Vérificateur, passe à bassins : profondeur de bassin %PB% insuffisante (minimum: %minPB%) dans la cloison %N% */ + ERROR_VERIF_PAB_YMOY, + + /** Vérificateur, passe à bassins à jet mlongeant : profondeur de bassin %PB% inférieure à 2x la chute %DH% dans la cloison %N% */ + ERROR_VERIF_PAB_YMOY_2_DH, + + /** Vérificateur, passe à ralentisseurs : présence d'une chute en bas de passe */ + ERROR_VERIF_PAR_DH, + + /** Vérificateur, passe à ralentisseurs : tirant d'eau %h% insuffisant (minimum: %minY%) */ + ERROR_VERIF_PAR_YMIN, + + /** Vérificateur, passe à ralentisseurs : les groupes d'espèces 3a, 3b et 7b sont déconseillés */ + WARNING_VERIF_PAR_SPECIES_GROUP, + /** * internationalisation : langue non prise en charge */ diff --git a/src/verification/espece.ts b/src/verification/espece.ts new file mode 100644 index 0000000000000000000000000000000000000000..b957efa90404b8d943b5b76841bfec6244ed0887 --- /dev/null +++ b/src/verification/espece.ts @@ -0,0 +1,645 @@ +import { Nub } from "../nub"; +import { EspeceParams } from "./espece_params"; +import { CalculatorType } from "../compute-node"; +import { Observer } from "../util/observer"; +import { ParamCalculability } from "../param/param-definition"; +import { FishSpecies } from "./fish_species"; +import { Result } from "../util/result"; +import { FishPass } from "../fish_pass"; +import { StructureJetTypeStrict } from "../structure/structure"; +import { Message, MessageCode } from "../util/message"; +import { ParSimulation } from "../par/par_simulation"; +import { ParType } from "../par/par"; +import { MacroRugo } from "../macrorugo/macrorugo"; +import { ResultElement } from "../util/resultelement"; +import { MacrorugoCompound } from "../macrorugo/macrorugo_compound"; +import { Pab } from "../pab/pab"; +import { LoiDebit } from "../structure/structure_props"; +import { RectangularStructureParams } from "../structure/rectangular_structure_params"; +import { Cloisons } from "../pab/cloisons"; +import { ParallelStructure } from "../structure/parallel_structure"; + +/** + * Settings for a given fish species (or custom settings), to verify crossing capacities on fish passes. + * Meant to be used with Verificateur. + */ +export class Espece extends Nub implements Observer { + + /** Multidimension table of parameters values presets, by pass type and species */ + protected presets: any; + + /** + * The Pab, ParSimulation, or MacroRugo[Compound] to check (Par are not supposed to be checked). + * Passed by the Verificateur + */ + protected _passToCheck: FishPass; + + /** + * When checking a Pab, expected jet type for every Cloison. + * Passed by the Verificateur + */ + public pabJetType: StructureJetTypeStrict; + + /** + * For variating passes, index of the result to examine. + * Passed by the Verificateur + */ + public indexToCheck: number; + + constructor(prms: EspeceParams, dbg: boolean = false) { + super(prms, dbg); + this._calcType = CalculatorType.Espece; + this._props.addObserver(this); + // defaults to CUSTOM mode, for GUI instanciation + this.species = FishSpecies.SPECIES_CUSTOM; + this.indexToCheck = 0; + this.calculatedParam = this.prms.OK; + this.resetDefaultCalculatedParam(); + + // presets + // Source: Informations sur la Continuité Ecologique (ICE), Onema 2014 + this.presets = {}; + // PAB + this.presets[CalculatorType.Pab] = {}; + // PAB - Plongeant + this.presets[CalculatorType.Pab][StructureJetTypeStrict.PLONGEANT] = {}; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.PLONGEANT][FishSpecies.SPECIES_1] = { + DHMax: 0.75, + PMin: 1, + HMin: 0.3, + LMin: 2 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.PLONGEANT][FishSpecies.SPECIES_2] = { + DHMax: 0.6, + PMin: 0.75, + HMin: 0.2, + LMin: 1.25 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.PLONGEANT][FishSpecies.SPECIES_4a] = { + DHMax: 0.4, + PMin: 0.75, + HMin: 0.2, + LMin: 1.25 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.PLONGEANT][FishSpecies.SPECIES_4b] = + this.presets[CalculatorType.Pab][StructureJetTypeStrict.PLONGEANT][FishSpecies.SPECIES_6] = { + DHMax: 0.3, + PMin: 0.75, + HMin: 0.2, + LMin: 1 + }; + // PAB - Surface + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE] = {}; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_1] = { + DHMax: 0.35, + BMin: 0.3, + PMin: 1, + LMin: 2.5 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_2] = { + DHMax: 0.35, + BMin: 0.2, + PMin: 1, + LMin: 1.75 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_3a] = + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_3b] = { + DHMax: 0.3, + BMin: 0.4, + PMin: 1, + LMin: 3.5 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_3c] = { + DHMax: 0.3, + BMin: 0.15, + PMin: 1, + LMin: 1.25 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_4a] = { + DHMax: 0.35, + BMin: 0.2, + PMin: 1, + LMin: 1.75 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_4b] = { + DHMax: 0.3, + BMin: 0.15, + PMin: 0.75, + LMin: 1.25 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_5] = { + DHMax: 0.3, + BMin: 0.3, + PMin: 0.75, + LMin: 2.5 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_6] = { + DHMax: 0.3, + BMin: 0.2, + PMin: 0.75, + LMin: 1.75 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_7a] = { + DHMax: 0.3, + BMin: 0.25, + PMin: 0.75, + LMin: 2 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_7b] = { + DHMax: 0.3, + BMin: 0.15, + PMin: 0.75, + LMin: 1.25 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_8a] = + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_8b] = + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_8c] = + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_8d] = { + DHMax: 0.25, + BMin: 0.3, + PMin: 0.75, + LMin: 2.5 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_9a] = { + DHMax: 0.25, + BMin: 0.25, + PMin: 0.75, + LMin: 2 + }; + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_9b] = + this.presets[CalculatorType.Pab][StructureJetTypeStrict.SURFACE][FishSpecies.SPECIES_10] = { + DHMax: 0.2, + BMin: 0.15, + PMin: 0.5, + LMin: 1.25 + }; + // PAR Simulation + this.presets[CalculatorType.ParSimulation] = {}; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_1] = { + YMinSB: 0.2, + YMinPB: 0.3 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_2] = { + YMinSB: 0.15, + YMinPB: 0.25 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_3a] = { + YMinSB: 0.2, + YMinPB: 0.3 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_3b] = { + YMinSB: 0.15, + YMinPB: 0.25 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_3c] = { + YMinSB: 0.1, + YMinPB: 0.1 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_4a] = { + YMinSB: 0.15, + YMinPB: 0.25 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_4b] = { + YMinSB: 0.1, + YMinPB: 0.2 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_5] = { + YMinSB: 0.2, + YMinPB: 0.3 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_6] = { + YMinSB: 0.15, + YMinPB: 0.25 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_7a] = { + YMinSB: 0.15, + YMinPB: 0.25 + }; + this.presets[CalculatorType.ParSimulation][FishSpecies.SPECIES_7b] = { + YMinSB: 0.1, + YMinPB: 0.1 + }; + // MacroRugo + this.presets[CalculatorType.MacroRugo] = {}; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_1] = { + YMin: 0.4, + VMax: 2.5 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_2] = { + YMin: 0.3, + VMax: 2.5 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3a] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3b] = { + YMin: 0.4, + VMax: 2 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_3c] = { + YMin: 0.15, + VMax: 2 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_4a] = { + YMin: 0.3, + VMax: 2 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_4b] = { + YMin: 0.2, + VMax: 2 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_5] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_6] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_7a] = { + YMin: 0.3, + VMax: 2 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_7b] = { + YMin: 0.15, + VMax: 2 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8a] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8b] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8c] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_8d] = { + YMin: 0.3, + VMax: 1.5 + }; + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_9a] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_9b] = + this.presets[CalculatorType.MacroRugo][FishSpecies.SPECIES_10] = { + YMin: 0.2, + VMax: 1.5 + }; + } + + public get prms(): EspeceParams { + return this._prms as EspeceParams; + } + + public get species(): FishSpecies { + return this._props.getPropValue("species") as FishSpecies; + } + + /** Changing the fish species will load adequate predefined values */ + public set species(s: FishSpecies) { + this.properties.setPropValue("species", s); + } + + public set passToCheck(p: FishPass) { + this._passToCheck = p; + this.loadPredefinedParametersValues(); + } + + /** Returns 1 if the fish can go through the pass, 0 if it cannot */ + public Equation(sVarCalc: string): Result { + // default result is 1 (OK) + const res = new Result(1, this); + + const sp = this.species; + // detect pass characteristics and species + let pt = this._passToCheck.calcType; + // MacroRugoCompound is just a repetition of the MacroRugo check + if (pt === CalculatorType.MacroRugoCompound) { + pt = CalculatorType.MacroRugo; + } + + // load preset + let preset = this.presets[pt]; + if (pt === CalculatorType.Pab && this.pabJetType !== undefined) { + preset = preset[this.pabJetType]; + } + + // get result to examine + const r = this._passToCheck.result.resultElements[this.indexToCheck]; + if (r === undefined) { + throw new Error(`Espece.Equation(): pass to check has no resultElements[${this.indexToCheck}]`); + } + + // is there a valid preset for the pass type / species couple ? + if (preset[sp] === undefined) { + res.vCalc = 0; + res.log.add(new Message(MessageCode.ERROR_VERIF_NO_PRESET)); + return res; + + } else { + // normal processing + switch (this._passToCheck.calcType) { // not pt, to detect MacroRugoCompound + case CalculatorType.Pab: + const passB = this._passToCheck as Pab; + + // 1. jet types + let cloisonNumber = 1; + for (const c of passB.children) { + this.checkJetTypes(c, cloisonNumber, res); + cloisonNumber++; + } + // downwall + this.checkJetTypes(passB.downWall, undefined, res); + + // 2. falls + cloisonNumber = 1; + for (const c of passB.children) { + const iRes = c.result.resultElements[this.indexToCheck]; + if (iRes.values.DH > this.prms.DHMax.singleValue) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_DHMAX); + m.extraVar.N = cloisonNumber; + m.extraVar.DH = iRes.values.DH; + m.extraVar.maxDH = this.prms.DHMax.singleValue; + res.log.add(m); + } + cloisonNumber++; + } + // downwall + const ca = passB.downWall; + const iRes = ca.result.resultElements[this.indexToCheck]; + if (iRes.values.DH > this.prms.DHMax.singleValue) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_DHMAX_DW); + m.extraVar.DH = iRes.values.DH; + m.extraVar.maxDH = this.prms.DHMax.singleValue; + res.log.add(m); + } + + // 3. weirs and slots witdh + if (this.pabJetType === StructureJetTypeStrict.SURFACE) { + cloisonNumber = 1; + for (const c of passB.children) { + let structureNumber = 1; + for (const s of c.structures) { + // for "Villemonte 1947" ("échancrure") or "Fente noyée (Larinier 1992)" ("fente") only + if ([ LoiDebit.WeirVillemonte, LoiDebit.WeirSubmergedLarinier ].includes(s.loiDebit)) { + const structParams = s.prms as RectangularStructureParams; + if (structParams.L.v < this.prms.BMin.singleValue) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_BMIN); + m.extraVar.NC = cloisonNumber; + m.extraVar.NS = structureNumber; + m.extraVar.L = structParams.L.v; + m.extraVar.minB = this.prms.BMin.singleValue; + res.log.add(m); + } + } + structureNumber++; + } + cloisonNumber++; + } + } + // @TODO downwall + + // 4. basins depth + cloisonNumber = 1; + for (const c of passB.children) { + const iRes = c.result.resultElements[this.indexToCheck]; + if (iRes.values.YMOY < this.prms.PMin.singleValue) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_YMOY); + m.extraVar.N = cloisonNumber; + m.extraVar.PB = iRes.values.YMOY; + m.extraVar.minPB = this.prms.PMin.singleValue; + res.log.add(m); + } + if (this.pabJetType === StructureJetTypeStrict.PLONGEANT) { + // depth < 2x fall + if (iRes.values.DH < (2 * iRes.values.DH)) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_YMOY_2_DH); + m.extraVar.N = cloisonNumber; + m.extraVar.PB = iRes.values.YMOY; + m.extraVar.DH = iRes.values.DH; + res.log.add(m); + } + } + cloisonNumber++; + } + + // 5. head on weirs + if (this.pabJetType === StructureJetTypeStrict.PLONGEANT) { + cloisonNumber = 1; + for (const c of passB.children) { + let structureNumber = 1; + for (const s of c.structures) { + // for "Villemonte 1947" ("échancrure") only + if (s.loiDebit === LoiDebit.WeirVillemonte && s.prms.h1.v < this.prms.HMin.singleValue) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_HMIN); + m.extraVar.NC = cloisonNumber; + m.extraVar.NS = structureNumber; + m.extraVar.h1 = s.prms.h1.v; + m.extraVar.minH = this.prms.HMin.singleValue; + res.log.add(m); + } + structureNumber++; + } + cloisonNumber++; + } + } + // @TODO downwall + + // 6. basins length + cloisonNumber = 1; + for (const c of passB.children) { + if (c.prms.LB.singleValue < this.prms.LMin.singleValue) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAB_LMIN); + m.extraVar.N = cloisonNumber; + m.extraVar.LB = c.prms.LB.singleValue; + m.extraVar.minL = this.prms.LMin.singleValue; + res.log.add(m); + } + cloisonNumber++; + } + break; + + case CalculatorType.ParSimulation: + const passR = this._passToCheck as ParSimulation; + + // 1. no downstream fall + if (r.values.DH > 0) { + res.vCalc = 0; + res.log.add(new Message(MessageCode.ERROR_VERIF_PAR_DH)); + } + + // 2. species groups 3a, 3b, 7b are discouraged + if ([ FishSpecies.SPECIES_3a, FishSpecies.SPECIES_3b, FishSpecies.SPECIES_7b ].includes(this.species)) { + res.log.add(new Message(MessageCode.WARNING_VERIF_PAR_SPECIES_GROUP)); + } + + // 3. water level + let minY: number; + if ([ ParType.PLANE, ParType.FATOU ].includes(passR.parType)) { + minY = this.prms.YMinPB.singleValue; + } else if ([ ParType.SUPERACTIVE, ParType.CHEVRON ].includes(passR.parType)) { + minY = this.prms.YMinSB.singleValue; + } + if (r.values.h < minY) { + res.vCalc = 0; + const m = new Message(MessageCode.ERROR_VERIF_PAR_YMIN); + m.extraVar.h = r.values.h; + m.extraVar.minY = minY; + res.log.add(m); + } + + // 4. slopes are already managed by ParSimulation + break; + + case CalculatorType.MacroRugoCompound: + const passMRC = this._passToCheck as MacrorugoCompound; + let atLeastOneOK = false; + let apronNumber = 1; + // loop on aprons with MacroRugo check; at least one is required + for (const mr of passMRC.children) { + const mrRes = this.checkMacroRugo(mr, mr.result.resultElements[this.indexToCheck], res, apronNumber); + if (mrRes === 1) { + atLeastOneOK = true; + } + apronNumber++; + } + if (! atLeastOneOK) { + res.vCalc = 0; + res.log.add(new Message(MessageCode.ERROR_VERIF_MRC_AT_LEAST_ONE_APRON)); + } + break; + + case CalculatorType.MacroRugo: + res.vCalc = this.checkMacroRugo(this._passToCheck as MacroRugo, r, res); + break; + + default: + // should never happen + } + } + + return res; + } + + public update(sender: any, data: any): void { + if (data.action === "propertyChange") { + if (data.name === "species") { + this.loadPredefinedParametersValues(); + // no parameter visibility update: GUI will never show anything but SPECIES_CUSTOM mode, + // where all parameters are visible + } + } + } + + /** + * Checks the jet type on every structure of the given wall of a Pab + * @param c the Pab wall to check + * @param cloisonNumber the number of the current wall inthe Pab, undefined means downwall + * @param res the current result to add logs to, and set value + */ + protected checkJetTypes(c: ParallelStructure, cloisonNumber: number, res: Result): boolean { + let nbSurface = 0; + let nbPlongeant = 0; + // test jet type for each device + for (const s of c.structures) { + const jt = s.result.resultElements[this.indexToCheck].values["ENUM_StructureJetTypeStrict"]; + if (jt === StructureJetTypeStrict.SURFACE) { + nbSurface++; + } else if (jt === StructureJetTypeStrict.PLONGEANT) { + nbPlongeant++; + } + } + let jetsOK: boolean; + let forbiddenJetType: StructureJetTypeStrict; + if (this.pabJetType === StructureJetTypeStrict.SURFACE) { + jetsOK = (nbSurface > 0 && nbPlongeant === 0); + forbiddenJetType = StructureJetTypeStrict.PLONGEANT; + } else if (this.pabJetType === StructureJetTypeStrict.PLONGEANT) { + jetsOK = (nbSurface === 0 && nbPlongeant > 0); + forbiddenJetType = StructureJetTypeStrict.SURFACE; + } + if (! jetsOK) { + res.vCalc = 0; + let m: Message; + if (cloisonNumber === undefined) { + m = new Message(MessageCode.ERROR_VERIF_PAB_JETS_DW); + } else { + m = new Message(MessageCode.ERROR_VERIF_PAB_JETS); + m.extraVar.N = cloisonNumber; + } + m.extraVar.required = this.pabJetType; + m.extraVar.forbidden = forbiddenJetType; + res.log.add(m); + } + return jetsOK; + } + + /** + * Checks a MacroRugo pass (factorized to use when checking MacroRugoCompound) + * @param pass the MacroRugo pass to check + * @param passResult the current result of the pass to check + * @param verifResult the result of the check, to add logs to + */ + protected checkMacroRugo(pass: MacroRugo, passResult: ResultElement, verifResult: Result, apronNumber?: number): number { + let val = 1; + + // 1. water level + if (pass.prms.Y.V < this.prms.YMin.singleValue) { + val = 0; + let m: Message; + if (apronNumber !== undefined) { + m = new Message(MessageCode.ERROR_VERIF_MRC_YMIN_APRON_N); + m.extraVar.N = apronNumber; + } else { + m = new Message(MessageCode.ERROR_VERIF_MR_YMIN); + } + m.extraVar.Y = pass.prms.Y.V; + m.extraVar.minY = this.prms.YMin.singleValue; + verifResult.log.add(m); + } + + // 2. speed + if (passResult.values.VMax > this.prms.VMax.singleValue) { + val = 0; + let m: Message; + if (apronNumber !== undefined) { + m = new Message(MessageCode.ERROR_VERIF_MRC_VMAX_APRON_N); + m.extraVar.N = apronNumber; + } else { + m = new Message(MessageCode.ERROR_VERIF_MR_VMAX); + } + m.extraVar.V = passResult.values.VMax; + m.extraVar.maxV = this.prms.VMax.singleValue; + verifResult.log.add(m); + } + return val; + } + + /** + * Load ICE tables values into parameters, depending on species + * and pass to check + */ + protected loadPredefinedParametersValues() { + if (this.species !== FishSpecies.SPECIES_CUSTOM && this._passToCheck !== undefined) { + const sp = this.species; + let pt = this._passToCheck.calcType; + // MacroRugoCompound is just a repetition of the MacroRugo check + if (pt === CalculatorType.MacroRugoCompound) { + pt = CalculatorType.MacroRugo; + } + // type de jet pour les PAB + console.log(`load predefined values for species=${FishSpecies[sp].substring(8)} and pass class=${CalculatorType[pt]}`); + for (const p of this.prms) { + if (p.symbol !== "OK") { + let preset = this.presets[pt]; + if (pt === CalculatorType.Pab && this.pabJetType !== undefined) { + preset = preset[this.pabJetType]; + } + if (preset[sp] !== undefined) { + // if (preset[sp][p.symbol] !== undefined) console.log(`-> setting ${p.symbol} to ${preset[sp][p.symbol]}`); + p.singleValue = preset[sp][p.symbol]; + } + } + } + } + } + /** Parameters other than OK are just settings here, nothing can vary or be calculated */ + protected setParametersCalculability(): void { + for (const p of this._prms) { + p.calculability = ParamCalculability.FIXED; + } + this.prms.OK.calculability = ParamCalculability.EQUATION; + } + +} diff --git a/src/verification/espece_params.ts b/src/verification/espece_params.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed7982353ae771a9172d5259d50045e9e77db5c5 --- /dev/null +++ b/src/verification/espece_params.ts @@ -0,0 +1,119 @@ +import { ParamsEquation } from "../param/params-equation"; +import { ParamDefinition, ParamFamily } from "../param/param-definition"; +import { ParamDomainValue } from "../param/param-domain"; + +export class EspeceParams extends ParamsEquation { + + /** Résultat de la vérification (seul paramètre calculable) */ + private _OK: ParamDefinition; + + /** Chute maximale (m) */ + private _DHMax: ParamDefinition; + + /** Chute préconisée (m) */ + // private _DH: ParamDefinition; + + /** Largeur minimale de fente ou échancrure latérale (m) (PAB jet de surface) */ + private _BMin: ParamDefinition; + + /** Profondeur minimale de bassin (m) (PAB, MacroRugo rangées périodiques) */ + private _PMin: ParamDefinition; + + /** Longueur minimale de bassins (m) (PAB) */ + private _LMin: ParamDefinition; + + /** Charge minimale sur l'échancrure (m) (PAB jet plongeant) */ + private _HMin: ParamDefinition; + + /** Charge minimale sur les seuils (m) (MacroRugo à rangées périodiques - on ne les fait pas ?) */ + // private _HMinW: ParamDefinition; + + /** Tirant d'eau minimum (m) (MacroRugo enrochements régulièrement répartis) */ + private _YMin: ParamDefinition; + + /** Vitesse d'écoulement maximale (m) (MacroRugo enrochements régulièrement répartis) */ + private _VMax: ParamDefinition; + + /** Tirant d'eau minimum sur les ralentisseurs suractifs de fond (m) */ + private _YMinSB: ParamDefinition; + + /** Tirant d'eau minimum sur les ralentisseurs plans (m) */ + private _YMinPB: ParamDefinition; + + constructor(rDHMax: number/* , rDH: number */, rBMin?: number, rPMin?: number, rLMin?: number, rHMin?: number/* , rHMinW?: number */, rYMin?: number, rVMax?: number, rYMinSB?: number, rYMinPB?: number) { + super(); + this._OK = new ParamDefinition(this, "OK", ParamDomainValue.POS, ""); + this._DHMax = new ParamDefinition(this, "DHMax", ParamDomainValue.POS, "m", rDHMax); + // this._DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, "m", rDH); + this._BMin = new ParamDefinition(this, "BMin", ParamDomainValue.POS, "m", rBMin); + this._PMin = new ParamDefinition(this, "PMin", ParamDomainValue.POS, "m", rPMin); + this._LMin = new ParamDefinition(this, "LMin", ParamDomainValue.POS, "m", rLMin); + this._HMin = new ParamDefinition(this, "HMin", ParamDomainValue.POS, "m", rHMin); + // this._HMinW = new ParamDefinition(this, "HMinW", ParamDomainValue.POS, "m", rHMinW); + this._YMin = new ParamDefinition(this, "YMin", ParamDomainValue.POS, "m", rYMin); + this._VMax = new ParamDefinition(this, "VMax", ParamDomainValue.POS, "m", rVMax); + this._YMinSB = new ParamDefinition(this, "YMinSB", ParamDomainValue.POS, "m", rYMinSB); + this._YMinPB = new ParamDefinition(this, "YMinPB", ParamDomainValue.POS, "m", rYMinPB); + + this.addParamDefinition(this._OK); + this.addParamDefinition(this._DHMax); + // this.addParamDefinition(this._DH); + this.addParamDefinition(this._BMin); + this.addParamDefinition(this._PMin); + this.addParamDefinition(this._LMin); + this.addParamDefinition(this._HMin); + // this.addParamDefinition(this._HMinW); + this.addParamDefinition(this._YMin); + this.addParamDefinition(this._VMax); + this.addParamDefinition(this._YMinSB); + this.addParamDefinition(this._YMinPB); + } + + public get OK(): ParamDefinition { + return this._OK; + } + + public get DHMax(): ParamDefinition { + return this._DHMax; + } + + /* public get DH(): ParamDefinition { + return this._DH; + } */ + + public get BMin(): ParamDefinition { + return this._BMin; + } + + public get PMin(): ParamDefinition { + return this._PMin; + } + + public get LMin(): ParamDefinition { + return this._LMin; + } + + public get HMin(): ParamDefinition { + return this._HMin; + } + + /* public get HMinW(): ParamDefinition { + return this._HMinW; + } */ + + public get YMin(): ParamDefinition { + return this._YMin; + } + + public get VMax(): ParamDefinition { + return this._VMax; + } + + public get YMinSB(): ParamDefinition { + return this._YMinSB; + } + + public get YMinPB(): ParamDefinition { + return this._YMinPB; + } +} diff --git a/src/verification/fish_species.ts b/src/verification/fish_species.ts new file mode 100644 index 0000000000000000000000000000000000000000..785aefe2be6207a98b04064dbd08ecac6293b7cd --- /dev/null +++ b/src/verification/fish_species.ts @@ -0,0 +1,26 @@ +/** + * Predefined crossing capabilities criteria for different fish species + * Source: Informations sur la Continuité Ecologique (ICE), Onema 2014 + * @see Espece + */ +export enum FishSpecies { + SPECIES_CUSTOM, + SPECIES_1, // Saumon atlantique (Salmo salar), Truite de mer ou de rivière [50-100] (Salmo trutta) + SPECIES_2, // Mulets (Chelon labrosus, Liza ramada) + SPECIES_3a, // Grande alose (Alosa alosa) + SPECIES_3b, // Alose feinte (Alosa fallax fallax) + SPECIES_3c, // Lamproie marine (Petromyzon marinus) + SPECIES_4a, // Truite de rivière ou truite de mer [25-55] (Salmo trutta) + SPECIES_4b, // Truite de rivière [15-30] (Salmo trutta) + SPECIES_5, // Aspe (Aspius aspius), Brochet (Esox lucius) + SPECIES_6, // Ombre commun (Thymallus thymallus) + SPECIES_7a, // Barbeau fluviatile (Barbus barbus), Chevaine (Squalius cephalus), Hotu (Chondrostoma nasus) + SPECIES_7b, // Lamproie fluviatile (Lampetra fluviatilis) + SPECIES_8a, // Carpe commune (Cyprinus carpio) + SPECIES_8b, // Brème commune (Abramis brama), Sandre (Sander lucioperca) + SPECIES_8c, // Brème bordelière (Blicca bjoerkna), Ide melanote (Leuciscus idus), Lotte de rivière (Lota lota), Perche (Perca fluviatilis), Tanche (Tinca tinca) + SPECIES_8d, // Vandoises (Leuciscus sp hors Idus) + SPECIES_9a, // Ablette commune (Alburnus alburnus), Ablette sprirlin (Alburnoides bipunctatus), Barbeau méridional (Barbus meridionalis), Blageon (Telestes souffia), Carassin commun (Carassius carassius), Carassin argenté (Carassius gibelio), Gardon (Rutilus rutilus), Rotengle (Scardinius erythrophthalmus), Toxostome (Parachondrostoma toxostoma) + SPECIES_9b, // Apron (Zingel asper), Chabots (Cottus sp), Goujons (Gobio sp), Grémille (Gymnocephalus cernuus), Lamproie de Planer (Lampetra planeri), Loche franche ( Barbatula barbatula), Loche de rivière (Cobitis taenia) + SPECIES_10 // Able de Heckel (Leucaspius delineatus), Bouvière (Rhodeus amarus), Epinoche (Gasterosteus gymnurus), Epinochette (Pungitius laevis), Vairons (Phoxinus sp) +} diff --git a/src/verification/verificateur.ts b/src/verification/verificateur.ts new file mode 100644 index 0000000000000000000000000000000000000000..e050792888f48d18f7fedb2a98231ad1b36e25ef --- /dev/null +++ b/src/verification/verificateur.ts @@ -0,0 +1,158 @@ +import { Nub } from "../nub"; +import { Observer } from "../util/observer"; +import { CalculatorType } from "../compute-node"; +import { Session } from "../session"; +import { Result } from "../util/result"; +import { Espece } from "./espece"; +import { FishSpecies } from "./fish_species"; +import { EspeceParams } from "./espece_params"; +import { FishPass } from "../fish_pass"; +import { ParamCalculability } from "../param/param-definition"; +import { Message, MessageCode } from "../util/message"; +import { VerificateurParams } from "./verificateur_params"; +import { StructureJetTypeStrict } from "../structure/structure"; + +export class Verificateur extends Nub implements Observer { + + constructor(prms?: VerificateurParams, dbg: boolean = false) { + super(new VerificateurParams(), dbg); + this._calcType = CalculatorType.Verificateur; + this._props.addObserver(this); + // UID of Session Nub to verify + this.nubToVerify = undefined; + // Jet type when verifying a Pab + this.pabJetType = StructureJetTypeStrict.SURFACE; + // List of fish species to check the pass against + this.speciesList = []; + this.calculatedParam = this.prms.OK; + this.resetDefaultCalculatedParam(); + } + + public get prms(): VerificateurParams { + return this._prms as VerificateurParams; + } + + public get speciesList(): string[] { + return this._props.getPropValue("speciesList") as string[]; + } + + public set speciesList(l: string[]) { + this.properties.setPropValue("speciesList", l); + } + + public get pabJetType(): StructureJetTypeStrict { + return this._props.getPropValue("pabJetType"); + } + + public set pabJetType(j: StructureJetTypeStrict) { + this.properties.setPropValue("pabJetType", j); + } + + /** finds the Nub to verify by its UID */ + public get nubToVerify(): FishPass { + let nub: Nub; + const nubUID: string = this._props.getPropValue("nubToVerify"); + if (nubUID !== undefined && nubUID !== "") { + nub = Session.getInstance().findNubByUid(nubUID); + // silent fail if (nub === undefined) + } + return nub; + } + + /** defines the Nub to verify by setting property "nubToVerify" to the UID of the given Nub */ + public set nubToVerify(n: FishPass) { + let uid = ""; // empty value + if (n !== undefined) { + uid = n.uid; + } + this.properties.setPropValue("nubToVerify", uid); + } + + public CalcSerie(rInit?: number): Result { + // calc pass if needed + if (! this.nubToVerify.result) { + this.nubToVerify.CalcSerie(); + } + // check presence of valid result + if (! this.nubToVerify.result || ! this.nubToVerify.result.ok) { + this._result = new Result(undefined, this); + this._result.globalLog.add(new Message(MessageCode.ERROR_VERIF_ERRORS_IN_PASS)); + return this._result; + } + // @TODO manage variating passes - fake parameter linked to pass result ? See in GUI ? + return super.CalcSerie(); + } + + public Equation(sVarCalc: string): Result { + let v: number = 0; + const r = new Result(v, this); + + switch (sVarCalc) { + case "OK": + // console.log("Equation ! Nub UID =", this.nubToVerify.uid); + for (const s of this.speciesList) { + const nub = this.getEspeceFromString(s); + // give the pass pointer + nub.passToCheck = this.nubToVerify; + if (this.nubToVerify.calcType === CalculatorType.Pab) { + // give the jet type for Pab + nub.pabJetType = this.pabJetType; + } + // @TODO give the index to check if pass is variating + nub.indexToCheck = 0; + + const subRes = nub.Calc(); + // copy log @TODO aggregate in a smarter way ? + r.resultElement.log.addLog(subRes.resultElement.log); + + v = Math.min(v + subRes.vCalc, 1); // 0 if everything goes OK, 1 as soon as a species check fails + } + r.vCalc = v; + break; + + default: + throw new Error("Verificateur.Equation() : invalid variable name " + sVarCalc); + } + + return r; + } + + // interface Observer + public update(sender: any, data: any): void { + if (data.action === "propertyChange") { + if (data.name === "nubToVerify" || data.name === "speciesList") { + // @TODO sélecteur pour Pab : "surface" ou "plongeant" + } + } + } + + /** + * Retrieves an Espece from a given string, which should be either + * the UID of an Espece Session Nub, or the label of an element + * of FishSpecies enum + * @param s + */ + protected getEspeceFromString(s: string): Espece { + let e: Espece; + // is it a predefined species ? + if (Object.keys(FishSpecies).includes(s)) { + if (s === "SPECIES_CUSTOM") { + throw new Error("Verificateur.getEspeceFromString(): cannot automatically instantiate SPECIES_CUSTOM"); + } + // instanciate out of Session + e = new Espece(new EspeceParams(1, 1)); + e.species = (<any>FishSpecies)[s]; + } else { + // is it a session Nub ? + e = Session.getInstance().findNubByUid(s) as Espece; + if (e === undefined) { + throw new Error(`Verificateur.getEspeceFromString(): could not find Nub ${s} in the session`); + } + } + return e; + } + + protected setParametersCalculability(): void { + this.prms.OK.calculability = ParamCalculability.EQUATION; + } +} diff --git a/src/verification/verificateur_params.ts b/src/verification/verificateur_params.ts new file mode 100644 index 0000000000000000000000000000000000000000..e868c560cce88235676a39220991f5263d48565b --- /dev/null +++ b/src/verification/verificateur_params.ts @@ -0,0 +1,19 @@ +import { ParamsEquation } from "../param/params-equation"; +import { ParamDefinition } from "../param/param-definition"; +import { ParamDomainValue } from "../param/param-domain"; + +export class VerificateurParams extends ParamsEquation { + + /** Résultat de la vérification (seul paramètre calculable) */ + private _OK: ParamDefinition; + + constructor() { + super(); + this._OK = new ParamDefinition(this, "OK", ParamDomainValue.POS, ""); + this.addParamDefinition(this._OK); + } + + public get OK(): ParamDefinition { + return this._OK; + } +}